Merge branch 'master' into Playerbot

# Conflicts:
#	src/server/game/World/IWorld.h
#	src/server/game/World/World.cpp
#	src/server/game/World/World.h
#	src/server/scripts/Commands/cs_server.cpp
This commit is contained in:
郑佩茹
2022-05-02 16:39:21 -06:00
99 changed files with 839 additions and 5304 deletions
+1
View File
@@ -61,6 +61,7 @@ Versions of macOS:
| macOS Version | Supported | | macOS Version | Supported |
| ------------- | ------------------ | | ------------- | ------------------ |
| 12 | :white_check_mark: |
| 11 | :white_check_mark: | | 11 | :white_check_mark: |
| 10.15 | :white_check_mark: | | 10.15 | :white_check_mark: |
+1
View File
@@ -18,6 +18,7 @@ jobs:
os: os:
- macos-10.15 - macos-10.15
- macos-11 - macos-11
- macos-12
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
name: ${{ matrix.os }} name: ${{ matrix.os }}
if: github.repository == 'azerothcore/azerothcore-wotlk' && (github.ref == 'refs/heads/master' || contains(github.event.pull_request.labels.*.name, 'run-build') || github.event.label.name == 'run-build') if: github.repository == 'azerothcore/azerothcore-wotlk' && (github.ref == 'refs/heads/master' || contains(github.event.pull_request.labels.*.name, 'run-build') || github.event.label.name == 'run-build')
-42
View File
@@ -43,10 +43,6 @@ function import() {
newVer=$dateToday"_"$cnt newVer=$dateToday"_"$cnt
startTransaction="START TRANSACTION;";
updHeader="ALTER TABLE version_db_"$db" CHANGE COLUMN "$oldVer" "$newVer" bit;";
endTransaction="COMMIT;";
newFile="$updPath/"$dateToday"_"$cnt".sql" newFile="$updPath/"$dateToday"_"$cnt".sql"
oldFile=$(basename "$entry") oldFile=$(basename "$entry")
@@ -61,46 +57,8 @@ function import() {
echo "-- DB update $oldVer -> $newVer" > "$newFile"; echo "-- DB update $oldVer -> $newVer" > "$newFile";
if [[ $isRev -eq 1 ]]; then
echo "DROP PROCEDURE IF EXISTS \`updateDb\`;" >> "$newFile";
echo "DELIMITER //" >> "$newFile";
echo "CREATE PROCEDURE updateDb ()" >> "$newFile";
echo "proc:BEGIN DECLARE OK VARCHAR(100) DEFAULT 'FALSE';" >> "$newFile";
echo "SELECT COUNT(*) INTO @COLEXISTS" >> "$newFile";
echo "FROM information_schema.COLUMNS" >> "$newFile";
echo "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'version_db_"$db"' AND COLUMN_NAME = '"$oldVer"';" >> "$newFile";
echo "IF @COLEXISTS = 0 THEN LEAVE proc; END IF;" >> "$newFile";
fi
echo "$startTransaction" >> "$newFile";
echo "$updHeader" >> "$newFile";
if [[ $isRev -eq 1 ]]; then
echo "SELECT sql_rev INTO OK FROM version_db_"$db" WHERE sql_rev = '$rev'; IF OK <> 'FALSE' THEN LEAVE proc; END IF;" >> "$newFile";
fi;
echo "--" >> "$newFile";
echo "-- START UPDATING QUERIES" >> "$newFile";
echo "--" >> "$newFile";
echo "" >> "$newFile";
cat $entry >> "$newFile"; cat $entry >> "$newFile";
echo "" >> "$newFile";
echo "--" >> "$newFile";
echo "-- END UPDATING QUERIES" >> "$newFile";
echo "--" >> "$newFile";
echo "UPDATE version_db_"$db" SET date = '"$newVer"' WHERE sql_rev = '"$rev"';" >> "$newFile";
echo "$endTransaction" >> "$newFile";
if [[ $isRev -eq 1 ]]; then
echo "END //" >> "$newFile";
echo "DELIMITER ;" >> "$newFile";
echo "CALL updateDb();" >> "$newFile";
echo "DROP PROCEDURE IF EXISTS \`updateDb\`;" >> "$newFile";
fi;
currentHash="$(git log --diff-filter=A "$entry" | grep "^commit " | sed -e 's/commit //')" currentHash="$(git log --diff-filter=A "$entry" | grep "^commit " | sed -e 's/commit //')"
if [[ "$COMMIT_HASH" != *"$currentHash"* ]] if [[ "$COMMIT_HASH" != *"$currentHash"* ]]
-9
View File
@@ -22,15 +22,6 @@ for i in `find data/sql/updates/pending* -name "*.sql" -type f`; do
fi fi
done done
for i in `find data/sql/updates/pending* -name "*.sql" -type f`; do
if $(cat "$i"|sed "s/'.*'\(.*\)/\1/g"|grep -q -i -E "version_db_"); then
echo "> version_db check - OK"
else
echo "> version_db check - Failed"
exit 1
fi
done
for i in `find data/sql/updates/pending* -name "*sql" -type f`; do for i in `find data/sql/updates/pending* -name "*sql" -type f`; do
if $(cat "$i"|sed "s/'.*'\(.*\)/\1/g"|grep -q -i -E "broadcast_text"); then if $(cat "$i"|sed "s/'.*'\(.*\)/\1/g"|grep -q -i -E "broadcast_text"); then
echo "> broadcast_text check - Failed" echo "> broadcast_text check - Failed"
-1
View File
@@ -62,7 +62,6 @@ option(USE_COREPCH "Use precompiled headers when compiling servers"
option(WITH_WARNINGS "Show all warnings during compile" 0) option(WITH_WARNINGS "Show all warnings during compile" 0)
option(WITH_COREDEBUG "Include additional debug-code in core" 0) option(WITH_COREDEBUG "Include additional debug-code in core" 0)
option(WITH_PERFTOOLS "Enable compilation with gperftools libraries included" 0) option(WITH_PERFTOOLS "Enable compilation with gperftools libraries included" 0)
option(WITH_MESHEXTRACTOR "Build meshextractor (alpha)" 0)
option(WITHOUT_GIT "Disable the GIT testing routines" 0) option(WITHOUT_GIT "Disable the GIT testing routines" 0)
option(ENABLE_VMAP_CHECKS "Enable Checks relative to DisableMgr system on vmap" 1) option(ENABLE_VMAP_CHECKS "Enable Checks relative to DisableMgr system on vmap" 1)
option(WITH_DYNAMIC_LINKING "Enable dynamic library linking." 0) option(WITH_DYNAMIC_LINKING "Enable dynamic library linking." 0)
@@ -0,0 +1,4 @@
-- DB update 2022_04_24_00 -> 2022_04_28_00
--
DROP TABLE IF EXISTS `version_db_auth`;
@@ -0,0 +1,4 @@
-- DB update 2022_04_24_00 -> 2022_04_28_00
--
DROP TABLE IF EXISTS `version_db_characters`;
@@ -0,0 +1,4 @@
-- DB update 2022_04_25_03 -> 2022_04_28_00
--
DROP TABLE IF EXISTS `version_db_world`;
@@ -0,0 +1,6 @@
-- DB update 2022_04_28_00 -> 2022_05_01_00
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 14347;
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 14347) AND (`source_type` = 0) AND (`id` IN (2));
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(14347, 0, 2, 0, 20, 0, 100, 0, 7786, 0, 0, 0, 0, 12, 14435, 6, 3600000, 0, 0, 0, 8, 0, 0, 0, 0, -6241.77, 1717.14, 4.25042, 0.680879, 'Highlord Demitrian - On Quest Thunderaan the Windseeker Finished - Summon Creature Prince Thunderaan at XYZO');
@@ -0,0 +1,3 @@
-- DB update 2022_05_01_00 -> 2022_05_01_01
--
UPDATE `creature_template` SET `flags_extra`=`flags_extra`|0x20000000 WHERE `entry`=8236;
@@ -12,4 +12,4 @@ CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )";
rev=$( $date +%s%N ); rev=$( $date +%s%N );
filename=rev_"$rev".sql filename=rev_"$rev".sql
echo "INSERT INTO \`version_db_auth\` (\`sql_rev\`) VALUES ('"$rev"');" > "$CUR_PATH/$filename" && echo "File created: $filename"; echo "--" > "$CUR_PATH/$filename" && echo "File created: $filename";
@@ -12,4 +12,4 @@ CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )";
rev=$( $date +%s%N ); rev=$( $date +%s%N );
filename=rev_"$rev".sql filename=rev_"$rev".sql
echo "INSERT INTO \`version_db_characters\` (\`sql_rev\`) VALUES ('"$rev"');" > "$CUR_PATH/$filename" && echo "File created: $filename"; echo "--" > "$CUR_PATH/$filename" && echo "File created: $filename";
@@ -12,4 +12,4 @@ CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )";
rev=$( $date +%s%N ); rev=$( $date +%s%N );
filename=rev_"$rev".sql filename=rev_"$rev".sql
echo "INSERT INTO \`version_db_world\` (\`sql_rev\`) VALUES ('"$rev"');" > "$CUR_PATH/$filename" && echo "File created: $filename"; echo "--" > "$CUR_PATH/$filename" && echo "File created: $filename";
+36 -28
View File
@@ -1,4 +1,4 @@
// Copyright 2006 Nemanja Trifunovic // Copyright 2006-2016 Nemanja Trifunovic
/* /*
Permission is hereby granted, free of charge, to any person or organization Permission is hereby granted, free of charge, to any person or organization
@@ -41,8 +41,8 @@ namespace utf8
class invalid_code_point : public exception { class invalid_code_point : public exception {
uint32_t cp; uint32_t cp;
public: public:
invalid_code_point(uint32_t cp) : cp(cp) {} invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
virtual const char* what() const throw() { return "Invalid code point"; } virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; }
uint32_t code_point() const {return cp;} uint32_t code_point() const {return cp;}
}; };
@@ -50,7 +50,7 @@ namespace utf8
uint8_t u8; uint8_t u8;
public: public:
invalid_utf8 (uint8_t u) : u8(u) {} invalid_utf8 (uint8_t u) : u8(u) {}
virtual const char* what() const throw() { return "Invalid UTF-8"; } virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-8"; }
uint8_t utf8_octet() const {return u8;} uint8_t utf8_octet() const {return u8;}
}; };
@@ -58,13 +58,13 @@ namespace utf8
uint16_t u16; uint16_t u16;
public: public:
invalid_utf16 (uint16_t u) : u16(u) {} invalid_utf16 (uint16_t u) : u16(u) {}
virtual const char* what() const throw() { return "Invalid UTF-16"; } virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-16"; }
uint16_t utf16_word() const {return u16;} uint16_t utf16_word() const {return u16;}
}; };
class not_enough_room : public exception { class not_enough_room : public exception {
public: public:
virtual const char* what() const throw() { return "Not enough space"; } virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Not enough space"; }
}; };
/// The library API - functions intended to be called by the users /// The library API - functions intended to be called by the users
@@ -107,7 +107,9 @@ namespace utf8
*out++ = *it; *out++ = *it;
break; break;
case internal::NOT_ENOUGH_ROOM: case internal::NOT_ENOUGH_ROOM:
throw not_enough_room(); out = utf8::append (replacement, out);
start = end;
break;
case internal::INVALID_LEAD: case internal::INVALID_LEAD:
out = utf8::append (replacement, out); out = utf8::append (replacement, out);
++start; ++start;
@@ -174,23 +176,19 @@ namespace utf8
return utf8::peek_next(it, end); return utf8::peek_next(it, end);
} }
/// Deprecated in versions that include "prior"
template <typename octet_iterator>
uint32_t previous(octet_iterator& it, octet_iterator pass_start)
{
octet_iterator end = it;
while (utf8::internal::is_trail(*(--it)))
if (it == pass_start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
octet_iterator temp = it;
return utf8::next(temp, end);
}
template <typename octet_iterator, typename distance_type> template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n, octet_iterator end) void advance (octet_iterator& it, distance_type n, octet_iterator end)
{ {
for (distance_type i = 0; i < n; ++i) const distance_type zero(0);
utf8::next(it, end); if (n < zero) {
// backward
for (distance_type i = n; i < zero; ++i)
utf8::prior(it, end);
} else {
// forward
for (distance_type i = zero; i < n; ++i)
utf8::next(it, end);
}
} }
template <typename octet_iterator> template <typename octet_iterator>
@@ -233,7 +231,7 @@ namespace utf8
template <typename u16bit_iterator, typename octet_iterator> template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{ {
while (start != end) { while (start < end) {
uint32_t cp = utf8::next(start, end); uint32_t cp = utf8::next(start, end);
if (cp > 0xffff) { //make a surrogate pair if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET); *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
@@ -257,7 +255,7 @@ namespace utf8
template <typename octet_iterator, typename u32bit_iterator> template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{ {
while (start != end) while (start < end)
(*result++) = utf8::next(start, end); (*result++) = utf8::next(start, end);
return result; return result;
@@ -265,16 +263,21 @@ namespace utf8
// The iterator class // The iterator class
template <typename octet_iterator> template <typename octet_iterator>
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { class iterator {
octet_iterator it; octet_iterator it;
octet_iterator range_start; octet_iterator range_start;
octet_iterator range_end; octet_iterator range_end;
public: public:
typedef uint32_t value_type;
typedef uint32_t* pointer;
typedef uint32_t& reference;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
iterator () {} iterator () {}
explicit iterator (const octet_iterator& octet_it, explicit iterator (const octet_iterator& octet_it,
const octet_iterator& range_start, const octet_iterator& rangestart,
const octet_iterator& range_end) : const octet_iterator& rangeend) :
it(octet_it), range_start(range_start), range_end(range_end) it(octet_it), range_start(rangestart), range_end(rangeend)
{ {
if (it < range_start || it > range_end) if (it < range_start || it > range_end)
throw std::out_of_range("Invalid utf-8 iterator position"); throw std::out_of_range("Invalid utf-8 iterator position");
@@ -322,6 +325,11 @@ namespace utf8
} // namespace utf8 } // namespace utf8
#if UTF_CPP_CPLUSPLUS >= 201703L // C++ 17 or later
#include "cpp17.h"
#elif UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
#include "cpp11.h"
#endif // C++ 11 or later
#endif //header guard #endif //header guard
+26 -17
View File
@@ -30,6 +30,23 @@ DEALINGS IN THE SOFTWARE.
#include <iterator> #include <iterator>
// Determine the C++ standard version.
// If the user defines UTF_CPP_CPLUSPLUS, use that.
// Otherwise, trust the unreliable predefined macro __cplusplus
#if !defined UTF_CPP_CPLUSPLUS
#define UTF_CPP_CPLUSPLUS __cplusplus
#endif
#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
#define UTF_CPP_OVERRIDE override
#define UTF_CPP_NOEXCEPT noexcept
#else // C++ 98/03
#define UTF_CPP_OVERRIDE
#define UTF_CPP_NOEXCEPT throw()
#endif // C++ 11 or later
namespace utf8 namespace utf8
{ {
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
@@ -49,8 +66,8 @@ namespace internal
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); const uint16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10)
const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; const uint32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN
// Maximum valid value for a Unicode code point // Maximum valid value for a Unicode code point
const uint32_t CODE_POINT_MAX = 0x0010ffffu; const uint32_t CODE_POINT_MAX = 0x0010ffffu;
@@ -142,7 +159,7 @@ namespace internal
if (!utf8::internal::is_trail(*it)) if (!utf8::internal::is_trail(*it))
return INCOMPLETE_SEQUENCE; return INCOMPLETE_SEQUENCE;
return UTF8_OK; return UTF8_OK;
} }
@@ -165,7 +182,7 @@ namespace internal
{ {
if (it == end) if (it == end)
return NOT_ENOUGH_ROOM; return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it); code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
@@ -222,6 +239,9 @@ namespace internal
template <typename octet_iterator> template <typename octet_iterator>
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{ {
if (it == end)
return NOT_ENOUGH_ROOM;
// Save the original value of it so we can go back in case of failure // Save the original value of it so we can go back in case of failure
// Of course, it does not make much sense with i.e. stream iterators // Of course, it does not make much sense with i.e. stream iterators
octet_iterator original_it = it; octet_iterator original_it = it;
@@ -234,7 +254,7 @@ namespace internal
// Get trail octets and calculate the code point // Get trail octets and calculate the code point
utf_error err = UTF8_OK; utf_error err = UTF8_OK;
switch (length) { switch (length) {
case 0: case 0:
return INVALID_LEAD; return INVALID_LEAD;
case 1: case 1:
err = utf8::internal::get_sequence_1(it, end, cp); err = utf8::internal::get_sequence_1(it, end, cp);
@@ -310,18 +330,7 @@ namespace internal
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
((it != end) && (utf8::internal::mask8(*it)) == bom[2]) ((it != end) && (utf8::internal::mask8(*it)) == bom[2])
); );
} }
//Deprecated in release 2.3
template <typename octet_iterator>
inline bool is_bom (octet_iterator it)
{
return (
(utf8::internal::mask8(*it++)) == bom[0] &&
(utf8::internal::mask8(*it++)) == bom[1] &&
(utf8::internal::mask8(*it)) == bom[2]
);
}
} // namespace utf8 } // namespace utf8
#endif // header guard #endif // header guard
+103
View File
@@ -0,0 +1,103 @@
// Copyright 2018 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1
#define UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1
#include "checked.h"
#include <string>
namespace utf8
{
inline void append(char32_t cp, std::string& s)
{
append(uint32_t(cp), std::back_inserter(s));
}
inline std::string utf16to8(const std::u16string& s)
{
std::string result;
utf16to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u16string utf8to16(const std::string& s)
{
std::u16string result;
utf8to16(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::string utf32to8(const std::u32string& s)
{
std::string result;
utf32to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u32string utf8to32(const std::string& s)
{
std::u32string result;
utf8to32(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::size_t find_invalid(const std::string& s)
{
std::string::const_iterator invalid = find_invalid(s.begin(), s.end());
return (invalid == s.end()) ? std::string::npos : (invalid - s.begin());
}
inline bool is_valid(const std::string& s)
{
return is_valid(s.begin(), s.end());
}
inline std::string replace_invalid(const std::string& s, char32_t replacement)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
return result;
}
inline std::string replace_invalid(const std::string& s)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline bool starts_with_bom(const std::string& s)
{
return starts_with_bom(s.begin(), s.end());
}
} // namespace utf8
#endif // header guard
+103
View File
@@ -0,0 +1,103 @@
// Copyright 2018 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
#define UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9
#include "checked.h"
#include <string>
namespace utf8
{
inline void append(char32_t cp, std::string& s)
{
append(uint32_t(cp), std::back_inserter(s));
}
inline std::string utf16to8(std::u16string_view s)
{
std::string result;
utf16to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u16string utf8to16(std::string_view s)
{
std::u16string result;
utf8to16(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::string utf32to8(std::u32string_view s)
{
std::string result;
utf32to8(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::u32string utf8to32(std::string_view s)
{
std::u32string result;
utf8to32(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline std::size_t find_invalid(std::string_view s)
{
std::string_view::const_iterator invalid = find_invalid(s.begin(), s.end());
return (invalid == s.end()) ? std::string_view::npos : (invalid - s.begin());
}
inline bool is_valid(std::string_view s)
{
return is_valid(s.begin(), s.end());
}
inline std::string replace_invalid(std::string_view s, char32_t replacement)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
return result;
}
inline std::string replace_invalid(std::string_view s)
{
std::string result;
replace_invalid(s.begin(), s.end(), std::back_inserter(result));
return result;
}
inline bool starts_with_bom(std::string_view s)
{
return starts_with_bom(s.begin(), s.end());
}
} // namespace utf8
#endif // header guard
+62 -16
View File
@@ -32,13 +32,13 @@ DEALINGS IN THE SOFTWARE.
namespace utf8 namespace utf8
{ {
namespace unchecked namespace unchecked
{ {
template <typename octet_iterator> template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result) octet_iterator append(uint32_t cp, octet_iterator result)
{ {
if (cp < 0x80) // one octet if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp); *(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0); *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80); *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
@@ -57,6 +57,46 @@ namespace utf8
return result; return result;
} }
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
{
while (start != end) {
octet_iterator sequence_start = start;
internal::utf_error err_code = utf8::internal::validate_next(start, end);
switch (err_code) {
case internal::UTF8_OK :
for (octet_iterator it = sequence_start; it != start; ++it)
*out++ = *it;
break;
case internal::NOT_ENOUGH_ROOM:
out = utf8::unchecked::append (replacement, out);
start = end;
break;
case internal::INVALID_LEAD:
out = utf8::unchecked::append (replacement, out);
++start;
break;
case internal::INCOMPLETE_SEQUENCE:
case internal::OVERLONG_SEQUENCE:
case internal::INVALID_CODE_POINT:
out = utf8::unchecked::append (replacement, out);
++start;
// just one replacement mark for the sequence
while (start != end && utf8::internal::is_trail(*start))
++start;
break;
}
}
return out;
}
template <typename octet_iterator, typename output_iterator>
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
return utf8::unchecked::replace_invalid(start, end, out, replacement_marker);
}
template <typename octet_iterator> template <typename octet_iterator>
uint32_t next(octet_iterator& it) uint32_t next(octet_iterator& it)
{ {
@@ -85,13 +125,13 @@ namespace utf8
break; break;
} }
++it; ++it;
return cp; return cp;
} }
template <typename octet_iterator> template <typename octet_iterator>
uint32_t peek_next(octet_iterator it) uint32_t peek_next(octet_iterator it)
{ {
return utf8::unchecked::next(it); return utf8::unchecked::next(it);
} }
template <typename octet_iterator> template <typename octet_iterator>
@@ -102,18 +142,19 @@ namespace utf8
return utf8::unchecked::next(temp); return utf8::unchecked::next(temp);
} }
// Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
template <typename octet_iterator>
inline uint32_t previous(octet_iterator& it)
{
return utf8::unchecked::prior(it);
}
template <typename octet_iterator, typename distance_type> template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n) void advance (octet_iterator& it, distance_type n)
{ {
for (distance_type i = 0; i < n; ++i) const distance_type zero(0);
utf8::unchecked::next(it); if (n < zero) {
// backward
for (distance_type i = n; i < zero; ++i)
utf8::unchecked::prior(it);
} else {
// forward
for (distance_type i = zero; i < n; ++i)
utf8::unchecked::next(it);
}
} }
template <typename octet_iterator> template <typename octet_iterator>
@@ -128,7 +169,7 @@ namespace utf8
template <typename u16bit_iterator, typename octet_iterator> template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{ {
while (start != end) { while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++); uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first // Take care of surrogate pairs first
@@ -138,7 +179,7 @@ namespace utf8
} }
result = utf8::unchecked::append(cp, result); result = utf8::unchecked::append(cp, result);
} }
return result; return result;
} }
template <typename u16bit_iterator, typename octet_iterator> template <typename u16bit_iterator, typename octet_iterator>
@@ -176,9 +217,14 @@ namespace utf8
// The iterator class // The iterator class
template <typename octet_iterator> template <typename octet_iterator>
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { class iterator {
octet_iterator it; octet_iterator it;
public: public:
typedef uint32_t value_type;
typedef uint32_t* pointer;
typedef uint32_t& reference;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
iterator () {} iterator () {}
explicit iterator (const octet_iterator& octet_it): it(octet_it) {} explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
// the default "big three" are OK // the default "big three" are OK
+46
View File
@@ -66,6 +66,52 @@ if(WITH_COREDEBUG)
message(STATUS "Clang: Debug-flags set (-g3)") message(STATUS "Clang: Debug-flags set (-g3)")
endif() endif()
if(MSAN)
target_compile_options(acore-compile-option-interface
INTERFACE
-fno-omit-frame-pointer
-fsanitize=memory
-fsanitize-memory-track-origins
-mllvm
-msan-keep-going=1)
target_link_options(acore-compile-option-interface
INTERFACE
-fno-omit-frame-pointer
-fsanitize=memory
-fsanitize-memory-track-origins)
message(STATUS "Clang: Enabled Memory Sanitizer MSan")
endif()
if(UBSAN)
target_compile_options(acore-compile-option-interface
INTERFACE
-fno-omit-frame-pointer
-fsanitize=undefined)
target_link_options(acore-compile-option-interface
INTERFACE
-fno-omit-frame-pointer
-fsanitize=undefined)
message(STATUS "Clang: Enabled Undefined Behavior Sanitizer UBSan")
endif()
if(TSAN)
target_compile_options(acore-compile-option-interface
INTERFACE
-fno-omit-frame-pointer
-fsanitize=thread)
target_link_options(acore-compile-option-interface
INTERFACE
-fno-omit-frame-pointer
-fsanitize=thread)
message(STATUS "Clang: Enabled Thread Sanitizer TSan")
endif()
# -Wno-narrowing needed to suppress a warning in g3d # -Wno-narrowing needed to suppress a warning in g3d
# -Wno-deprecated-register is needed to suppress gsoap warnings on Unix systems. # -Wno-deprecated-register is needed to suppress gsoap warnings on Unix systems.
target_compile_options(acore-compile-option-interface target_compile_options(acore-compile-option-interface
+1 -1
View File
@@ -24,7 +24,7 @@ ExternalProject_Add(
GIT_REPOSITORY GIT_REPOSITORY
https://github.com/google/googletest.git https://github.com/google/googletest.git
GIT_TAG GIT_TAG
release-1.10.0 main
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""
INSTALL_COMMAND "" INSTALL_COMMAND ""
+21
View File
@@ -168,6 +168,27 @@ elseif (WITH_DETAILED_METRICS)
add_definitions(-DWITH_DETAILED_METRICS) add_definitions(-DWITH_DETAILED_METRICS)
endif() endif()
if(MSAN)
message("")
message(" *** MSAN - WARNING!")
message(" *** Please note that this is for DEBUGGING WITH MEMORY SANITIZER only!")
add_definitions(-DMSAN)
endif()
if(UBSAN)
message("")
message(" *** UBSAN - WARNING!")
message(" *** Please note that this is for DEBUGGING WITH UNDEFINED BEHAVIOR SANITIZER only!")
add_definitions(-DUBSAN)
endif()
if(TSAN)
message("")
message(" *** TSAN - WARNING!")
message(" *** Please note that this is for DEBUGGING WITH THREAD SANITIZER only!")
add_definitions(-DTSAN -DNO_BUFFERPOOL)
endif()
if(BUILD_SHARED_LIBS) if(BUILD_SHARED_LIBS)
message("") message("")
message(" *** WITH_DYNAMIC_LINKING - INFO!") message(" *** WITH_DYNAMIC_LINKING - INFO!")
+2 -1
View File
@@ -23,6 +23,7 @@
#include <iomanip> #include <iomanip>
#include <set> #include <set>
#include <sstream> #include <sstream>
#include <boost/filesystem.hpp>
using G3D::Vector3; using G3D::Vector3;
using G3D::AABox; using G3D::AABox;
@@ -54,7 +55,7 @@ namespace VMAP
TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName) TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName)
: iDestDir(pDestDirName), iSrcDir(pSrcDirName) : iDestDir(pDestDirName), iSrcDir(pSrcDirName)
{ {
//mkdir(iDestDir); boost::filesystem::create_directory(iDestDir);
//init(); //init();
} }
@@ -334,11 +334,12 @@ void Minion::InitStats(uint32 duration)
SetReactState(REACT_PASSIVE); SetReactState(REACT_PASSIVE);
Unit* owner = GetOwner(); if (Unit* owner = GetOwner())
SetCreatorGUID(owner->GetGUID()); {
SetFaction(owner->GetFaction()); SetCreatorGUID(owner->GetGUID());
SetFaction(owner->GetFaction());
owner->SetMinion(this, true); owner->SetMinion(this, true);
}
} }
void Minion::RemoveFromWorld() void Minion::RemoveFromWorld()
@@ -11035,6 +11035,11 @@ void Player::LeaveBattleground(Battleground* bg)
// xinef: reset corpse reclaim time // xinef: reset corpse reclaim time
m_deathExpireTime = GameTime::GetGameTime().count(); m_deathExpireTime = GameTime::GetGameTime().count();
// Remove all dots
RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
// pussywizard: clear movement, because after porting player will move to arena cords // pussywizard: clear movement, because after porting player will move to arena cords
GetMotionMaster()->MovementExpired(); GetMotionMaster()->MovementExpired();
StopMoving(); StopMoving();
+1 -1
View File
@@ -1952,7 +1952,7 @@ inline LiquidData const GridMap::GetLiquidData(float x, float y, float z, float
float ground_level = getHeight(x, y); float ground_level = getHeight(x, y);
// Check water level and ground level // Check water level and ground level
if (liquid_level >= ground_level && z >= ground_level - 2) if (liquid_level >= ground_level && z >= ground_level)
{ {
// All ok in water -> store data // All ok in water -> store data
liquidData.Entry = entry; liquidData.Entry = entry;
+13
View File
@@ -608,6 +608,19 @@ void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id,
} }
} }
void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_CHARGE*/)
{
G3D::Vector3 dest = path.GetActualEndPosition();
MoveCharge(dest.x, dest.y, dest.z, speed, EVENT_CHARGE_PREPATH);
// Charge movement is not started when using EVENT_CHARGE_PREPATH
Movement::MoveSplineInit init(_owner);
init.MovebyPath(path.GetPath());
init.SetVelocity(speed);
init.Launch();
}
void MotionMaster::MoveSeekAssistance(float x, float y, float z) void MotionMaster::MoveSeekAssistance(float x, float y, float z)
{ {
// Xinef: do not allow to move with UNIT_FLAG_DISABLE_MOVE // Xinef: do not allow to move with UNIT_FLAG_DISABLE_MOVE
+1
View File
@@ -219,6 +219,7 @@ public:
void MoveTakeoff(uint32 id, float x, float y, float z, float speed = 0.0f); // pussywizard: added for easy calling by passing 3 floats x, y, z void MoveTakeoff(uint32 id, float x, float y, float z, float speed = 0.0f); // pussywizard: added for easy calling by passing 3 floats x, y, z
void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, const Movement::PointsArray* path = nullptr, bool generatePath = false, float orientation = 0.0f, ObjectGuid targetGUID = ObjectGuid::Empty); void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, const Movement::PointsArray* path = nullptr, bool generatePath = false, float orientation = 0.0f, ObjectGuid targetGUID = ObjectGuid::Empty);
void MoveCharge(PathGenerator const& path, float speed = SPEED_CHARGE);
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ); void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ);
void MoveJumpTo(float angle, float speedXY, float speedZ); void MoveJumpTo(float angle, float speedXY, float speedZ);
void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = 0) void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = 0)
@@ -117,7 +117,7 @@ bool PointMovementGenerator<T>::DoUpdate(T* unit, uint32 /*diff*/)
unit->AddUnitState(UNIT_STATE_ROAMING_MOVE); unit->AddUnitState(UNIT_STATE_ROAMING_MOVE);
if (i_recalculateSpeed && !unit->movespline->Finalized()) if (id != EVENT_CHARGE_PREPATH && i_recalculateSpeed && !unit->movespline->Finalized())
{ {
i_recalculateSpeed = false; i_recalculateSpeed = false;
Movement::MoveSplineInit init(unit); Movement::MoveSplineInit init(unit);
@@ -446,11 +446,10 @@ bool FollowMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
else else
i_path->Clear(); i_path->Clear();
float distance = _range - target->GetCombatReach(); target->MovePositionToFirstCollision(targetPosition, owner->GetCombatReach() + _range, target->ToAbsoluteAngle(_angle.RelativeAngle) - target->GetOrientation());
float relAngle = _angle.RelativeAngle;
float x, y, z; float x, y, z;
target->GetNearPoint(owner, x, y, z, owner->GetCombatReach(), distance, target->ToAbsoluteAngle(relAngle), 0.f, &targetPosition); targetPosition.GetPosition(x, y, z);
if (owner->IsHovering()) if (owner->IsHovering())
owner->UpdateAllowedPositionZ(x, y, z); owner->UpdateAllowedPositionZ(x, y, z);
+17 -31
View File
@@ -646,7 +646,6 @@ Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags,
m_glyphIndex = 0; m_glyphIndex = 0;
m_preCastSpell = 0; m_preCastSpell = 0;
m_spellAura = nullptr; m_spellAura = nullptr;
m_pathFinder = nullptr; // pussywizard
_scriptsLoaded = false; _scriptsLoaded = false;
//Auto Shot & Shoot (wand) //Auto Shot & Shoot (wand)
@@ -701,7 +700,6 @@ Spell::~Spell()
} }
delete m_spellValue; delete m_spellValue;
delete m_pathFinder; // pussywizard
CheckEffectExecuteData(); CheckEffectExecuteData();
} }
@@ -6001,40 +5999,28 @@ SpellCastResult Spell::CheckCast(bool strict)
{ {
Unit* target = m_targets.GetUnitTarget(); Unit* target = m_targets.GetUnitTarget();
if (!target) if (!target)
return SPELL_FAILED_BAD_TARGETS; return SPELL_FAILED_DONT_REPORT;
Position pos; // first we must check to see if the target is in LoS. A path can usually be built but LoS matters for charge spells
target->GetChargeContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ); if (!target->IsWithinLOSInMap(m_caster)) //Do full LoS/Path check. Don't exclude m2
return SPELL_FAILED_LINE_OF_SIGHT;
if (m_caster->GetMapId() == 618) // pussywizard: 618 Ring of Valor float objSize = target->GetCombatReach();
pos.m_positionZ = std::max(pos.m_positionZ, 28.28f); float range = m_spellInfo->GetMaxRange(true, m_caster, this) * 1.5f + objSize; // can't be overly strict
float maxdist = m_caster->GetMeleeRange(target); m_preGeneratedPath = std::make_unique<PathGenerator>(m_caster);
if (!target->IsInDist(&pos, maxdist)) m_preGeneratedPath->SetPathLengthLimit(range);
// first try with raycast, if it fails fall back to normal path
bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false);
if (m_preGeneratedPath->GetPathType() & PATHFIND_SHORT)
return SPELL_FAILED_NOPATH;
else if (!result || m_preGeneratedPath->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE))
return SPELL_FAILED_NOPATH;
else if (m_preGeneratedPath->IsInvalidDestinationZ(target)) // Check position z, if not in a straight line
return SPELL_FAILED_NOPATH; return SPELL_FAILED_NOPATH;
if (m_caster->GetMapId() == 618) // pussywizard: 618 Ring of Valor m_preGeneratedPath->ShortenPathUntilDist(G3D::Vector3(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()), objSize); // move back
{
if (!((target->GetPositionZ() > 32.0f) ^ (m_caster->GetPositionZ() > 32.0f)))
break;
return SPELL_FAILED_NOPATH;
}
else if (m_caster->GetMapId() == 572) // pussywizard: 572 Ruins of Lordaeron
{
if (pos.GetPositionX() < 1275.0f || m_caster->GetPositionX() < 1275.0f) // special case (acid)
break; // can't force path because the way is around and the path is too long
}
if (m_caster->GetTransport() != target->GetTransport())
return SPELL_FAILED_NOPATH;
if (m_caster->GetTransport())
break;
m_pathFinder = new PathGenerator(m_caster);
m_pathFinder->CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ + 0.15f, false);
G3D::Vector3 endPos = m_pathFinder->GetEndPosition(); // also check distance between target and the point calculated by mmaps
if (m_pathFinder->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE) || target->GetExactDistSq(endPos.x, endPos.y, endPos.z) > maxdist * maxdist || m_pathFinder->getPathLength() > (40.0f + (m_caster->HasAura(58097) ? 5.0f : 0.0f)))
return SPELL_FAILED_NOPATH;
} }
if (Player* player = m_caster->ToPlayer()) if (Player* player = m_caster->ToPlayer())
player->SetCanTeleport(true); player->SetCanTeleport(true);
+1 -2
View File
@@ -544,8 +544,6 @@ public:
UsedSpellMods m_appliedMods; UsedSpellMods m_appliedMods;
PathGenerator* m_pathFinder; // pussywizard: for precomputing path for charge
int32 GetCastTime() const { return m_casttime; } int32 GetCastTime() const { return m_casttime; }
bool IsAutoRepeat() const { return m_autoRepeat; } bool IsAutoRepeat() const { return m_autoRepeat; }
void SetAutoRepeat(bool rep) { m_autoRepeat = rep; } void SetAutoRepeat(bool rep) { m_autoRepeat = rep; }
@@ -770,6 +768,7 @@ public:
bool m_skipCheck; bool m_skipCheck;
uint8 m_auraScaleMask; uint8 m_auraScaleMask;
std::unique_ptr<PathGenerator> m_preGeneratedPath;
// xinef: // xinef:
bool _spellTargetsSelected; bool _spellTargetsSelected;
+8 -7
View File
@@ -2728,6 +2728,8 @@ void Spell::EffectAddFarsight(SpellEffIndex effIndex)
dynObj->SetDuration(duration); dynObj->SetDuration(duration);
dynObj->SetCasterViewpoint(); dynObj->SetCasterViewpoint();
m_caster->ToPlayer()->UpdateVisibilityForPlayer();
} }
void Spell::EffectUntrainTalents(SpellEffIndex /*effIndex*/) void Spell::EffectUntrainTalents(SpellEffIndex /*effIndex*/)
@@ -4868,10 +4870,12 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
targetGUID = unitTarget->GetGUID(); targetGUID = unitTarget->GetGUID();
} }
if (m_pathFinder) float speed = G3D::fuzzyGt(m_spellInfo->Speed, 0.0f) ? m_spellInfo->Speed : SPEED_CHARGE;
// Spell is not using explicit target - no generated path
if (!m_preGeneratedPath)
{ {
m_caster->GetMotionMaster()->MoveCharge(m_pathFinder->GetEndPosition().x, m_pathFinder->GetEndPosition().y, m_pathFinder->GetEndPosition().z, Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetCombatReach(), unitTarget->GetRelativeAngle(m_caster));
42.0f, EVENT_CHARGE, &m_pathFinder->GetPath(), false, 0.f, targetGUID); m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speed);
if (m_caster->GetTypeId() == TYPEID_PLAYER) if (m_caster->GetTypeId() == TYPEID_PLAYER)
{ {
@@ -4880,10 +4884,7 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
} }
else else
{ {
Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster)); m_caster->GetMotionMaster()->MoveCharge(*m_preGeneratedPath, speed);
m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ + Z_OFFSET_FIND_HEIGHT, SPEED_CHARGE, EVENT_CHARGE,
nullptr, false, 0.f, targetGUID);
if (m_caster->GetTypeId() == TYPEID_PLAYER) if (m_caster->GetTypeId() == TYPEID_PLAYER)
{ {
-4
View File
@@ -583,11 +583,7 @@ public:
virtual void UpdateRealmCharCount(uint32 accid) = 0; virtual void UpdateRealmCharCount(uint32 accid) = 0;
[[nodiscard]] virtual LocaleConstant GetAvailableDbcLocale(LocaleConstant locale) const = 0; [[nodiscard]] virtual LocaleConstant GetAvailableDbcLocale(LocaleConstant locale) const = 0;
virtual void LoadDBVersion() = 0; virtual void LoadDBVersion() = 0;
virtual void LoadDBRevision() = 0;
[[nodiscard]] virtual char const* GetDBVersion() const = 0; [[nodiscard]] virtual char const* GetDBVersion() const = 0;
[[nodiscard]] virtual char const* GetWorldDBRevision() const = 0;
[[nodiscard]] virtual char const* GetCharacterDBRevision() const = 0;
[[nodiscard]] virtual char const* GetAuthDBRevision() const = 0;
#ifdef MOD_PLAYERBOTS #ifdef MOD_PLAYERBOTS
[[nodiscard]] virtual char const* GetPlayerbotsDBRevision() const = 0; [[nodiscard]] virtual char const* GetPlayerbotsDBRevision() const = 0;
#endif #endif
-43
View File
@@ -3274,49 +3274,6 @@ void World::LoadDBVersion()
m_DBVersion = "Unknown world database."; m_DBVersion = "Unknown world database.";
} }
void World::LoadDBRevision()
{
QueryResult resultWorld = WorldDatabase.Query("SELECT date FROM version_db_world ORDER BY date DESC LIMIT 1");
QueryResult resultCharacter = CharacterDatabase.Query("SELECT date FROM version_db_characters ORDER BY date DESC LIMIT 1");
QueryResult resultAuth = LoginDatabase.Query("SELECT date FROM version_db_auth ORDER BY date DESC LIMIT 1");
if (resultWorld)
{
Field* fields = resultWorld->Fetch();
m_WorldDBRevision = fields[0].Get<std::string>();
}
if (resultCharacter)
{
Field* fields = resultCharacter->Fetch();
m_CharacterDBRevision = fields[0].Get<std::string>();
}
if (resultAuth)
{
Field* fields = resultAuth->Fetch();
m_AuthDBRevision = fields[0].Get<std::string>();
}
if (m_WorldDBRevision.empty())
{
m_WorldDBRevision = "Unkown World Database Revision";
}
if (m_CharacterDBRevision.empty())
{
m_CharacterDBRevision = "Unkown Character Database Revision";
}
if (m_AuthDBRevision.empty())
{
m_AuthDBRevision = "Unkown Auth Database Revision";
}
#ifdef MOD_PLAYERBOTS
sScriptMgr->OnDatabaseGetDBRevision(m_PlayerbotsDBRevision);
#endif
}
void World::UpdateAreaDependentAuras() void World::UpdateAreaDependentAuras()
{ {
SessionMap::const_iterator itr; SessionMap::const_iterator itr;
-7
View File
@@ -339,11 +339,7 @@ public:
// used World DB version // used World DB version
void LoadDBVersion() override; void LoadDBVersion() override;
void LoadDBRevision() override;
[[nodiscard]] char const* GetDBVersion() const override { return m_DBVersion.c_str(); } [[nodiscard]] char const* GetDBVersion() const override { return m_DBVersion.c_str(); }
[[nodiscard]] char const* GetWorldDBRevision() const override { return m_WorldDBRevision.c_str(); }
[[nodiscard]] char const* GetCharacterDBRevision() const override { return m_CharacterDBRevision.c_str(); }
[[nodiscard]] char const* GetAuthDBRevision() const override { return m_AuthDBRevision.c_str(); }
#ifdef MOD_PLAYERBOTS #ifdef MOD_PLAYERBOTS
[[nodiscard]] char const* GetPlayerbotsDBRevision() const { return m_PlayerbotsDBRevision.c_str(); } [[nodiscard]] char const* GetPlayerbotsDBRevision() const { return m_PlayerbotsDBRevision.c_str(); }
#endif #endif
@@ -445,9 +441,6 @@ private:
// used versions // used versions
std::string m_DBVersion; std::string m_DBVersion;
std::string m_WorldDBRevision;
std::string m_CharacterDBRevision;
std::string m_AuthDBRevision;
#ifdef MOD_PLAYERBOTS #ifdef MOD_PLAYERBOTS
std::string m_PlayerbotsDBRevision; std::string m_PlayerbotsDBRevision;
#endif #endif
@@ -213,9 +213,6 @@ public:
handler->PSendSysMessage("Using %s DBC Locale as default. All available DBC locales: %s", localeNames[defaultLocale], availableLocales.c_str()); handler->PSendSysMessage("Using %s DBC Locale as default. All available DBC locales: %s", localeNames[defaultLocale], availableLocales.c_str());
handler->PSendSysMessage("Using World DB: %s", sWorld->GetDBVersion()); handler->PSendSysMessage("Using World DB: %s", sWorld->GetDBVersion());
handler->PSendSysMessage("Using World DB Revision: %s", sWorld->GetWorldDBRevision());
handler->PSendSysMessage("Using Character DB Revision: %s", sWorld->GetCharacterDBRevision());
handler->PSendSysMessage("Using Auth DB Revision: %s", sWorld->GetAuthDBRevision());
#ifdef MOD_PLAYERBOTS #ifdef MOD_PLAYERBOTS
handler->PSendSysMessage("Using Playerbots DB Revision: %s", sWorld->GetPlayerbotsDBRevision()); handler->PSendSysMessage("Using Playerbots DB Revision: %s", sWorld->GetPlayerbotsDBRevision());
#endif #endif
@@ -33,8 +33,8 @@ enum Sartura
SAY_DEATH = 2, SAY_DEATH = 2,
SPELL_WHIRLWIND = 26083, SPELL_WHIRLWIND = 26083,
SPELL_ENRAGE = 28747, //Not sure if right ID. SPELL_ENRAGE = 8269,
SPELL_ENRAGEHARD = 28798, SPELL_BERSERK = 27680,
//Guard Spell //Guard Spell
SPELL_WHIRLWINDADD = 26038, SPELL_WHIRLWINDADD = 26038,
@@ -166,7 +166,7 @@ public:
{ {
if (!HealthAbovePct(20) && !me->IsNonMeleeSpellCast(false)) if (!HealthAbovePct(20) && !me->IsNonMeleeSpellCast(false))
{ {
DoCast(me, SPELL_ENRAGE); DoCast(me, SPELL_ENRAGE, true);
Enraged = true; Enraged = true;
} }
} }
@@ -176,7 +176,7 @@ public:
{ {
if (EnrageHard_Timer <= diff) if (EnrageHard_Timer <= diff)
{ {
DoCast(me, SPELL_ENRAGEHARD); DoCast(me, SPELL_BERSERK, true);
EnragedHard = true; EnragedHard = true;
} }
else EnrageHard_Timer -= diff; else EnrageHard_Timer -= diff;
@@ -311,7 +311,7 @@ public:
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim() || !CheckInRoom()) if (!UpdateVictim())
return; return;
events.Update(diff); events.Update(diff);
@@ -189,7 +189,7 @@ public:
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim() || !CheckInRoom()) if (!UpdateVictim())
return; return;
events.Update(diff); events.Update(diff);
@@ -330,7 +330,7 @@ public:
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if ((!UpdateVictim() && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) || !CheckInRoom()) if (!UpdateVictim() && !(events.GetPhaseMask() & PHASE_INTRO_MASK))
return; return;
events.Update(diff); events.Update(diff);
@@ -156,7 +156,7 @@ public:
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim() || !CheckInRoom()) if (!UpdateVictim())
return; return;
events.Update(diff); events.Update(diff);
@@ -524,7 +524,7 @@ public:
return; return;
} }
if (!UpdateVictim() || !CheckInRoom()) if (!UpdateVictim())
return; return;
events.Update(diff); events.Update(diff);
@@ -258,7 +258,7 @@ public:
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim() || !CheckInRoom()) if (!UpdateVictim())
return; return;
events.Update(diff); events.Update(diff);
@@ -523,7 +523,7 @@ public:
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim() || !CheckInRoom()) if (!UpdateVictim())
return; return;
events.Update(diff); events.Update(diff);
@@ -80,7 +80,7 @@ BossBoundaryData const boundaries =
{ DATA_SISTER_SVALNA, new RectangleBoundary(4291.0f, 4423.0f, 2438.0f, 2653.0f) }, { DATA_SISTER_SVALNA, new RectangleBoundary(4291.0f, 4423.0f, 2438.0f, 2653.0f) },
{ DATA_VALITHRIA_DREAMWALKER, new RectangleBoundary(4112.5f, 4293.5f, 2385.0f, 2585.0f) }, { DATA_VALITHRIA_DREAMWALKER, new RectangleBoundary(4112.5f, 4293.5f, 2385.0f, 2585.0f) },
{ DATA_SINDRAGOSA, new EllipseBoundary(Position(4408.6f, 2484.0f), 100.0, 75.0) } { DATA_SINDRAGOSA, new EllipseBoundary(Position(4418.6f, 2484.0f), 110.0, 75.0) }
}; };
DoorData const doorData[] = DoorData const doorData[] =
@@ -164,7 +164,7 @@ public:
break; break;
} }
if (!UpdateVictim() || !CheckInRoom()) if (!UpdateVictim())
return; return;
events.Update(diff); events.Update(diff);
+130 -22
View File
@@ -218,12 +218,23 @@ class spell_gen_have_item_auras : public AuraScript
} }
}; };
enum MineSweeper
{
SPELL_LAND_MINE_KNOCKBACK = 54402,
SPELL_LANDMINE_KNOCKBACK_ACHIEVEMENT = 57064,
};
/* 54355 - Detonation /* 54355 - Detonation
57099 - Landmine Knockback Achievement Aura */ 57099 - Landmine Knockback Achievement Aura */
class spell_gen_mine_sweeper : public SpellScript class spell_gen_mine_sweeper : public SpellScript
{ {
PrepareSpellScript(spell_gen_mine_sweeper); PrepareSpellScript(spell_gen_mine_sweeper);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_LAND_MINE_KNOCKBACK, SPELL_LANDMINE_KNOCKBACK_ACHIEVEMENT});
}
void HandleSchoolDMG(SpellEffIndex /*effIndex*/) void HandleSchoolDMG(SpellEffIndex /*effIndex*/)
{ {
Unit* caster = GetCaster(); Unit* caster = GetCaster();
@@ -232,7 +243,7 @@ class spell_gen_mine_sweeper : public SpellScript
return; return;
target->RemoveAurasByType(SPELL_AURA_MOUNTED); target->RemoveAurasByType(SPELL_AURA_MOUNTED);
caster->CastSpell(target, 54402, true); caster->CastSpell(target, SPELL_LAND_MINE_KNOCKBACK, true);
} }
void HandleScriptEffect(SpellEffIndex /*effIndex*/) void HandleScriptEffect(SpellEffIndex /*effIndex*/)
@@ -240,7 +251,7 @@ class spell_gen_mine_sweeper : public SpellScript
if (Unit* target = GetHitPlayer()) if (Unit* target = GetHitPlayer())
if (Aura* aur = target->GetAura(GetSpellInfo()->Id)) if (Aura* aur = target->GetAura(GetSpellInfo()->Id))
if (aur->GetStackAmount() >= 10) if (aur->GetStackAmount() >= 10)
target->CastSpell(target, 57064, true); target->CastSpell(target, SPELL_LANDMINE_KNOCKBACK_ACHIEVEMENT, true);
} }
void Register() override void Register() override
@@ -1840,6 +1851,11 @@ class spell_gen_teleporting : public SpellScript
{ {
PrepareSpellScript(spell_gen_teleporting); PrepareSpellScript(spell_gen_teleporting);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_TELEPORT_SPIRE_UP, SPELL_TELEPORT_SPIRE_DOWN });
}
void HandleScript(SpellEffIndex /* effIndex */) void HandleScript(SpellEffIndex /* effIndex */)
{ {
Unit* target = GetHitUnit(); Unit* target = GetHitUnit();
@@ -2268,6 +2284,11 @@ class spell_gen_turkey_marker : public AuraScript
{ {
PrepareAuraScript(spell_gen_turkey_marker); PrepareAuraScript(spell_gen_turkey_marker);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_TURKEY_VENGEANCE });
}
bool Load() override bool Load() override
{ {
_applyTimes.clear(); _applyTimes.clear();
@@ -2470,7 +2491,14 @@ class spell_gen_damage_reduction_aura : public AuraScript
bool Validate(SpellInfo const* /*spellInfo*/) override bool Validate(SpellInfo const* /*spellInfo*/) override
{ {
return ValidateSpellInfo({ SPELL_DAMAGE_REDUCTION_AURA }); return ValidateSpellInfo(
{
SPELL_DAMAGE_REDUCTION_AURA,
SPELL_BLESSING_OF_SANCTUARY,
SPELL_GREATER_BLESSING_OF_SANCTUARY,
SPELL_RENEWED_HOPE,
SPELL_VIGILANCE
});
} }
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
@@ -2665,26 +2693,17 @@ class spell_gen_dalaran_disguise : public SpellScript
{ {
PrepareSpellScript(spell_gen_dalaran_disguise); PrepareSpellScript(spell_gen_dalaran_disguise);
bool Validate(SpellInfo const* spellInfo) override bool Validate(SpellInfo const* /*spellInfo*/) override
{ {
switch (spellInfo->Id) return ValidateSpellInfo(
{ {
case SPELL_SUNREAVER_DISGUISE_TRIGGER: SPELL_SUNREAVER_DISGUISE_TRIGGER,
return ValidateSpellInfo( SPELL_SUNREAVER_DISGUISE_FEMALE,
{ SPELL_SUNREAVER_DISGUISE_MALE,
SPELL_SUNREAVER_DISGUISE_FEMALE, SPELL_SILVER_COVENANT_DISGUISE_TRIGGER,
SPELL_SUNREAVER_DISGUISE_MALE SPELL_SILVER_COVENANT_DISGUISE_FEMALE,
}); SPELL_SILVER_COVENANT_DISGUISE_MALE
case SPELL_SILVER_COVENANT_DISGUISE_TRIGGER: });
return ValidateSpellInfo(
{
SPELL_SILVER_COVENANT_DISGUISE_FEMALE,
SPELL_SILVER_COVENANT_DISGUISE_MALE
});
default:
break;
}
return false;
} }
void HandleScript(SpellEffIndex /*effIndex*/) void HandleScript(SpellEffIndex /*effIndex*/)
@@ -2759,6 +2778,19 @@ class spell_gen_break_shield : public SpellScript
{ {
PrepareSpellScript(spell_gen_break_shield) PrepareSpellScript(spell_gen_break_shield)
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_BREAK_SHIELD_DAMAGE_2K,
SPELL_BREAK_SHIELD_DAMAGE_10K,
SPELL_BREAK_SHIELD_TRIGGER_FACTION_MOUNTS,
SPELL_BREAK_SHIELD_TRIGGER_CAMPAING_WARHORSE,
SPELL_BREAK_SHIELD_TRIGGER_UNK,
SPELL_BREAK_SHIELD_TRIGGER_SUNDERING_THURST
});
}
void HandleScriptEffect(SpellEffIndex effIndex) void HandleScriptEffect(SpellEffIndex effIndex)
{ {
Unit* target = GetHitUnit(); Unit* target = GetHitUnit();
@@ -2876,6 +2908,24 @@ class spell_gen_mounted_charge : public SpellScript
{ {
PrepareSpellScript(spell_gen_mounted_charge) PrepareSpellScript(spell_gen_mounted_charge)
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_CHARGE_DAMAGE_8K5,
SPELL_CHARGE_DAMAGE_20K,
SPELL_CHARGE_DAMAGE_45K,
SPELL_CHARGE_CHARGING_EFFECT_8K5,
SPELL_CHARGE_CHARGING_EFFECT_20K_1,
SPELL_CHARGE_CHARGING_EFFECT_20K_2,
SPELL_CHARGE_CHARGING_EFFECT_45K_1,
SPELL_CHARGE_CHARGING_EFFECT_45K_2,
SPELL_CHARGE_TRIGGER_FACTION_MOUNTS,
SPELL_CHARGE_TRIGGER_TRIAL_CHAMPION,
SPELL_CHARGE_MISS_EFFECT
});
}
void HandleScriptEffect(SpellEffIndex effIndex) void HandleScriptEffect(SpellEffIndex effIndex)
{ {
Unit* target = GetHitUnit(); Unit* target = GetHitUnit();
@@ -3250,6 +3300,49 @@ class spell_gen_on_tournament_mount : public AuraScript
{ {
PrepareAuraScript(spell_gen_on_tournament_mount); PrepareAuraScript(spell_gen_on_tournament_mount);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_PENNANT_STORMWIND_ASPIRANT,
SPELL_PENNANT_STORMWIND_VALIANT,
SPELL_PENNANT_STORMWIND_CHAMPION,
SPELL_PENNANT_GNOMEREGAN_ASPIRANT,
SPELL_PENNANT_GNOMEREGAN_VALIANT,
SPELL_PENNANT_GNOMEREGAN_CHAMPION,
SPELL_PENNANT_SEN_JIN_ASPIRANT,
SPELL_PENNANT_SEN_JIN_VALIANT,
SPELL_PENNANT_SEN_JIN_CHAMPION,
SPELL_PENNANT_SILVERMOON_ASPIRANT,
SPELL_PENNANT_SILVERMOON_VALIANT,
SPELL_PENNANT_SILVERMOON_CHAMPION,
SPELL_PENNANT_DARNASSUS_ASPIRANT,
SPELL_PENNANT_DARNASSUS_VALIANT,
SPELL_PENNANT_DARNASSUS_CHAMPION,
SPELL_PENNANT_EXODAR_ASPIRANT,
SPELL_PENNANT_EXODAR_VALIANT,
SPELL_PENNANT_EXODAR_CHAMPION,
SPELL_PENNANT_IRONFORGE_ASPIRANT,
SPELL_PENNANT_IRONFORGE_VALIANT,
SPELL_PENNANT_IRONFORGE_CHAMPION,
SPELL_PENNANT_UNDERCITY_ASPIRANT,
SPELL_PENNANT_UNDERCITY_VALIANT,
SPELL_PENNANT_UNDERCITY_CHAMPION,
SPELL_PENNANT_ORGRIMMAR_ASPIRANT,
SPELL_PENNANT_ORGRIMMAR_VALIANT,
SPELL_PENNANT_ORGRIMMAR_CHAMPION,
SPELL_PENNANT_THUNDER_BLUFF_ASPIRANT,
SPELL_PENNANT_THUNDER_BLUFF_VALIANT,
SPELL_PENNANT_THUNDER_BLUFF_CHAMPION,
SPELL_PENNANT_ARGENT_CRUSADE_ASPIRANT,
SPELL_PENNANT_ARGENT_CRUSADE_VALIANT,
SPELL_PENNANT_ARGENT_CRUSADE_CHAMPION,
SPELL_PENNANT_EBON_BLADE_ASPIRANT,
SPELL_PENNANT_EBON_BLADE_VALIANT,
SPELL_PENNANT_EBON_BLADE_CHAMPION
});
}
uint32 _pennantSpellId; uint32 _pennantSpellId;
bool Load() override bool Load() override
@@ -3968,6 +4061,11 @@ class spell_gen_bonked : public SpellScript
{ {
PrepareSpellScript(spell_gen_bonked); PrepareSpellScript(spell_gen_bonked);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_BONKED, SPELL_FOAM_SWORD_DEFEAT, SPELL_ON_GUARD });
}
void HandleScript(SpellEffIndex /*effIndex*/) void HandleScript(SpellEffIndex /*effIndex*/)
{ {
if (Player* target = GetHitPlayer()) if (Player* target = GetHitPlayer())
@@ -4051,6 +4149,11 @@ class spell_gen_replenishment : public SpellScript
{ {
PrepareSpellScript(spell_gen_replenishment); PrepareSpellScript(spell_gen_replenishment);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_REPLENISHMENT, SPELL_INFINITE_REPLENISHMENT });
}
void RemoveInvalidTargets(std::list<WorldObject*>& targets) void RemoveInvalidTargets(std::list<WorldObject*>& targets)
{ {
// In arenas Replenishment may only affect the caster // In arenas Replenishment may only affect the caster
@@ -4352,6 +4455,11 @@ class spell_gen_holiday_buff_food : public AuraScript
{ {
PrepareAuraScript(spell_gen_holiday_buff_food); PrepareAuraScript(spell_gen_holiday_buff_food);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WELL_FED });
}
void TriggerFoodBuff(AuraEffect* aurEff) void TriggerFoodBuff(AuraEffect* aurEff)
{ {
if (aurEff->GetTickNumber() == 10 && GetUnitOwner()) if (aurEff->GetTickNumber() == 10 && GetUnitOwner())
@@ -22,9 +22,15 @@
#include <iterator> #include <iterator>
template <class T> template <class T>
class DBCStorageIterator : public std::iterator<std::forward_iterator_tag, T> class DBCStorageIterator
{ {
public: public:
using iterator_category = std::forward_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using reference = T&;
DBCStorageIterator() : _index(nullptr) { } DBCStorageIterator() : _index(nullptr) { }
DBCStorageIterator(T** index, uint32 size, uint32 pos = 0) : _index(index), _pos(pos), _end(size) DBCStorageIterator(T** index, uint32 size, uint32 pos = 0) : _index(index), _pos(pos), _end(size)
{ {
+5
View File
@@ -3282,6 +3282,11 @@ enum SummonType
enum EventId enum EventId
{ {
EVENT_CHARGE = 1003, EVENT_CHARGE = 1003,
/// Special charge event which is used for charge spells that have explicit targets
/// and had a path already generated - using it in PointMovementGenerator will not
/// create a new spline and launch it
EVENT_CHARGE_PREPATH = 1005,
}; };
enum ResponseCodes enum ResponseCodes
-1
View File
@@ -484,7 +484,6 @@ bool StartDB()
WorldDatabase.Execute("UPDATE version SET core_version = '{}', core_revision = '{}'", GitRevision::GetFullVersion(), GitRevision::GetHash()); // One-time query WorldDatabase.Execute("UPDATE version SET core_version = '{}', core_revision = '{}'", GitRevision::GetFullVersion(), GitRevision::GetHash()); // One-time query
sWorld->LoadDBVersion(); sWorld->LoadDBVersion();
sWorld->LoadDBRevision();
LOG_INFO("server.loading", "> Version DB world: {}", sWorld->GetDBVersion()); LOG_INFO("server.loading", "> Version DB world: {}", sWorld->GetDBVersion());
-4
View File
@@ -111,11 +111,7 @@ public:
MOCK_METHOD(void, UpdateRealmCharCount, (uint32 accid), ()); MOCK_METHOD(void, UpdateRealmCharCount, (uint32 accid), ());
MOCK_METHOD(LocaleConstant, GetAvailableDbcLocale, (LocaleConstant locale), (const)); MOCK_METHOD(LocaleConstant, GetAvailableDbcLocale, (LocaleConstant locale), (const));
MOCK_METHOD(void, LoadDBVersion, ()); MOCK_METHOD(void, LoadDBVersion, ());
MOCK_METHOD(void, LoadDBRevision, ());
MOCK_METHOD(char const *, GetDBVersion, (), (const)); MOCK_METHOD(char const *, GetDBVersion, (), (const));
MOCK_METHOD(char const *, GetWorldDBRevision, (), (const));
MOCK_METHOD(char const *, GetCharacterDBRevision, (), (const));
MOCK_METHOD(char const *, GetAuthDBRevision, (), (const));
MOCK_METHOD(void, LoadAutobroadcasts, ()); MOCK_METHOD(void, LoadAutobroadcasts, ());
MOCK_METHOD(void, UpdateAreaDependentAuras, ()); MOCK_METHOD(void, UpdateAreaDependentAuras, ());
MOCK_METHOD(uint32, GetCleaningFlags, (), (const)); MOCK_METHOD(uint32, GetCleaningFlags, (), (const));
-4
View File
@@ -14,7 +14,3 @@ add_subdirectory(map_extractor)
add_subdirectory(vmap4_assembler) add_subdirectory(vmap4_assembler)
add_subdirectory(vmap4_extractor) add_subdirectory(vmap4_extractor)
add_subdirectory(mmaps_generator) add_subdirectory(mmaps_generator)
if (WITH_MESHEXTRACTOR)
add_subdirectory(mesh_extractor)
endif()
-70
View File
@@ -1,70 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ADT.h"
#include "DoodadHandler.h"
#include "LiquidHandler.h"
#include "WorldModelHandler.h"
ADT::ADT( std::string file, int x, int y ) : ObjectData(nullptr), Data(nullptr), HasObjectData(false),
_DoodadHandler(nullptr), _WorldModelHandler(nullptr), _LiquidHandler(nullptr), X(x), Y(y)
{
Data = new ChunkedData(file);
ObjectData = new ChunkedData(file);
if (ObjectData->Stream)
HasObjectData = true;
else
ObjectData = nullptr;
}
ADT::~ADT()
{
delete ObjectData;
delete Data;
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
delete *itr;
MapChunks.clear();
delete _DoodadHandler;
delete _WorldModelHandler;
delete _LiquidHandler;
}
void ADT::Read()
{
Header.Read(Data->GetChunkByName("MHDR")->GetStream());
MapChunks.reserve(16 * 16);
for (std::vector<Chunk*>::iterator itr = Data->Chunks.begin(); itr != Data->Chunks.end(); ++itr)
if ((*itr)->Name == "MCNK")
MapChunks.push_back(new MapChunk(this, *itr));
_LiquidHandler = new LiquidHandler(this);
// do this separate from map chunk initialization to access liquid data
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
(*itr)->GenerateTriangles();
_DoodadHandler = new DoodadHandler(this);
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
_DoodadHandler->ProcessMapChunk(*itr);
_WorldModelHandler = new WorldModelHandler(this);
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
_WorldModelHandler->ProcessMapChunk(*itr);
}
-49
View File
@@ -1,49 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADT_H
#define ADT_H
#include "ChunkedData.h"
#include "MapChunk.h"
class DoodadHandler;
class WorldModelHandler;
class LiquidHandler;
class ADT
{
public:
ADT(std::string file, int x, int y);
~ADT();
void Read();
ChunkedData* ObjectData;
ChunkedData* Data;
std::vector<MapChunk*> MapChunks;
MHDR Header;
// Can we dispose of this?
bool HasObjectData;
DoodadHandler* _DoodadHandler;
WorldModelHandler* _WorldModelHandler;
LiquidHandler* _LiquidHandler;
int X;
int Y;
};
#endif
-49
View File
@@ -1,49 +0,0 @@
#
# This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
CollectSourceFiles(
${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE_SOURCES)
add_executable(MeshExtractor ${PRIVATE_SOURCES})
target_link_libraries(MeshExtractor
PRIVATE
acore-core-interface
PUBLIC
common
Recast
mpq)
# Group sources
GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
CollectIncludeDirectories(
${CMAKE_CURRENT_SOURCE_DIR}
PUBLIC_INCLUDES)
target_include_directories(MeshExtractor
PUBLIC
${PUBLIC_INCLUDES}
PRIVATE
${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(MeshExtractor
PROPERTIES
FOLDER
"tools")
if( UNIX )
install(TARGETS MeshExtractor DESTINATION bin)
elseif( WIN32 )
install(TARGETS MeshExtractor DESTINATION "${CMAKE_INSTALL_PREFIX}")
endif()
-80
View File
@@ -1,80 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CACHE_H
#define CACHE_H
#include "Define.h"
#include "Model.h"
#include "PolicyLock.h"
#include "WorldModelRoot.h"
#include <map>
#include <mutex>
#include <string>
template<class K, class T>
class GenericCache
{
public:
GenericCache() {}
static const uint32 FlushLimit = 300; // We can't get too close to filling up all the memory, and we have to be wary of the maximum number of open streams.
void Insert(K key, T* val)
{
std::lock_guard<std::mutex> guard(mutex);
if (_items.size() > FlushLimit)
Clear();
_items[key] = val;
}
T* Get(K key)
{
GUARD_RETURN(mutex, nullptr);
typename std::map<K, T*>::iterator itr = _items.find(key);
if (itr != _items.end())
return itr->second;
return nullptr;
}
void Clear()
{
for (typename std::map<K, T*>::iterator itr = _items.begin(); itr != _items.end(); ++itr)
delete itr->second;
_items.clear();
}
private:
std::map<K, T*> _items;
std::mutex mutex;
};
class CacheClass
{
public:
CacheClass() {}
GenericCache<std::string, Model> ModelCache;
GenericCache<std::string, WorldModelRoot> WorldModelCache;
void Clear()
{
ModelCache.Clear();
WorldModelCache.Clear();
}
};
extern CacheClass* Cache;
#endif
-48
View File
@@ -1,48 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Chunk.h"
#include "Utils.h"
int32 Chunk::FindSubChunkOffset(std::string name)
{
// Reverse the name
name = std::string(name.rbegin(), name.rend());
if (name.size() != 4)
return -1;
FILE* stream = GetStream();
uint32 matched = 0;
while (uint32(ftell(stream)) < Utils::Size(stream))
{
char b = 0;
if (fread(&b, sizeof(char), 1, stream) != 1 || b != name[matched])
matched = 0;
else
++matched;
if (matched == 4)
return ftell(stream) - 4;
}
return -1;
}
FILE* Chunk::GetStream()
{
fseek(Stream, Offset, SEEK_SET);
return Stream;
}
-37
View File
@@ -1,37 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHUNK_H
#define CHUNK_H
#include "Define.h"
#include <string>
class ChunkedData;
class Chunk
{
public:
Chunk(const char* name, uint32 length, uint32 offset, FILE* stream) : Name(name), Length(length), Offset(offset), Stream(stream) {}
int32 FindSubChunkOffset(std::string name);
FILE* GetStream();
std::string Name;
uint32 Length;
uint32 Offset;
FILE* Stream;
};
#endif
-91
View File
@@ -1,91 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ChunkedData.h"
#include "MPQMgr.h"
#include "Utils.h"
#include <string>
ChunkedData::ChunkedData( FILE* stream, uint32 maxLength, uint32 chunksHint /*= 300*/ ) :
Stream(stream)
{
if (!Stream)
return;
Load(maxLength, chunksHint);
}
ChunkedData::ChunkedData( const std::string& file, uint32 chunksHint /*= 300*/ )
{
Stream = MPQHandler->GetFile(file);
if (!Stream)
return;
Load(0, chunksHint);
}
void ChunkedData::Load( uint32 maxLength, uint32 chunksHint )
{
if (!maxLength)
maxLength = Utils::Size(Stream);
Chunks.reserve(chunksHint);
uint32 baseOffset = ftell(Stream);
uint32 calcOffset = 0;
while ((calcOffset + baseOffset) < Utils::Size(Stream) && (calcOffset < maxLength))
{
char nameBytes[5];
uint32 read = fread(&nameBytes, sizeof(char), 4, Stream);
nameBytes[read] = '\0';
std::string name = std::string(nameBytes);
// Utils::Reverse(nameBytes);
name = std::string(name.rbegin(), name.rend());
uint32 length;
if (fread(&length, sizeof(uint32), 1, Stream) != 1)
continue;
calcOffset += 8;
Chunks.push_back(new Chunk(name.c_str(), length, calcOffset + baseOffset, Stream));
calcOffset += length;
// save an extra seek at the end
if ((calcOffset + baseOffset) < Utils::Size(Stream) && calcOffset < maxLength)
fseek(Stream, length, SEEK_CUR);
}
}
int ChunkedData::GetFirstIndex( const std::string& name )
{
for (uint32 i = 0; i < Chunks.size(); ++i)
if (Chunks[i]->Name == name)
return i;
return -1;
}
Chunk* ChunkedData::GetChunkByName( const std::string& name )
{
for (uint32 i = 0; i < Chunks.size(); ++i)
if (Chunks[i]->Name == name)
return Chunks[i];
return nullptr;
}
ChunkedData::~ChunkedData()
{
for (std::vector<Chunk*>::iterator itr = Chunks.begin(); itr != Chunks.end(); ++itr)
delete *itr;
Chunks.clear();
if (Stream)
fclose(Stream);
}
-38
View File
@@ -1,38 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHNK_H
#define CHNK_H
#include "Chunk.h"
#include <vector>
class ChunkedData
{
public:
ChunkedData(FILE* stream, uint32 maxLength, uint32 chunksHint = 300);
ChunkedData(const std::string& file, uint32 chunksHint = 300);
~ChunkedData();
int GetFirstIndex(const std::string& name);
Chunk* GetChunkByName(const std::string& name);
void Load(uint32 maxLength, uint32 chunksHint);
std::vector<Chunk*> Chunks;
FILE* Stream;
};
#endif
-75
View File
@@ -1,75 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONSTANTS_H
#define CONSTANTS_H
class Constants
{
public:
enum TriangleType
{
TRIANGLE_TYPE_UNKNOWN,
TRIANGLE_TYPE_TERRAIN,
TRIANGLE_TYPE_WATER,
TRIANGLE_TYPE_DOODAD,
TRIANGLE_TYPE_WMO
};
enum PolyArea
{
POLY_AREA_TERRAIN = 1,
POLY_AREA_WATER = 2,
POLY_AREA_ROAD = 3,
POLY_AREA_DANGER = 4,
};
enum PolyFlag
{
POLY_FLAG_WALK = 1,
POLY_FLAG_SWIM = 2,
POLY_FLAG_FLIGHTMASTER = 4
};
enum ExtractFlags
{
EXTRACT_FLAG_DBC = 0x01,
EXTRACT_FLAG_MAPS = 0x02,
EXTRACT_FLAG_VMAPS = 0x04,
EXTRACT_FLAG_GOB_MODELS = 0x08,
EXTRACT_FLAG_MMAPS = 0x10,
EXTRACT_FLAG_TEST = 0x20,
EXTRACT_FLAG_ALLOWED = EXTRACT_FLAG_DBC | EXTRACT_FLAG_MAPS | EXTRACT_FLAG_VMAPS | EXTRACT_FLAG_GOB_MODELS | EXTRACT_FLAG_MMAPS | EXTRACT_FLAG_TEST
};
static const float TileSize;
static const float MaxXY;
static const float ChunkSize;
static const float UnitSize;
static const float Origin[];
static const float PI;
static const float MaxStandableHeight;
static bool ToWoWCoords;
static bool Debug;
static const char* VMAPMagic;
static const float BaseUnitDim;
static const int VertexPerMap;
static const int VertexPerTile;
static const int TilesPerMap;
};
#endif
@@ -1,213 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ContinentBuilder.h"
#include "Cache.h"
#include "DetourCommon.h"
#include "DetourNavMesh.h"
#include "Recast.h"
#include "TileBuilder.h"
#include "Utils.h"
#include "WDT.h"
#include <thread>
class BuilderThread
{
private:
int X, Y, MapId;
std::string Continent;
dtNavMeshParams Params;
ContinentBuilder* cBuilder;
public:
BuilderThread(ContinentBuilder* _cBuilder, dtNavMeshParams& params) : Params(params), cBuilder(_cBuilder), Free(true) {}
void SetData(int x, int y, int map, const std::string& cont)
{
X = x;
Y = y;
MapId = map;
Continent = cont;
}
int svc()
{
Free = false;
printf("[%02i,%02i] Building tile\n", X, Y);
TileBuilder builder(cBuilder, Continent, X, Y, MapId);
char buff[100];
sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, Y, X);
FILE* f = fopen(buff, "r");
if (f) // Check if file already exists.
{
printf("[%02i,%02i] Tile skipped, file already exists\n", X, Y);
fclose(f);
Free = true;
return 0;
}
uint8* nav = builder.BuildTiled(Params);
if (nav)
{
f = fopen(buff, "wb");
if (!f)
{
printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff);
return 0;
}
MmapTileHeader header;
header.size = builder.DataSize;
fwrite(&header, sizeof(MmapTileHeader), 1, f);
fwrite(nav, sizeof(unsigned char), builder.DataSize, f);
fclose(f);
}
dtFree(nav);
printf("[%02i,%02i] Tile Built!\n", X, Y);
Free = true;
return 0;
}
bool Free;
};
void ContinentBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax)
{
// this is for elevation
if (verts && vertCount)
rcCalcBounds(verts, vertCount, bmin, bmax);
else
{
bmin[1] = FLT_MIN;
bmax[1] = FLT_MAX;
}
// this is for width and depth
bmax[0] = (32 - int(tileX)) * Constants::TileSize;
bmax[2] = (32 - int(tileY)) * Constants::TileSize;
bmin[0] = bmax[0] - Constants::TileSize;
bmin[2] = bmax[2] - Constants::TileSize;
}
void ContinentBuilder::CalculateTileBounds()
{
for (std::vector<TilePos>::iterator itr = TileMap->TileTable.begin(); itr != TileMap->TileTable.end(); ++itr)
{
tileXMax = std::max(itr->X, tileXMax);
tileXMin = std::min(itr->X, tileXMin);
tileYMax = std::max(itr->Y, tileYMax);
tileYMin = std::min(itr->Y, tileYMin);
}
getTileBounds(tileXMax, tileYMax, nullptr, 0, bmin, bmax);
}
void ContinentBuilder::Build()
{
char buff[50];
sprintf(buff, "mmaps/%03u.mmap", MapId);
FILE* mmap = fopen(buff, "wb");
if (!mmap)
{
printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff);
return;
}
CalculateTileBounds();
dtNavMeshParams params;
std::vector<BuilderThread*> Threads;
if (TileMap->IsGlobalModel)
{
printf("Map %s ( %u ) is a WMO. Building with 1 thread.\n", Continent.c_str(), MapId);
TileBuilder* builder = new TileBuilder(this, Continent, 0, 0, MapId);
builder->AddGeometry(TileMap->Model, TileMap->ModelDefinition);
uint8* nav = builder->BuildInstance(params);
if (nav)
{
// Set some params for the navmesh
dtMeshHeader* header = (dtMeshHeader*)nav;
dtVcopy(params.orig, header->bmin);
params.tileWidth = header->bmax[0] - header->bmin[0];
params.tileHeight = header->bmax[2] - header->bmin[2];
params.maxTiles = 1;
params.maxPolys = header->polyCount;
fwrite(&params, sizeof(dtNavMeshParams), 1, mmap);
fclose(mmap);
char buff[100];
sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, 0, 0);
FILE* f = fopen(buff, "wb");
if (!f)
{
printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff);
return;
}
MmapTileHeader mheader;
mheader.size = builder->DataSize;
fwrite(&mheader, sizeof(MmapTileHeader), 1, f);
fwrite(nav, sizeof(unsigned char), builder->DataSize, f);
fclose(f);
}
dtFree(nav);
delete builder;
}
else
{
params.maxPolys = 32768;
params.maxTiles = 4096;
rcVcopy(params.orig, Constants::Origin);
params.tileHeight = Constants::TileSize;
params.tileWidth = Constants::TileSize;
fwrite(&params, sizeof(dtNavMeshParams), 1, mmap);
fclose(mmap);
for (uint32 i = 0; i < NumberOfThreads; ++i)
Threads.push_back(new BuilderThread(this, params));
printf("Map %s ( %u ) has %u tiles. Building them with %u threads\n", Continent.c_str(), MapId, uint32(TileMap->TileTable.size()), NumberOfThreads);
for (std::vector<TilePos>::iterator itr = TileMap->TileTable.begin(); itr != TileMap->TileTable.end(); ++itr)
{
bool next = false;
while (!next)
{
for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th)
{
if ((*_th)->Free)
{
(*_th)->SetData(itr->X, itr->Y, MapId, Continent);
(*_th)->activate();
next = true;
break;
}
}
// Wait for 20 seconds
std::this_thread::sleep_for(std::chrono::seconds(20));
}
}
}
Cache->Clear();
// Free memory
for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th)
{
(*_th)->wait();
delete *_th;
}
}
@@ -1,47 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONT_BUILDER_H
#define CONT_BUILDER_H
#include "Define.h"
#include "WDT.h"
#include <string>
class ContinentBuilder
{
public:
ContinentBuilder(std::string continent, uint32 mapId, WDT* wdt, uint32 tn) :
Continent(continent), TileMap(wdt), MapId(mapId),
NumberOfThreads(tn), tileXMin(64), tileYMin(64), tileXMax(0), tileYMax(0)
{}
void Build();
void getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax);
void CalculateTileBounds();
float bmin[3];
float bmax[3];
private:
std::string Continent;
WDT* TileMap;
uint32 MapId;
uint32 NumberOfThreads;
int tileXMin;
int tileYMin;
int tileXMax;
int tileYMax;
};
#endif
-87
View File
@@ -1,87 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DBC.h"
#include "Define.h"
#include <cstdio>
DBC::DBC( FILE* stream ) : StringBlock(nullptr), StringBlockSize(0), IsFaulty(true)
{
char magic[5];
uint32 count = 0;
count += fread(&magic, sizeof(char), 4, stream);
magic[4] = '\0';
count += fread(&RecordCount, sizeof(uint32), 1, stream);
Records.reserve(RecordCount);
count += fread(&Fields, sizeof(uint32), 1, stream);
count += fread(&RecordSize, sizeof(uint32), 1, stream);
count += fread(&StringBlockSize, sizeof(uint32), 1, stream);
if (count != 8)
printf("DBC::DBC: Failed to read some data expected 8, read %u\n", count);
for (int i = 0; i < RecordCount; i++)
{
Record* rec = new Record(this);
Records.push_back(rec);
int size = 0;
for (int f = 0; f < Fields; f++)
{
if (size + 4 > RecordSize)
{
IsFaulty = true;
break;
}
uint32 tmp;
if (fread(&tmp, sizeof(uint32), 1, stream) != 1)
printf("DBC::DBC: Failed to read some data expected 1, read 0\n");
rec->Values.push_back(tmp);
size += 4;
}
}
StringBlock = new uint8[StringBlockSize];
count = fread(StringBlock, sizeof(uint8), StringBlockSize, stream);
if (count != StringBlockSize)
printf("DBC::DBC: Failed to read some data expected %u, read %u\n", StringBlockSize, count);
}
std::string DBC::GetStringByOffset( int offset )
{
int len = 0;
for (uint32 i = offset; i < StringBlockSize; i++)
{
if (!StringBlock[i])
{
len = (i - offset);
break;
}
}
char* d = new char[len + 1];
strcpy(d, (const char*)(StringBlock + offset));
d[len] = '\0';
std::string val = std::string(d);
delete [] d;
return val;
}
Record* DBC::GetRecordById( int id )
{
// we assume Id is index 0
for (std::vector<Record*>::iterator itr = Records.begin(); itr != Records.end(); ++itr)
if ((*itr)->Values[0] == id)
return *itr;
return nullptr;
}
-70
View File
@@ -1,70 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DBC_H
#define DBC_H
#include "Define.h"
#include <string>
#include <vector>
class Record;
class DBC
{
public:
DBC(FILE* stream);
std::string GetStringByOffset(int offset);
Record* GetRecordById(int id);
std::string Name;
std::vector<Record*> Records;
int RecordCount;
int Fields;
int RecordSize;
uint8* StringBlock;
uint32 StringBlockSize;
bool IsFaulty;
};
class Record
{
public:
Record(DBC* dbc) : Source(dbc) {}
DBC* Source;
std::vector<int> Values;
int operator[](int index)
{
return Values[index];
}
template <typename T>
T GetValue(int index)
{
return *(T*)(&Values[index]);
}
std::string Get<std::string>(int index)
{
return Source->GetStringByOffset(Values[index]);
}
};
#endif
-126
View File
@@ -1,126 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DoodadHandler.h"
#include "Cache.h"
#include "Chunk.h"
#include "G3D/Matrix4.h"
#include "Model.h"
DoodadHandler::DoodadHandler( ADT* adt ) :
ObjectDataHandler(adt), _definitions(nullptr), _paths(nullptr)
{
Chunk* mddf = adt->ObjectData->GetChunkByName("MDDF");
if (mddf)
ReadDoodadDefinitions(mddf);
Chunk* mmid = adt->ObjectData->GetChunkByName("MMID");
Chunk* mmdx = adt->ObjectData->GetChunkByName("MMDX");
if (mmid && mmdx)
ReadDoodadPaths(mmid, mmdx);
}
void DoodadHandler::ProcessInternal( MapChunk* mcnk )
{
if (!IsSane())
return;
uint32 refCount = mcnk->Header.DoodadRefs;
FILE* stream = mcnk->Source->GetStream();
fseek(stream, mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET);
for (uint32 i = 0; i < refCount; i++)
{
int32 index;
int32 count;
if ((count = fread(&index, sizeof(int32), 1, stream)) != 1)
printf("DoodadHandler::ProcessInternal: Failed to read some data expected 1, read %d\n", count);
if (index < 0 || uint32(index) >= _definitions->size())
continue;
DoodadDefinition doodad = (*_definitions)[index];
if (_drawn.find(doodad.UniqueId) != _drawn.end())
continue;
_drawn.insert(doodad.UniqueId);
if (doodad.MmidIndex >= _paths->size())
continue;
std::string path = (*_paths)[doodad.MmidIndex];
Model* model = Cache->ModelCache.Get(path);
if (!model)
{
model = new Model(path);
Cache->ModelCache.Insert(path, model);
}
if (!model->IsCollidable)
continue;
Vertices.reserve(refCount * model->Vertices.size() * 0.2);
Triangles.reserve(refCount * model->Triangles.size() * 0.2);
InsertModelGeometry(doodad, model);
}
// Restore the stream position
fseek(stream, mcnk->Source->Offset, SEEK_SET);
}
void DoodadHandler::ReadDoodadDefinitions( Chunk* chunk )
{
int32 count = chunk->Length / 36;
_definitions = new std::vector<DoodadDefinition>;
_definitions->reserve(count);
FILE* stream = chunk->GetStream();
for (int i = 0; i < count; i++)
{
DoodadDefinition def;
def.Read(stream);
_definitions->push_back(def);
}
}
void DoodadHandler::ReadDoodadPaths( Chunk* id, Chunk* data )
{
int paths = id->Length / 4;
_paths = new std::vector<std::string>();
_paths->reserve(paths);
for (int i = 0; i < paths; i++)
{
FILE* idStream = id->GetStream();
fseek(idStream, i * 4, SEEK_CUR);
uint32 offset;
if (fread(&offset, sizeof(uint32), 1, idStream) != 1)
printf("DoodadHandler::ReadDoodadPaths: Failed to read some data expected 1, read 0\n");
FILE* dataStream = data->GetStream();
fseek(dataStream, offset + data->Offset, SEEK_SET);
_paths->push_back(Utils::ReadString(dataStream));
}
}
void DoodadHandler::InsertModelGeometry(const DoodadDefinition& def, Model* model)
{
uint32 vertOffset = Vertices.size();
for (std::vector<Vector3>::iterator itr = model->Vertices.begin(); itr != model->Vertices.end(); ++itr)
Vertices.push_back(Utils::TransformDoodadVertex(def, *itr)); // Vertices have to be converted based on the information from the DoodadDefinition struct
for (std::vector<Triangle<uint16>>::iterator itr = model->Triangles.begin(); itr != model->Triangles.end(); ++itr)
Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_DOODAD, itr->V0 + vertOffset, itr->V1 + vertOffset, itr->V2 + vertOffset));
}
DoodadHandler::~DoodadHandler()
{
delete _definitions;
delete _paths;
}
-78
View File
@@ -1,78 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DOOADHNDL_H
#define DOOADHNDL_H
#include "Chunk.h"
#include "Model.h"
#include "ObjectDataHandler.h"
#include "Utils.h"
#include <set>
#include <vector>
class DoodadDefinition : public IDefinition
{
public:
uint32 MmidIndex;
uint32 UniqueId;
uint16 DecimalScale;
uint16 Flags;
virtual float Scale() const { return DecimalScale / 1024.0f; }
Vector3 FixCoords(Vector3& vec)
{
return Vector3(vec.z, vec.x, vec.y);
}
void Read(FILE* stream)
{
int count = 0;
count += fread(&MmidIndex, sizeof(uint32), 1, stream);
count += fread(&UniqueId, sizeof(uint32), 1, stream);
Position = (Vector3::Read(stream));
Rotation = Vector3::Read(stream);
count += fread(&DecimalScale, sizeof(uint16), 1, stream);
count += fread(&Flags, sizeof(uint16), 1, stream);
if (count != 4)
printf("DoodadDefinition::Read: Failed to read some data expected 4, read %d\n", count);
}
};
class DoodadHandler : public ObjectDataHandler
{
public:
DoodadHandler(ADT* adt);
~DoodadHandler();
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32>> Triangles;
bool IsSane() { return _definitions && _paths; }
protected:
void ProcessInternal(MapChunk* chunk);
private:
void ReadDoodadDefinitions(Chunk* chunk);
void ReadDoodadPaths(Chunk* id, Chunk* data);
void InsertModelGeometry(const DoodadDefinition& def, Model* model);
std::set<uint32> _drawn;
std::vector<DoodadDefinition>* _definitions;
std::vector<std::string>* _paths;
};
#endif
-144
View File
@@ -1,144 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Geometry.h"
#include "ADT.h"
#include "Constants.h"
#include "DoodadHandler.h"
#include "WorldModelHandler.h"
Geometry::Geometry() : Transform(false)
{
Vertices.reserve(10000);
Triangles.reserve(10000);
}
void Geometry::CalculateBoundingBox( float*& min, float*& max )
{
min = new float[3];
max = new float[3];
for (int i = 0; i < 3; ++i)
{
max[i] = std::numeric_limits<float>::min();
min[i] = std::numeric_limits<float>::max();
}
for (std::vector<Vector3>::iterator itr = Vertices.begin(); itr != Vertices.end(); ++itr)
{
if (itr->x > max[0])
max[0] = itr->x;
if (itr->x < min[0])
min[0] = itr->x;
if (itr->y > max[1])
max[1] = itr->y;
if (itr->y < min[1])
min[1] = itr->y;
if (itr->z > max[2])
max[2] = itr->z;
if (itr->z < min[2])
min[2] = itr->z;
}
}
void Geometry::CalculateMinMaxHeight( float& min, float& max )
{
min = std::numeric_limits<float>::max();
max = std::numeric_limits<float>::min();
for (std::vector<Vector3>::iterator itr = Vertices.begin(); itr != Vertices.end(); ++itr)
{
if (Transform)
{
if (itr->y < min)
min = itr->y;
if (itr->y > max)
max = itr->y;
}
else
{
if (itr->z < min)
min = itr->z;
if (itr->z > max)
max = itr->z;
}
}
}
void Geometry::AddData( std::vector<Vector3>& verts, std::vector<Triangle<uint32>>& tris )
{
uint32 vertOffset = Vertices.size();
for (std::vector<Vector3>::iterator itr = verts.begin(); itr != verts.end(); ++itr)
Vertices.push_back(Transform ? Utils::ToRecast(*itr) : *itr);
for (std::vector<Triangle<uint32>>::iterator itr = tris.begin(); itr != tris.end(); ++itr)
Triangles.push_back(Triangle<uint32>(itr->Type, itr->V0 + vertOffset, itr->V1 + vertOffset, itr->V2 + vertOffset));
}
void Geometry::GetRawData( float*& verts, int*& tris, uint8*& areas )
{
verts = new float[Vertices.size() * 3];
for (uint32 i = 0; i < Vertices.size(); ++i)
{
Vector3& vert = Vertices[i];
verts[(i * 3) + 0] = vert.x;
verts[(i * 3) + 1] = vert.y;
verts[(i * 3) + 2] = vert.z;
}
tris = new int[Triangles.size() * 3];
for (uint32 i = 0; i < Triangles.size(); ++i)
{
Triangle<uint32>& tri = Triangles[i];
tris[(i * 3) + 0] = (int)tri.V0;
tris[(i * 3) + 1] = (int)tri.V1;
tris[(i * 3) + 2] = (int)tri.V2;
}
areas = new uint8[Triangles.size()];
for (uint32 i = 0; i < Triangles.size(); i++)
{
switch (Triangles[i].Type)
{
case Constants::TRIANGLE_TYPE_WATER:
areas[i] = Constants::POLY_AREA_WATER;
break;
default:
areas[i] = Constants::POLY_AREA_TERRAIN;
break;
}
}
}
void Geometry::AddAdt( ADT* adt )
{
for (std::vector<MapChunk*>::iterator itr = adt->MapChunks.begin(); itr != adt->MapChunks.end(); ++itr)
{
std::vector<Triangle<uint32>> tmp;
tmp.reserve((*itr)->Triangles.size());
for (std::vector<Triangle<uint8>>::iterator itr2 = (*itr)->Triangles.begin(); itr2 != (*itr)->Triangles.end(); ++itr2)
tmp.push_back(Triangle<uint32>(itr2->Type, itr2->V0, itr2->V1, itr2->V2));
AddData((*itr)->Vertices, tmp);
}
if (!adt->_DoodadHandler->Triangles.empty())
AddData(adt->_DoodadHandler->Vertices, adt->_DoodadHandler->Triangles);
if (!adt->_WorldModelHandler->Triangles.empty())
AddData(adt->_WorldModelHandler->Vertices, adt->_WorldModelHandler->Triangles);
}
-40
View File
@@ -1,40 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GEOMETRY_H
#define GEOMETRY_H
#include <vector>
#include "Utils.h"
class ADT;
class Geometry
{
public:
Geometry();
void CalculateBoundingBox(float*& min, float*& max);
void CalculateMinMaxHeight(float& min, float& max);
void AddData(std::vector<Vector3>& verts, std::vector<Triangle<uint32>>& tris);
void AddAdt(ADT* adt);
void GetRawData(float*& verts, int*& tris, uint8*& areas);
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32>> Triangles;
bool Transform;
};
#endif
-119
View File
@@ -1,119 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LiquidHandler.h"
#include "Utils.h"
LiquidHandler::LiquidHandler( ADT* adt ) : Source(adt)
{
HandleNewLiquid();
}
void LiquidHandler::HandleNewLiquid()
{
Chunk* chunk = Source->Data->GetChunkByName("MH2O");
if (!chunk)
return;
Vertices.reserve(1000);
Triangles.reserve(1000);
FILE* stream = chunk->GetStream();
H2OHeader header[256];
MCNKData.reserve(256);
for (int i = 0; i < 256; i++)
header[i] = H2OHeader::Read(stream);
for (int i = 0; i < 256; i++)
{
H2OHeader h = header[i];
if (h.LayerCount == 0)
{
// Need to fill in missing data with dummies.
MCNKData.push_back(MCNKLiquidData(nullptr, H2ORenderMask()));
continue;
}
fseek(stream, chunk->Offset + h.OffsetInformation, SEEK_SET);
H2OInformation information = H2OInformation::Read(stream);
float** heights = new float*[9];
for (int j = 0; j < 9; ++j)
{
heights[j] = new float[9];
memset(heights[j], 0, sizeof(float) * 9);
}
H2ORenderMask renderMask;
if (information.LiquidType != 2)
{
fseek(stream, chunk->Offset + h.OffsetRender, SEEK_SET);
renderMask = H2ORenderMask::Read(stream);
if ((Utils::IsAllZero(renderMask.Mask, 8) || (information.Width == 8 && information.Height == 8)) && information.OffsetMask2)
{
fseek(stream, chunk->Offset + information.OffsetMask2, SEEK_SET);
uint32 size = std::ceil(information.Width * information.Height / 8.0f);
uint8* altMask = new uint8[size];
if (fread(altMask, sizeof(uint8), size, stream) == size)
for (uint32 mi = 0; mi < size; mi++)
renderMask.Mask[mi + information.OffsetY] |= altMask[mi];
delete[] altMask;
}
fseek(stream, chunk->Offset + information.OffsetHeightmap, SEEK_SET);
for (int y = information.OffsetY; y < (information.OffsetY + information.Height); y++)
for (int x = information.OffsetX; x < (information.OffsetX + information.Width); x++)
if (fread(&heights[x][y], sizeof(float), 1, stream) != 1)
return;
}
else
{
// Fill with ocean data
for (uint32 i = 0; i < 8; ++i)
renderMask.Mask[i] = 0xFF;
for (uint32 y = 0; y < 9; ++y)
for (uint32 x = 0; x < 9; ++x)
heights[x][y] = information.HeightLevel1;
}
MCNKData.push_back(MCNKLiquidData(heights, renderMask));
for (int y = information.OffsetY; y < (information.OffsetY + information.Height); y++)
{
for (int x = information.OffsetX; x < (information.OffsetX + information.Width); x++)
{
if (!renderMask.ShouldRender(x, y))
continue;
MapChunk* mapChunk = Source->MapChunks[i];
Vector3 location = mapChunk->Header.Position;
location.y = location.y - (x * Constants::UnitSize);
location.x = location.x - (y * Constants::UnitSize);
location.z = heights[x][y];
uint32 vertOffset = Vertices.size();
Vertices.push_back(location);
Vertices.push_back(Vector3(location.x - Constants::UnitSize, location.y, location.z));
Vertices.push_back(Vector3(location.x, location.y - Constants::UnitSize, location.z));
Vertices.push_back(Vector3(location.x - Constants::UnitSize, location.y - Constants::UnitSize, location.z));
Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset, vertOffset + 2, vertOffset + 1));
Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset + 2, vertOffset + 3, vertOffset + 1));
}
}
}
}
-38
View File
@@ -1,38 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIQUID_H
#define LIQUID_H
#include "ADT.h"
#include "Define.h"
#include "Utils.h"
#include <vector>
class LiquidHandler
{
public:
LiquidHandler(ADT* adt);
ADT* Source;
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32>> Triangles;
std::vector<MCNKLiquidData> MCNKData;
private:
void HandleNewLiquid();
};
#endif
-140
View File
@@ -1,140 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "MPQ.h"
#include "MPQMgr.h"
#include <cstdio>
#include <deque>
MPQArchive::MPQArchive(const char* filename)
{
int result = libmpq__archive_open(&mpq_a, filename, -1);
printf("Opening %s\n", filename);
if (result)
{
switch (result)
{
case LIBMPQ_ERROR_OPEN :
printf("Error opening archive '%s': Does file really exist?\n", filename);
break;
case LIBMPQ_ERROR_FORMAT : /* bad file format */
printf("Error opening archive '%s': Bad file format\n", filename);
break;
case LIBMPQ_ERROR_SEEK : /* seeking in file failed */
printf("Error opening archive '%s': Seeking in file failed\n", filename);
break;
case LIBMPQ_ERROR_READ : /* Read error in archive */
printf("Error opening archive '%s': Read error in archive\n", filename);
break;
case LIBMPQ_ERROR_MALLOC : /* maybe not enough memory? :) */
printf("Error opening archive '%s': Maybe not enough memory\n", filename);
break;
default:
printf("Error opening archive '%s': Unknown error\n", filename);
break;
}
}
GetFileListTo(Files);
}
void MPQArchive::close()
{
libmpq__archive_close(mpq_a);
}
MPQFile::MPQFile(const char* filename):
eof(false), buffer(0), pointer(0), size(0)
{
for (std::deque<MPQArchive*>::iterator i = MPQHandler->Archives.begin(); i != MPQHandler->Archives.end(); ++i)
{
mpq_archive* mpq_a = (*i)->mpq_a;
uint32_t filenum;
if (libmpq__file_number(mpq_a, filename, &filenum))
continue;
libmpq__off_t transferred;
libmpq__file_unpacked_size(mpq_a, filenum, &size);
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
if (size <= 1)
{
// printf("warning: file %s has size %d; cannot Read.\n", filename, size);
eof = true;
buffer = 0;
return;
}
buffer = new char[size];
//libmpq_file_getdata
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
/*libmpq_file_getdata(&mpq_a, hash, fileno, (unsigned char*)buffer);*/
return;
}
eof = true;
buffer = 0;
}
size_t MPQFile::Read(void* dest, size_t bytes)
{
if (eof)
return 0;
size_t rpos = pointer + bytes;
if (rpos > size_t(size))
{
bytes = size - pointer;
eof = true;
}
memcpy(dest, &(buffer[pointer]), bytes);
pointer = rpos;
return bytes;
}
void MPQFile::seek(int offset)
{
pointer = offset;
eof = (pointer >= size);
}
void MPQFile::seekRelative(int offset)
{
pointer += offset;
eof = (pointer >= size);
}
void MPQFile::close()
{
delete[] buffer;
buffer = 0;
eof = true;
}
FILE* MPQFile::GetFileStream()
{
FILE* file = tmpfile();
if (!file)
{
printf("Could not create temporary file. Please run as Administrator or root\n");
exit(1);
}
fwrite(buffer, sizeof(char), size, file);
fseek(file, 0, SEEK_SET);
return file;
}
-108
View File
@@ -1,108 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MPQ_H
#define MPQ_H
#include "Define.h"
#include "Errors.h"
#include "libmpq/mpq.h"
#include <ctype.h>
#include <deque>
#include <iostream>
#include <string>
#include <vector>
class MPQArchive
{
public:
mpq_archive_s* mpq_a;
std::vector<std::string> Files;
MPQArchive(const char* filename);
void close();
void GetFileListTo(std::vector<std::string>& filelist)
{
uint32_t filenum;
if (libmpq__file_number(mpq_a, "(listfile)", &filenum)) return;
libmpq__off_t size, transferred;
libmpq__file_unpacked_size(mpq_a, filenum, &size);
char* buffer = new char[size + 1];
buffer[size] = '\0';
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
char seps[] = "\n";
char* token;
token = strtok( buffer, seps );
uint32 counter = 0;
while ((token != nullptr) && (counter < size))
{
//cout << token << endl;
token[strlen(token) - 1] = 0;
std::string s = token;
filelist.push_back(s);
counter += strlen(token) + 2;
token = strtok(nullptr, seps);
}
delete[] buffer;
}
};
class MPQFile
{
//MPQHANDLE handle;
bool eof;
char* buffer;
libmpq__off_t pointer, size;
// disable copying
MPQFile(const MPQFile& /*f*/) {}
void operator=(const MPQFile& /*f*/) {}
public:
MPQFile(const char* filename); // filenames are not case sensitive
~MPQFile() { close(); }
size_t Read(void* dest, size_t bytes);
FILE* GetFileStream();
size_t getSize() { return size; }
size_t getPos() { return pointer; }
char* getBuffer() { return buffer; }
char* getPointer() { return buffer + pointer; }
bool isEof() { return eof; }
void seek(int offset);
void seekRelative(int offset);
void close();
};
inline void flipcc(char* fcc)
{
char t;
t = fcc[0];
fcc[0] = fcc[3];
fcc[3] = t;
t = fcc[1];
fcc[1] = fcc[2];
fcc[2] = t;
}
#endif
-132
View File
@@ -1,132 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "MPQMgr.h"
#include "DBC.h"
#include "MPQ.h"
#include "Utils.h"
char const* MPQMgr::Files[] =
{
"common.MPQ",
"common-2.MPQ",
"expansion.MPQ",
"lichking.MPQ",
"patch.MPQ",
"patch-2.MPQ",
"patch-3.MPQ"
};
char const* MPQMgr::Languages[] = { "enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" };
void MPQMgr::Initialize()
{
InitializeDBC();
uint32 size = sizeof(Files) / sizeof(char*);
for (uint32 i = 0; i < size; ++i)
{
MPQArchive* arc = new MPQArchive(std::string("Data/" + std::string(Files[i])).c_str());
Archives.push_front(arc); // MPQ files have to be transversed in reverse order to properly account for patched files
printf("Opened %s\n", Files[i]);
}
}
void MPQMgr::InitializeDBC()
{
BaseLocale = -1;
std::string fileName;
uint32 size = sizeof(Languages) / sizeof(char*);
MPQArchive* _baseLocale = nullptr;
for (uint32 i = 0; i < size; ++i)
{
std::string _fileName = "Data/" + std::string(Languages[i]) + "/locale-" + std::string(Languages[i]) + ".MPQ";
FILE* file = fopen(_fileName.c_str(), "rb");
if (file)
{
if (BaseLocale == -1)
{
BaseLocale = i;
_baseLocale = new MPQArchive(_fileName.c_str());
fileName = _fileName;
LocaleFiles[i] = _baseLocale;
}
else
LocaleFiles[i] = new MPQArchive(_fileName.c_str());
AvailableLocales.insert(i);
printf("Detected locale: %s\n", Languages[i]);
}
}
Archives.push_front(_baseLocale);
if (BaseLocale == -1)
{
printf("No locale data detected. Please make sure that the executable is in the same folder as your WoW installation.\n");
ABORT();
}
else
printf("Using default locale: %s\n", Languages[BaseLocale]);
}
FILE* MPQMgr::GetFile(const std::string& path )
{
GUARD_RETURN(mutex, nullptr);
MPQFile file(path.c_str());
if (file.isEof())
return nullptr;
return file.GetFileStream();
}
DBC* MPQMgr::GetDBC(const std::string& name )
{
std::string path = "DBFilesClient\\" + name + ".dbc";
return new DBC(GetFile(path));
}
FILE* MPQMgr::GetFileFrom(const std::string& path, MPQArchive* file )
{
GUARD_RETURN(mutex, nullptr);
mpq_archive* mpq_a = file->mpq_a;
uint32_t filenum;
if (libmpq__file_number(mpq_a, path.c_str(), &filenum))
return nullptr;
libmpq__off_t transferred;
libmpq__off_t size = 0;
libmpq__file_unpacked_size(mpq_a, filenum, &size);
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
if (size <= 1)
return nullptr;
uint8* buffer = new uint8[size];
//libmpq_file_getdata
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
// Pack the return into a FILE stream
FILE* ret = tmpfile();
if (!ret)
{
printf("Could not create temporary file. Please run as Administrator or root\n");
exit(1);
}
fwrite(buffer, sizeof(uint8), size, ret);
fseek(ret, 0, SEEK_SET);
delete[] buffer;
return ret;
}
-54
View File
@@ -1,54 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MPQ_MANAGER_H
#define MPQ_MANAGER_H
#include "MPQ.h"
#include "PolicyLock.h"
#include <map>
#include <mutex>
#include <set>
class DBC;
class MPQMgr
{
public:
MPQMgr() {}
~MPQMgr() {}
void Initialize();
FILE* GetFile(const std::string& path);
FILE* GetFileFrom(const std::string& path, MPQArchive* file);
DBC* GetDBC(const std::string& name);
std::vector<std::string> GetAllFiles(std::string extension);
std::deque<MPQArchive*> Archives;
int32 BaseLocale;
std::set<uint32> AvailableLocales;
std::map<uint32, MPQArchive*> LocaleFiles;
static char const* Files[];
static char const* Languages[];
protected:
void InitializeDBC();
private:
std::mutex mutex;
};
extern MPQMgr* MPQHandler;
#endif
-93
View File
@@ -1,93 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "MapChunk.h"
#include "ADT.h"
#include "LiquidHandler.h"
MapChunk::MapChunk( ADT* _adt, Chunk* chunk ) : Adt(_adt), Source(chunk)
{
FILE* stream = chunk->GetStream();
Header.Read(stream);
fseek(stream, chunk->Offset, SEEK_SET);
Index = Header.IndexX + Header.IndexY * 16;
GenerateVertices(stream);
}
void MapChunk::GenerateTriangles()
{
Triangles.reserve(256);
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
if (HasHole(Header.Holes, x / 2, y / 2))
continue;
uint32 topLeft = (17 * y) + x;
uint32 topRight = (17 * y) + x + 1;
uint32 bottomLeft = (17 * (y + 1)) + x;
uint32 bottomRight = (17 * (y + 1)) + x + 1;
uint32 center = (17 * y) + 9 + x;
Constants::TriangleType triangleType = Constants::TRIANGLE_TYPE_TERRAIN;
if (Adt->_LiquidHandler && !Adt->_LiquidHandler->MCNKData.empty())
{
MCNKLiquidData& data = Adt->_LiquidHandler->MCNKData[Index];
float maxHeight = std::max(
std::max(
std::max(std::max(Vertices[topLeft].z, Vertices[topRight].z), Vertices[bottomLeft].z),
Vertices[bottomRight].z), Vertices[center].z);
if (data.IsWater(x, y, maxHeight))
triangleType = Constants::TRIANGLE_TYPE_WATER;
}
Triangles.push_back(Triangle<uint8>(triangleType, topRight, topLeft, center));
Triangles.push_back(Triangle<uint8>(triangleType, topLeft, bottomLeft, center));
Triangles.push_back(Triangle<uint8>(triangleType, bottomLeft, bottomRight, center));
Triangles.push_back(Triangle<uint8>(triangleType, bottomRight, topRight, center));
}
}
}
void MapChunk::GenerateVertices( FILE* stream )
{
fseek(stream, Header.OffsetMCVT, SEEK_CUR);
Vertices.reserve(125);
for (int j = 0; j < 17; j++)
{
int values = j % 2 ? 8 : 9;
for (int i = 0; i < values; i++)
{
float tmp;
if (fread(&tmp, sizeof(float), 1, stream) != 1)
printf("MapChunk::GenerateVertices: Failed to read some data expected 1, read 0\n");
Vector3 vert(Header.Position.x - (j * (Constants::UnitSize * 0.5f)), Header.Position.y - (i * Constants::UnitSize), Header.Position.z + tmp);
if (values == 8)
vert.y -= Constants::UnitSize * 0.5f;
Vertices.push_back(vert);
}
}
// Restore stream position.
fseek(stream, Source->Offset, SEEK_SET);
}
bool MapChunk::HasHole( uint32 map, int x, int y )
{
return (map & 0x0000FFFF) & ((1 << x) << (y << 2));
}
-41
View File
@@ -1,41 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MAPCHUNK_H
#define MAPCHUNK_H
#include "Chunk.h"
#include "Constants.h"
#include "Utils.h"
#include <vector>
class ADT;
class MapChunk
{
public:
MapChunk(ADT* _adt, Chunk* chunk);
void GenerateTriangles();
void GenerateVertices(FILE* stream);
static bool HasHole(uint32 map, int x, int y);
ADT* Adt;
Chunk* Source;
MapChunkHeader Header;
std::vector<Vector3> Vertices;
std::vector<Triangle<uint8>> Triangles;
int32 Index;
};
#endif
-485
View File
@@ -1,485 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Cache.h"
#include "Constants.h"
#include "ContinentBuilder.h"
#include "DBC.h"
#include "MPQMgr.h"
#include "Model.h"
#include "WDT.h"
#include "DetourNavMesh.h"
#include "DetourNavMeshQuery.h"
#include "Recast.h"
#include <stdio.h>
#include <set>
MPQMgr* MPQHandler;
CacheClass* Cache;
void ExtractMMaps(std::set<uint32>& mapIds, uint32 threads)
{
DBC* dbc = MPQHandler->GetDBC("Map");
printf("Map.dbc contains %u rows.\n", dbc->Records.size());
for (std::vector<Record*>::iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr)
{
uint32 mapId = (*itr)->Values[0];
// Skip this map if a list of specific maps was provided and this one is not contained in it.
if (!mapIds.empty() && mapIds.find(mapId) == mapIds.end())
{
if (Constants::Debug)
printf("Map %u will not be built.\n", mapId);
continue;
}
std::string name = (*itr)->Get<std::string>(1);
WDT wdt("World\\maps\\" + name + "\\" + name + ".wdt");
if (!wdt.IsValid)
{
printf("Could not find WDT data for map %u (%s)\n", mapId, name.c_str());
continue;
}
printf("Building %s MapId %u\n", name.c_str(), mapId);
ContinentBuilder builder(name, mapId, &wdt, threads);
builder.Build();
}
}
void ExtractDBCs()
{
printf("Extracting DBCs\n");
// Create the file system structure
std::string baseDBCPath = "dbc/";
Utils::CreateDir(baseDBCPath);
std::set<std::string> DBCFiles;
const size_t extLen = strlen(".dbc");
// Populate list of DBC files
// We get the DBC names by going over the (guaranteed to exist) default locale files
// Then we look in other locale files in case that they are available.
for (std::vector<std::string>::iterator itr = MPQHandler->LocaleFiles[MPQHandler->BaseLocale]->Files.begin(); itr != MPQHandler->LocaleFiles[MPQHandler->BaseLocale]->Files.end(); ++itr)
if (itr->rfind(".dbc") == itr->length() - extLen) // Check if the extension is ".dbc"
DBCFiles.insert(*itr);
const size_t folderLen = strlen("DBFilesClient\\");
// Iterate over all available locales
for (std::set<uint32>::iterator itr = MPQHandler->AvailableLocales.begin(); itr != MPQHandler->AvailableLocales.end(); ++itr)
{
printf("Extracting DBCs for locale %s\n", MPQMgr::Languages[*itr]);
std::string path = baseDBCPath;
if (*itr != uint32(MPQHandler->BaseLocale))
{
path += std::string(MPQMgr::Languages[*itr]) + "/";
Utils::CreateDir(path);
}
std::string component = "component.wow-" + std::string(MPQMgr::Languages[*itr]) + ".txt";
// Extract the component file
Utils::SaveToDisk(MPQHandler->GetFileFrom(component, MPQHandler->LocaleFiles[*itr]), path + component);
// Extract the DBC files for the given locale
for (std::set<std::string>::iterator itr2 = DBCFiles.begin(); itr2 != DBCFiles.end(); ++itr2)
Utils::SaveToDisk(MPQHandler->GetFileFrom(*itr2, MPQHandler->LocaleFiles[*itr]), path + (itr2->c_str() + folderLen));
}
printf("DBC extraction finished!\n");
}
void ExtractGameobjectModels()
{
Constants::ToWoWCoords = true;
printf("Extracting GameObject models\n");
std::string baseBuildingsPath = "Buildings/";
std::string baseVmapsPath = "vmaps/";
Utils::CreateDir(baseVmapsPath);
Utils::CreateDir(baseBuildingsPath);
FILE* modelList = fopen((baseVmapsPath + "GameObjectModels.list").c_str(), "wb");
if (!modelList)
{
printf("Could not create file vmaps/GameObjectModels.list, please make sure that you have the write permissions in the folder\n");
return;
}
DBC* dbc = MPQHandler->GetDBC("GameObjectDisplayInfo");
for (std::vector<Record*>::iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr)
{
std::string path = (*itr)->Get<std::string>(1);
std::string fileName = Utils::GetPlainName(path.c_str());
std::string extension = Utils::GetExtension(fileName);
// Convert the extension to lowercase
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
if (extension == "mdx" || extension == "m2")
{
fileName = Utils::FixModelPath(fileName);
Model model(path);
if (model.IsBad)
continue;
FILE* output = fopen((baseBuildingsPath + fileName).c_str(), "wb");
if (!output)
{
printf("Could not create file %s, please check that you have write permissions\n", (baseBuildingsPath + fileName).c_str());
continue;
}
// Placeholder for 0 values
int Nop[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
fwrite(Constants::VMAPMagic, 8, 1, output);
uint32 numVerts = model.Header.CountBoundingVertices;
fwrite(&numVerts, sizeof(uint32), 1, output);
uint32 numGroups = 1;
fwrite(&numGroups, sizeof(uint32), 1, output);
fwrite(Nop, 4 * 3, 1, output); // rootwmoid, flags, groupid
fwrite(Nop, sizeof(float), 3 * 2, output);//bbox, only needed for WMO currently
fwrite(Nop, 4, 1, output);// liquidflags
fwrite("GRP ", 4, 1, output);
uint32 branches = 1;
uint32 wsize = sizeof(branches) + sizeof(uint32) * branches;
fwrite(&wsize, sizeof(uint32), 1, output);
fwrite(&branches, sizeof(branches), 1, output);
uint32 numTris = model.Header.CountBoundingTriangles;
fwrite(&numTris, sizeof(uint32), 1, output);
fwrite("INDX", 4, 1, output);
wsize = sizeof(uint32) + sizeof(unsigned short) * numTris;
fwrite(&wsize, sizeof(int), 1, output);
fwrite(&numTris, sizeof(uint32), 1, output);
uint16* indices = new uint16[numTris];
if (numTris > 0)
{
uint32 i = 0;
for (std::vector<Triangle<uint16>>::iterator itr2 = model.Triangles.begin(); itr2 != model.Triangles.end(); ++itr2, ++i)
{
indices[i * 3 + 0] = itr2->V0;
indices[i * 3 + 1] = itr2->V1;
indices[i * 3 + 2] = itr2->V2;
}
fwrite(indices, sizeof(uint16), numTris, output);
}
fwrite("VERT", 4, 1, output);
wsize = sizeof(int) + sizeof(float) * 3 * numVerts;
fwrite(&wsize, sizeof(int), 1, output);
fwrite(&numVerts, sizeof(int), 1, output);
float* vertices = new float[numVerts * 3];
if (numVerts > 0)
{
uint32 i = 0;
for (std::vector<Vector3>::iterator itr2 = model.Vertices.begin(); itr2 != model.Vertices.end(); ++itr2, ++i)
{
vertices[i * 3 + 0] = itr2->x;
vertices[i * 3 + 1] = itr2->y;
vertices[i * 3 + 2] = itr2->z;
}
fwrite(vertices, sizeof(float), numVerts * 3, output);
}
fclose(output);
delete[] indices;
delete[] vertices;
uint32 displayId = (*itr)->Values[0];
uint32 pathLength = fileName.size();
fwrite(&displayId, sizeof(uint32), 1, modelList);
fwrite(&pathLength, sizeof(uint32), 1, modelList);
fwrite(fileName.c_str(), sizeof(char), pathLength, modelList);
}
else if (extension == "wmo")
{
WorldModelRoot model(path);
FILE* output = fopen((baseBuildingsPath + fileName).c_str(), "wb");
if (!output)
{
printf("Could not create file %s, please check that you have write permissions\n", (baseBuildingsPath + fileName).c_str());
continue;
}
fwrite(Constants::VMAPMagic, 1, 8, output);
uint32 numVertices = 0;
fwrite(&numVertices, sizeof(uint32), 1, output); // will be filled later
fwrite(&model.Header.CountGroups, sizeof(uint32), 1, output);
fwrite(&model.Header.WmoId, sizeof(uint32), 1, output);
const char grp[] = { 'G', 'R', 'P', ' ' };
for (std::vector<WorldModelGroup>::iterator itr2 = model.Groups.begin(); itr2 != model.Groups.end(); ++itr2)
{
const WMOGroupHeader& header = itr2->Header;
fwrite(&header.Flags, sizeof(uint32), 1, output);
fwrite(&header.WmoId, sizeof(uint32), 1, output);
fwrite(&header.BoundingBox[0], sizeof(uint32), 1, output);
fwrite(&header.BoundingBox[1], sizeof(uint32), 1, output);
uint32 LiquidFlags = itr2->HasLiquidData ? 1 : 0;
fwrite(&LiquidFlags, sizeof(uint32), 1, output);
fwrite(grp, sizeof(char), sizeof(grp), output);
uint32 k = 0;
uint32 mobaBatch = itr2->MOBALength / 12;
uint32* MobaEx = new uint32[mobaBatch * 4];
for (uint32 i = 8; i < itr2->MOBALength; i += 12)
MobaEx[k++] = itr2->MOBA[i];
int mobaSizeGrp = mobaBatch * 4 + 4;
fwrite(&mobaSizeGrp, 4, 1, output);
fwrite(&mobaBatch, 4, 1, output);
fwrite(MobaEx, 4, k, output);
delete[] MobaEx;
//@TODO: Finish this.
}
fclose(output);
}
}
fclose(modelList);
printf("GameObject models extraction finished!");
Constants::ToWoWCoords = false;
}
bool HandleArgs(int argc, char** argv, uint32& threads, std::set<uint32>& mapList, bool& debugOutput, uint32& extractFlags)
{
char* param = nullptr;
extractFlags = 0;
for (int i = 1; i < argc; ++i)
{
if (strcmp(argv[i], "--threads") == 0)
{
param = argv[++i];
if (!param)
return false;
threads = atoi(param);
printf("Using %u threads\n", threads);
}
else if (strcmp(argv[i], "--maps") == 0)
{
param = argv[++i];
if (!param)
return false;
char* copy = strdup(param);
char* token = strtok(copy, ",");
while (token)
{
mapList.insert(atoi(token));
token = strtok(nullptr, ",");
}
free(copy);
printf("Extracting only provided list of maps (%u).\n", uint32(mapList.size()));
}
else if (strcmp(argv[i], "--debug") == 0)
{
param = argv[++i];
if (!param)
return false;
debugOutput = atoi(param);
if (debugOutput)
printf("Output will contain debug information (.obj files)\n");
}
else if (strcmp(argv[i], "--extract") == 0)
{
param = argv[++i];
if (!param)
return false;
extractFlags = atoi(param);
if (!(extractFlags & Constants::EXTRACT_FLAG_ALLOWED)) // Tried to use an invalid flag
return false;
printf("Detected flags: \n");
printf("* Extract DBCs: %s\n", (extractFlags & Constants::EXTRACT_FLAG_DBC) ? "Yes" : "No");
printf("* Extract Maps: %s\n", (extractFlags & Constants::EXTRACT_FLAG_MAPS) ? "Yes" : "No");
printf("* Extract VMaps: %s\n", (extractFlags & Constants::EXTRACT_FLAG_VMAPS) ? "Yes" : "No");
printf("* Extract GameObject Models: %s\n", (extractFlags & Constants::EXTRACT_FLAG_GOB_MODELS) ? "Yes" : "No");
printf("* Extract MMaps: %s\n", (extractFlags & Constants::EXTRACT_FLAG_MMAPS) ? "Yes" : "No");
}
}
return true;
}
void PrintUsage()
{
printf("MeshExtractor help.\n");
printf("* Use \"--threads <number>\" to specify <number> threads, default to 4 (Only available when extracting MMaps)\n");
printf("* Use \"--maps a,b,c,d,e\" to extract only the maps specified (Do not use spaces)\n");
printf("* Use \"--debug 1\" to generate debug information of the tiles (Only available when extracting MMaps)\n");
printf("* Use \"--extract X\" to extract the data specified by the flag X (Note: You can combine the flags with the bitwise OR operator |). Available flags are: \n");
{
printf("- %u to extract DBCs\n", Constants::EXTRACT_FLAG_DBC);
printf("- %u to extract Maps (Not yet implemented)\n", Constants::EXTRACT_FLAG_MAPS);
printf("- %u to extract VMaps (Not yet implemented)\n", Constants::EXTRACT_FLAG_VMAPS);
printf("- %u to extract GameObject models (Not yet finished, you need to run VMapAssembler on the extracted files)\n", Constants::EXTRACT_FLAG_GOB_MODELS);
printf("- %u to extract MMaps (Not yet finished)\n", Constants::EXTRACT_FLAG_MMAPS);
}
}
void LoadTile(dtNavMesh*& navMesh, const char* tile)
{
FILE* f = fopen(tile, "rb");
if (!f)
return;
MmapTileHeader header;
if (fread(&header, sizeof(MmapTileHeader), 1, f) != 1)
return;
uint8* nav = new uint8[header.size];
if (fread(nav, header.size, 1, f) != 1)
return;
navMesh->addTile(nav, header.size, DT_TILE_FREE_DATA, 0, nullptr);
fclose(f);
}
int main(int argc, char* argv[])
{
_setmaxstdio(2048);
uint32 threads = 4, extractFlags = 0;
std::set<uint32> mapIds;
if (!HandleArgs(argc, argv, threads, mapIds, Constants::Debug, extractFlags))
{
PrintUsage();
return -1;
}
if (extractFlags == 0)
{
printf("You must provide valid extract flags.\n");
PrintUsage();
return -1;
}
Cache = new CacheClass();
MPQHandler = new MPQMgr();
MPQHandler->Initialize();
if (extractFlags & Constants::EXTRACT_FLAG_DBC)
ExtractDBCs();
if (extractFlags & Constants::EXTRACT_FLAG_MMAPS)
ExtractMMaps(mapIds, threads);
if (extractFlags & Constants::EXTRACT_FLAG_GOB_MODELS)
ExtractGameobjectModels();
if (extractFlags & Constants::EXTRACT_FLAG_TEST)
{
float start[] = { 16226.200195f, 16257.000000f, 13.202200f };
float end[] = { 16245.725586f, 16382.465820f, 47.384956f };
//
float m_spos[3];
m_spos[0] = -start[1];
m_spos[1] = start[2];
m_spos[2] = -start[0];
//
float m_epos[3];
m_epos[0] = -end[1];
m_epos[1] = end[2];
m_epos[2] = -end[0];
//
dtQueryFilterExt m_filter;
m_filter.setIncludeFlags(Constants::POLY_AREA_ROAD | Constants::POLY_AREA_TERRAIN);
m_filter.setExcludeFlags(Constants::POLY_AREA_WATER);
//
float m_polyPickExt[3];
m_polyPickExt[0] = 2.5f;
m_polyPickExt[1] = 2.5f;
m_polyPickExt[2] = 2.5f;
//
dtPolyRef m_startRef;
dtPolyRef m_endRef;
FILE* mmap = fopen("mmaps/001.mmap", "rb");
dtNavMeshParams params;
int count = fread(&params, sizeof(dtNavMeshParams), 1, mmap);
fclose(mmap);
if (count != 1)
{
printf("main: Error reading from .mmap\n");
return 0;
}
dtNavMesh* navMesh = new dtNavMesh();
dtNavMeshQuery* navMeshQuery = new dtNavMeshQuery();
navMesh->init(&params);
for (int i = 0; i <= 32; ++i)
{
for (int j = 0; j <= 32; ++j)
{
char buff[100];
sprintf(buff, "mmaps/001%02i%02i.mmtile", i, j);
LoadTile(navMesh, buff);
}
}
navMeshQuery->init(navMesh, 2048);
float nearestPt[3];
navMeshQuery->findNearestPoly(m_spos, m_polyPickExt, &m_filter, &m_startRef, nearestPt);
navMeshQuery->findNearestPoly(m_epos, m_polyPickExt, &m_filter, &m_endRef, nearestPt);
if ( !m_startRef || !m_endRef )
{
std::cerr << "Could not find any nearby poly's (" << m_startRef << "," << m_endRef << ")" << std::endl;
return 0;
}
int hops;
dtPolyRef* hopBuffer = new dtPolyRef[8192];
dtStatus status = navMeshQuery->findPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter, hopBuffer, &hops, 8192);
int resultHopCount;
float* straightPath = new float[2048 * 3];
unsigned char* pathFlags = new unsigned char[2048];
dtPolyRef* pathRefs = new dtPolyRef[2048];
status = navMeshQuery->findStraightPath(m_spos, m_epos, hopBuffer, hops, straightPath, pathFlags, pathRefs, &resultHopCount, 2048);
std::vector<Vector3> FinalPath;
FinalPath.reserve(resultHopCount);
for (int32 i = 0; i < resultHopCount; ++i)
{
Vector3 finalV = Utils::ToWoWCoords(Vector3(straightPath[i * 3 + 0], straightPath[i * 3 + 1], straightPath[i * 3 + 2]));
FinalPath.push_back(finalV);
printf("Point %f %f %f\n", finalV.x, finalV.y, finalV.z);
}
}
return 0;
}
-83
View File
@@ -1,83 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Model.h"
#include "MPQMgr.h"
#include "Utils.h"
Model::Model( std::string path ) : IsCollidable(false), IsBad(false)
{
Stream = MPQHandler->GetFile(Utils::FixModelPath(path));
if (!Stream)
{
IsBad = true;
return;
}
Header.Read(Stream);
if (Header.OffsetBoundingNormals > 0 && Header.OffsetBoundingVertices > 0 &&
Header.OffsetBoundingTriangles > 0 && Header.BoundingRadius > 0.0f)
{
IsCollidable = true;
ReadVertices();
ReadBoundingNormals();
ReadBoundingTriangles();
}
}
Model::~Model()
{
if (Stream)
fclose(Stream);
}
void Model::ReadVertices()
{
fseek(Stream, Header.OffsetBoundingVertices, SEEK_SET);
Vertices.reserve(Header.CountBoundingVertices);
for (uint32 i = 0; i < Header.CountBoundingVertices; ++i)
{
Vertices.push_back(Vector3::Read(Stream));
if (Constants::ToWoWCoords)
Vertices[i] = Utils::ToWoWCoords(Vertices[i]);
}
}
void Model::ReadBoundingTriangles()
{
fseek(Stream, Header.OffsetBoundingTriangles, SEEK_SET);
Triangles.reserve(Header.CountBoundingTriangles / 3);
for (uint32 i = 0; i < Header.CountBoundingTriangles / 3; i++)
{
Triangle<uint16> tri;
tri.Type = Constants::TRIANGLE_TYPE_DOODAD;
int count = 0;
count += fread(&tri.V0, sizeof(uint16), 1, Stream);
count += fread(&tri.V1, sizeof(uint16), 1, Stream);
count += fread(&tri.V2, sizeof(uint16), 1, Stream);
if (count != 3)
printf("Model::ReadBoundingTriangles: Error reading data, expected 3, read %d\n", count);
Triangles.push_back(tri);
}
}
void Model::ReadBoundingNormals()
{
fseek(Stream, Header.OffsetBoundingNormals, SEEK_SET);
Normals.reserve(Header.CountBoundingNormals);
for (uint32 i = 0; i < Header.CountBoundingNormals; i++)
Normals.push_back(Vector3::Read(Stream));
}
-40
View File
@@ -1,40 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MODEL_H
#define MODEL_H
#include "Utils.h"
#include <vector>
class Model
{
public:
Model(std::string path);
~Model();
void ReadVertices();
void ReadBoundingTriangles();
void ReadBoundingNormals();
ModelHeader Header;
std::vector<Vector3> Vertices;
std::vector<Vector3> Normals;
std::vector<Triangle<uint16>> Triangles;
bool IsCollidable;
FILE* Stream;
bool IsBad;
};
#endif
@@ -1,24 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ObjectDataHandler.h"
#include "ADT.h"
void ObjectDataHandler::ProcessMapChunk( MapChunk* chunk )
{
ProcessInternal(chunk);
}
@@ -1,32 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ODATA_HNDL_H
#define ODATA_HNDL_H
#include "ADT.h"
#include "MapChunk.h"
class ObjectDataHandler
{
public:
ObjectDataHandler(ADT* _adt) : Source(_adt) {}
void ProcessMapChunk(MapChunk* chunk);
virtual void ProcessInternal(MapChunk* data) = 0;
ADT* Source;
};
#endif
-412
View File
@@ -1,412 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TileBuilder.h"
#include "ADT.h"
#include "Cache.h"
#include "Constants.h"
#include "ContinentBuilder.h"
#include "DetourNavMeshBuilder.h"
#include "Geometry.h"
#include "Recast.h"
#include "RecastAlloc.h"
#include "Utils.h"
#include "WDT.h"
#include "WorldModelRoot.h"
TileBuilder::TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, int y, uint32 mapId) :
World(world), X(x), Y(y), MapId(mapId), _Geometry(nullptr), DataSize(0), cBuilder(_cBuilder)
{
// Config for normal maps
memset(&Config, 0, sizeof(rcConfig));
Config.cs = Constants::TileSize / 1800.0f; // TileSize / voxelSize
Config.ch = 0.3f;
Config.minRegionArea = 36;
Config.mergeRegionArea = 144;
Config.walkableSlopeAngle = 50.0f;
Config.detailSampleDist = 3.0f;
Config.detailSampleMaxError = 1.25f;
Config.walkableClimb = 1.0f / Config.ch;
Config.walkableHeight = 2.1 / Config.ch;
Config.walkableRadius = 0.6f / Config.cs;
Config.maxEdgeLen = Config.walkableRadius * 8;
Config.borderSize = Config.walkableRadius + 8;
Config.tileSize = 1800;
Config.maxSimplificationError = 1.3f;
Config.maxVertsPerPoly = 6;
// Config for instances
memset(&InstanceConfig, 0, sizeof(rcConfig));
InstanceConfig.cs = 0.2f;
InstanceConfig.ch = 0.3f;
InstanceConfig.minRegionArea = 25;
InstanceConfig.mergeRegionArea = 100;
InstanceConfig.walkableSlopeAngle = 50.0f;
InstanceConfig.detailSampleDist = 3.0f;
InstanceConfig.detailSampleMaxError = 1.5f;
InstanceConfig.walkableClimb = 1.0f / InstanceConfig.ch;
InstanceConfig.walkableHeight = 2.1f / InstanceConfig.ch;
InstanceConfig.walkableRadius = 0.6f / InstanceConfig.cs;
InstanceConfig.maxEdgeLen = 8 * InstanceConfig.walkableRadius;
InstanceConfig.maxVertsPerPoly = 6;
InstanceConfig.maxSimplificationError = 1.25f;
InstanceConfig.borderSize = 0;
Context = new rcContext;
}
void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax, dtNavMeshParams& /*navMeshParams*/ )
{
bmin = new float[3];
bmax = new float[3];
bmin[0] = Constants::Origin[0] /*navMeshParams.orig[0]*/ + (Constants::TileSize * X);
bmin[2] = Constants::Origin[2] /*navMeshParams.orig[2]*/ + (Constants::TileSize * Y);
bmax[0] = Constants::Origin[0] /*navMeshParams.orig[0]*/ + (Constants::TileSize * (X + 1));
bmax[2] = Constants::Origin[2] /*navMeshParams.orig[2]*/ + (Constants::TileSize * (Y + 1));
}
void TileBuilder::AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def)
{
_Geometry = new Geometry();
_Geometry->Transform = true;
WorldModelHandler::InsertModelGeometry(_Geometry->Vertices, _Geometry->Triangles, def, root, false);
OutputDebugVertices();
}
uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams )
{
float* bmin = nullptr, *bmax = nullptr;
_Geometry->CalculateBoundingBox(bmin, bmax);
rcVcopy(InstanceConfig.bmax, bmax);
rcVcopy(InstanceConfig.bmin, bmin);
uint32 numVerts = _Geometry->Vertices.size();
uint32 numTris = _Geometry->Triangles.size();
float* vertices;
int* triangles;
uint8* areas;
_Geometry->GetRawData(vertices, triangles, areas);
// this sets the dimensions of the heightfield
rcCalcGridSize(InstanceConfig.bmin, InstanceConfig.bmax, InstanceConfig.cs, &InstanceConfig.width, &InstanceConfig.height);
rcHeightfield* hf = rcAllocHeightfield();
rcCreateHeightfield(Context, *hf, InstanceConfig.width, InstanceConfig.height, InstanceConfig.bmin, InstanceConfig.bmax, InstanceConfig.cs, InstanceConfig.ch);
rcClearUnwalkableTriangles(Context, InstanceConfig.walkableSlopeAngle, vertices, numVerts, triangles, numTris, areas);
rcRasterizeTriangles(Context, vertices, numVerts, triangles, areas, numTris, *hf, InstanceConfig.walkableClimb);
rcFilterLowHangingWalkableObstacles(Context, InstanceConfig.walkableClimb, *hf);
rcFilterLedgeSpans(Context, InstanceConfig.walkableHeight, InstanceConfig.walkableClimb, *hf);
rcFilterWalkableLowHeightSpans(Context, InstanceConfig.walkableHeight, *hf);
rcCompactHeightfield* chf = rcAllocCompactHeightfield();
rcBuildCompactHeightfield(Context, InstanceConfig.walkableHeight, InstanceConfig.walkableClimb, *hf, *chf);
rcErodeWalkableArea(Context, InstanceConfig.walkableRadius, *chf);
rcBuildDistanceField(Context, *chf);
rcBuildRegions(Context, *chf, InstanceConfig.borderSize, InstanceConfig.minRegionArea, InstanceConfig.minRegionArea);
rcContourSet* contours = rcAllocContourSet();
rcBuildContours(Context, *chf, InstanceConfig.maxSimplificationError, InstanceConfig.maxEdgeLen, *contours);
rcPolyMesh* pmesh = rcAllocPolyMesh();
rcBuildPolyMesh(Context, *contours, InstanceConfig.maxVertsPerPoly, *pmesh);
rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail();
rcBuildPolyMeshDetail(Context, *pmesh, *chf, InstanceConfig.detailSampleDist, InstanceConfig.detailSampleMaxError, *dmesh);
// Set flags according to area types (e.g. Swim for Water)
for (int i = 0; i < pmesh->npolys; i++)
{
if (pmesh->areas[i] == Constants::POLY_AREA_ROAD || pmesh->areas[i] == Constants::POLY_AREA_TERRAIN)
pmesh->flags[i] = Constants::POLY_FLAG_WALK;
else if (pmesh->areas[i] == Constants::POLY_AREA_WATER)
pmesh->flags[i] = Constants::POLY_FLAG_SWIM;
}
dtNavMeshCreateParams params;
memset(&params, 0, sizeof(params));
// PolyMesh data
params.verts = pmesh->verts;
params.vertCount = pmesh->nverts;
params.polys = pmesh->polys;
params.polyAreas = pmesh->areas;
params.polyFlags = pmesh->flags;
params.polyCount = pmesh->npolys;
params.nvp = pmesh->nvp;
// PolyMeshDetail data
params.detailMeshes = dmesh->meshes;
params.detailVerts = dmesh->verts;
params.detailVertsCount = dmesh->nverts;
params.detailTris = dmesh->tris;
params.detailTriCount = dmesh->ntris;
rcVcopy(params.bmin, pmesh->bmin);
rcVcopy(params.bmax, pmesh->bmax);
// General settings
params.ch = InstanceConfig.ch;
params.cs = InstanceConfig.cs;
params.walkableClimb = InstanceConfig.walkableClimb * InstanceConfig.ch;
params.walkableHeight = InstanceConfig.walkableHeight * InstanceConfig.ch;
params.walkableRadius = InstanceConfig.walkableRadius * InstanceConfig.cs;
params.tileX = X;
params.tileY = Y;
params.tileLayer = 0;
params.buildBvTree = true;
rcVcopy(params.bmax, bmax);
rcVcopy(params.bmin, bmin);
// Offmesh-connection settings
params.offMeshConCount = 0; // none for now
rcFreeHeightField(hf);
rcFreeCompactHeightfield(chf);
rcFreeContourSet(contours);
delete vertices;
delete triangles;
delete areas;
delete bmin;
delete bmax;
if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == params.polyCount)
{
// we have flat tiles with no actual geometry - don't build those, its useless
// keep in mind that we do output those into debug info
// drop tiles with only exact count - some tiles may have geometry while having less tiles
printf("No polygons to build on tile, skipping.\n");
rcFreePolyMesh(pmesh);
rcFreePolyMeshDetail(dmesh);
return nullptr;
}
int navDataSize;
uint8* navData;
printf("Creating the navmesh with %i vertices, %i polys, %i triangles!\n", params.vertCount, params.polyCount, params.detailTriCount);
bool result = dtCreateNavMeshData(&params, &navData, &navDataSize);
rcFreePolyMesh(pmesh);
rcFreePolyMeshDetail(dmesh);
if (result)
{
printf("NavMesh created, size %i!\n", navDataSize);
DataSize = navDataSize;
return navData;
}
return nullptr;
}
uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
{
_Geometry = new Geometry();
_Geometry->Transform = true;
ADT* adt = new ADT(Utils::GetAdtPath(World, X, Y), X, Y);
adt->Read();
_Geometry->AddAdt(adt);
delete adt;
if (_Geometry->Vertices.empty() && _Geometry->Triangles.empty())
return nullptr;
float* bmin = nullptr, *bmax = nullptr;
CalculateTileBounds(bmin, bmax, navMeshParams);
_Geometry->CalculateMinMaxHeight(bmin[1], bmax[1]);
// again, we load everything - wasteful but who cares
for (int ty = Y - 1; ty <= Y + 1; ty++)
{
for (int tx = X - 1; tx <= X + 1; tx++)
{
// don't load main tile again
if (tx == X && ty == Y)
continue;
ADT* _adt = new ADT(Utils::GetAdtPath(World, tx, ty), tx, ty);
// If this condition is met, it means that this WDT does not contain the ADT
if (!_adt->Data->Stream)
{
delete _adt;
continue;
}
_adt->Read();
_Geometry->AddAdt(_adt);
delete _adt;
}
}
OutputDebugVertices();
uint32 numVerts = _Geometry->Vertices.size();
uint32 numTris = _Geometry->Triangles.size();
float* vertices;
int* triangles;
uint8* areas;
_Geometry->GetRawData(vertices, triangles, areas);
_Geometry->Vertices.clear();
_Geometry->Triangles.clear();
// add border
bmin[0] -= Config.borderSize * Config.cs;
bmin[2] -= Config.borderSize * Config.cs;
bmax[0] += Config.borderSize * Config.cs;
bmax[2] += Config.borderSize * Config.cs;
rcHeightfield* hf = rcAllocHeightfield();
int width = Config.tileSize + (Config.borderSize * 2);
rcCreateHeightfield(Context, *hf, width, width, bmin, bmax, Config.cs, Config.ch);
rcClearUnwalkableTriangles(Context, Config.walkableSlopeAngle, vertices, numVerts, triangles, numTris, areas);
rcRasterizeTriangles(Context, vertices, numVerts, triangles, areas, numTris, *hf, Config.walkableClimb);
rcFilterLowHangingWalkableObstacles(Context, Config.walkableClimb, *hf);
rcFilterLedgeSpans(Context, Config.walkableHeight, Config.walkableClimb, *hf);
rcFilterWalkableLowHeightSpans(Context, Config.walkableHeight, *hf);
rcCompactHeightfield* chf = rcAllocCompactHeightfield();
rcBuildCompactHeightfield(Context, Config.walkableHeight, Config.walkableClimb, *hf, *chf);
rcErodeWalkableArea(Context, Config.walkableRadius, *chf);
rcBuildDistanceField(Context, *chf);
rcBuildRegions(Context, *chf, Config.borderSize, Config.minRegionArea, Config.mergeRegionArea);
rcContourSet* contours = rcAllocContourSet();
rcBuildContours(Context, *chf, Config.maxSimplificationError, Config.maxEdgeLen, *contours);
rcPolyMesh* pmesh = rcAllocPolyMesh();
rcBuildPolyMesh(Context, *contours, Config.maxVertsPerPoly, *pmesh);
rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail();
rcBuildPolyMeshDetail(Context, *pmesh, *chf, Config.detailSampleDist, Config.detailSampleMaxError, *dmesh);
// Set flags according to area types (e.g. Swim for Water)
for (int i = 0; i < pmesh->npolys; i++)
{
if (pmesh->areas[i] == Constants::POLY_AREA_ROAD || pmesh->areas[i] == Constants::POLY_AREA_TERRAIN)
pmesh->flags[i] = Constants::POLY_FLAG_WALK;
else if (pmesh->areas[i] == Constants::POLY_AREA_WATER)
pmesh->flags[i] = Constants::POLY_FLAG_SWIM;
}
dtNavMeshCreateParams params;
memset(&params, 0, sizeof(params));
// PolyMesh data
params.verts = pmesh->verts;
params.vertCount = pmesh->nverts;
params.polys = pmesh->polys;
params.polyAreas = pmesh->areas;
params.polyFlags = pmesh->flags;
params.polyCount = pmesh->npolys;
params.nvp = pmesh->nvp;
// PolyMeshDetail data
params.detailMeshes = dmesh->meshes;
params.detailVerts = dmesh->verts;
params.detailVertsCount = dmesh->nverts;
params.detailTris = dmesh->tris;
params.detailTriCount = dmesh->ntris;
// General settings
params.ch = Config.ch;
params.cs = Config.cs;
params.walkableClimb = Config.walkableClimb * Config.ch;
params.walkableHeight = Config.walkableHeight * Config.ch;
params.walkableRadius = Config.walkableRadius * Config.cs;
params.tileX = X;
params.tileY = Y;
params.tileLayer = 0;
params.buildBvTree = true;
// Recalculate the bounds with the added geometry
float* bmin2 = nullptr, *bmax2 = nullptr;
CalculateTileBounds(bmin2, bmax2, navMeshParams);
bmin2[1] = bmin[1];
bmax2[1] = bmax[1];
rcVcopy(params.bmax, bmax2);
rcVcopy(params.bmin, bmin2);
// Offmesh-connection settings
params.offMeshConCount = 0; // none for now
rcFreeHeightField(hf);
rcFreeCompactHeightfield(chf);
rcFreeContourSet(contours);
delete vertices;
delete triangles;
delete areas;
delete bmin;
delete bmax;
if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == params.polyCount)
{
// we have flat tiles with no actual geometry - don't build those, its useless
// keep in mind that we do output those into debug info
// drop tiles with only exact count - some tiles may have geometry while having less tiles
printf("[%02i, %02i] No polygons to build on tile, skipping.\n", X, Y);
rcFreePolyMesh(pmesh);
rcFreePolyMeshDetail(dmesh);
return nullptr;
}
int navDataSize;
uint8* navData;
printf("[%02i, %02i] Creating the navmesh with %i vertices, %i polys, %i triangles!\n", X, Y, params.vertCount, params.polyCount, params.detailTriCount);
bool result = dtCreateNavMeshData(&params, &navData, &navDataSize);
rcFreePolyMesh(pmesh);
rcFreePolyMeshDetail(dmesh);
if (result)
{
printf("[%02i, %02i] NavMesh created, size %i!\n", X, Y, navDataSize);
DataSize = navDataSize;
return navData;
}
return nullptr;
}
void TileBuilder::OutputDebugVertices()
{
if (Constants::Debug)
{
char buff[100];
sprintf(buff, "mmaps/%s_%02u%02u.obj", World.c_str(), Y, X);
FILE* debug = fopen(buff, "wb");
for (uint32 i = 0; i < _Geometry->Vertices.size(); ++i)
{
const Vector3& vector = _Geometry->Vertices[i];
fprintf(debug, "v %f %f %f\n", vector.x, vector.y, vector.z);
}
for (uint32 i = 0; i < _Geometry->Triangles.size(); ++i)
{
const Triangle<uint32>& triangle = _Geometry->Triangles[i];
fprintf(debug, "f %u %u %u\n", triangle.V0 + 1, triangle.V1 + 1, triangle.V2 + 1);
}
fclose(debug);
}
}
TileBuilder::~TileBuilder()
{
delete Context;
delete _Geometry;
}
-51
View File
@@ -1,51 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TILE_BUILD_H
#define TILE_BUILD_H
#include "Recast.h"
#include <string>
#include "Geometry.h"
#include "WorldModelRoot.h"
class ContinentBuilder;
class WDT;
class TileBuilder
{
public:
TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, int y, uint32 mapId);
~TileBuilder();
void CalculateTileBounds(float*& bmin, float*& bmax, dtNavMeshParams& navMeshParams);
uint8* BuildTiled(dtNavMeshParams& navMeshParams);
uint8* BuildInstance(dtNavMeshParams& navMeshParams);
void AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def);
void OutputDebugVertices();
std::string World;
int X;
int Y;
int MapId;
rcConfig Config;
rcConfig InstanceConfig;
rcContext* Context;
Geometry* _Geometry;
uint32 DataSize;
ContinentBuilder* cBuilder;
};
#endif
-563
View File
@@ -1,563 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Utils.h"
#include "Constants.h"
#include "G3D/Matrix4.h"
#include "G3D/Quat.h"
#include "WorldModelHandler.h"
#include <cstring>
#ifdef _WIN32
#include "direct.h"
#else
#include <sys/stat.h>
#include <unistd.h>
#endif
const float Constants::TileSize = 533.0f + (1 / 3.0f);
const float Constants::MaxXY = 32.0f * Constants::TileSize;
const float Constants::ChunkSize = Constants::TileSize / 16.0f;
const float Constants::UnitSize = Constants::ChunkSize / 8.0f;
const float Constants::Origin[] = { -Constants::MaxXY, 0.0f, -Constants::MaxXY };
const float Constants::PI = 3.1415926f;
const float Constants::MaxStandableHeight = 1.5f;
const char* Constants::VMAPMagic = "VMAP044";
bool Constants::ToWoWCoords = false;
bool Constants::Debug = false;
const float Constants::BaseUnitDim = 0.533333f;
const int Constants::VertexPerMap = (Constants::TileSize / Constants::BaseUnitDim) + 0.5f;
const int Constants::VertexPerTile = 40;
const int Constants::TilesPerMap = Constants::VertexPerMap / Constants::VertexPerTile;
void Utils::CreateDir( const std::string& Path )
{
#ifdef _WIN32
_mkdir( Path.c_str());
#else
mkdir( Path.c_str(), 0777 );
#endif
}
void Utils::Reverse(char word[])
{
int len = strlen(word);
for (int i = 0; i < len / 2; i++)
{
word[i] ^= word[len - i - 1];
word[len - i - 1] ^= word[i];
word[i] ^= word[len - i - 1];
}
}
std::string Utils::ReadString( FILE* file )
{
std::string ret;
while (true)
{
char b;
if (fread(&b, sizeof(char), 1, file) != 1 || b == 0)
break;
ret.push_back(b);
}
return ret;
}
uint32 Utils::Size( FILE* file )
{
// store the old position
uint32 offset = ftell(file);
// Get file size
fseek(file, 0, SEEK_END);
uint32 size = ftell(file);
// reset back to the old position
fseek(file, offset, SEEK_SET);
return size;
}
Vector3 Utils::ToRecast(const Vector3& val )
{
return Vector3(-val.y, val.z, -val.x);
}
std::string Utils::GetAdtPath(const std::string& world, int x, int y )
{
return "World\\Maps\\" + world + "\\" + world + "_" + Utils::ToString(x) + "_" + Utils::ToString(y) + ".adt";
}
std::string Utils::FixModelPath(const std::string& path )
{
return Utils::GetPathBase(path) + ".M2";
}
Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate)
{
// Sources of information:
/// http://www.pxr.dk/wowdev/wiki/index.php?title=ADT/v18&oldid=3715
// This function applies to both external doodads and WMOs
// Rotate our Doodad vertex
G3D::Matrix4 rot = G3D::Matrix3::fromEulerAnglesXYZ(Utils::ToRadians(def.Rotation.z), Utils::ToRadians(-def.Rotation.x), Utils::ToRadians(def.Rotation.y + 180));
Vector3 ret = Utils::VectorTransform(vec, rot);
// And finally scale and translate it to our origin
ret = ret * def.Scale();
if (translate)
ret = ret + Vector3(Constants::MaxXY - def.Position.z, Constants::MaxXY - def.Position.x, def.Position.y);
return ret;
}
Vector3 Utils::TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate )
{
G3D::Quat quat = G3D::Quat(-inst.QuatY, inst.QuatZ, -inst.QuatX, inst.QuatW);
Vector3 ret = Utils::VectorTransform(vec, G3D::Matrix4(quat.toRotationMatrix()));
ret = ret * (inst.Scale / 1024.0f);
if (translate)
ret = ret + Vector3(Constants::MaxXY - inst.Position.z, Constants::MaxXY - inst.Position.x, inst.Position.y);
return ret;
}
float Utils::ToRadians( float degrees )
{
return Constants::PI * degrees / 180.0f;
}
Vector3 Utils::VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal )
{
G3D::Vector3 ret(vec.x, vec.y, vec.z);
ret = matrix.homoMul(ret, normal ? 0 : 1);
return Vector3(ret.x, ret.y, ret.z);
}
std::string Utils::GetPathBase(const std::string& path )
{
size_t lastIndex = path.find_last_of(".");
if (lastIndex != std::string::npos)
return path.substr(0, lastIndex);
return path;
}
Vector3 Vector3::Read( FILE* file )
{
Vector3 ret;
if (fread(&ret, sizeof(Vector3), 1, file) != 1)
printf("Vector3::Read: Failed to read some data expected 1, read 0\n");
return ret;
}
Vector3 Utils::GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int x, int y, bool translate)
{
if (Utils::Distance(height, 0.0f) > 0.5f)
basePosition.z = 0.0f;
return Utils::TransformDoodadVertex(def, basePosition + Vector3(x * Constants::UnitSize, y * Constants::UnitSize, height), translate);
}
float Utils::Distance( float x, float y )
{
return std::sqrt(x * x + y * y);
}
std::string Utils::Replace( std::string str, const std::string& oldStr, const std::string& newStr )
{
size_t pos = 0;
while ((pos = str.find(oldStr, pos)) != std::string::npos)
{
str.replace(pos, oldStr.length(), newStr);
pos += newStr.length();
}
return str;
}
void Utils::SaveToDisk( FILE* stream, const std::string& path )
{
FILE* disk = fopen(path.c_str(), "wb");
if (!disk)
{
printf("SaveToDisk: Could not save file %s to disk, please verify that you have write permissions on that directory\n", path.c_str());
fclose(stream);
return;
}
uint32 size = Utils::Size(stream);
uint8* data = new uint8[size];
// Read the data to an array
size_t read = fread(data, size, 1, stream);
if (read != 1)
{
printf("SaveToDisk: Error reading from Stream while trying to save file %s to disk.\n", path.c_str());
fclose(disk);
fclose(stream);
return;
}
// And write it in the file
size_t wrote = fwrite(data, size, 1, disk);
if (wrote != 1)
{
printf("SaveToDisk: Error writing to the file while trying to save %s to disk.\n", path.c_str());
fclose(stream);
fclose(disk);
return;
}
// Close the filestream
fclose(disk);
fclose(stream);
// Free the used memory
delete[] data;
}
Vector3 Utils::ToWoWCoords(const Vector3& vec )
{
return Vector3(-vec.z, -vec.x, vec.y);
}
std::string Utils::GetExtension( std::string path )
{
std::string::size_type idx = path.rfind('.');
std::string extension = "";
if (idx != std::string::npos)
extension = path.substr(idx + 1);
return extension;
}
void MapChunkHeader::Read(FILE* stream)
{
int count = 0;
count += fread(&Flags, sizeof(uint32), 1, stream);
count += fread(&IndexX, sizeof(uint32), 1, stream);
count += fread(&IndexY, sizeof(uint32), 1, stream);
count += fread(&Layers, sizeof(uint32), 1, stream);
count += fread(&DoodadRefs, sizeof(uint32), 1, stream);
count += fread(&OffsetMCVT, sizeof(uint32), 1, stream);
count += fread(&OffsetMCNR, sizeof(uint32), 1, stream);
count += fread(&OffsetMCLY, sizeof(uint32), 1, stream);
count += fread(&OffsetMCRF, sizeof(uint32), 1, stream);
count += fread(&OffsetMCAL, sizeof(uint32), 1, stream);
count += fread(&SizeMCAL, sizeof(uint32), 1, stream);
count += fread(&OffsetMCSH, sizeof(uint32), 1, stream);
count += fread(&SizeMCSH, sizeof(uint32), 1, stream);
count += fread(&AreaId, sizeof(uint32), 1, stream);
count += fread(&MapObjectRefs, sizeof(uint32), 1, stream);
count += fread(&Holes, sizeof(uint32), 1, stream);
LowQualityTextureMap = new uint32[4];
count += fread(LowQualityTextureMap, sizeof(uint32), 4, stream);
count += fread(&PredTex, sizeof(uint32), 1, stream);
count += fread(&NumberEffectDoodad, sizeof(uint32), 1, stream);
count += fread(&OffsetMCSE, sizeof(uint32), 1, stream);
count += fread(&SoundEmitters, sizeof(uint32), 1, stream);
count += fread(&OffsetMCLQ, sizeof(uint32), 1, stream);
count += fread(&SizeMCLQ, sizeof(uint32), 1, stream);
Position = Vector3::Read(stream);
count += fread(&OffsetMCCV, sizeof(uint32), 1, stream);
if (count != 27)
printf("MapChunkHeader::Read: Failed to read some data expected 27, read %d\n", count);
}
void MHDR::Read(FILE* stream)
{
int count = 0;
count += fread(&Flags, sizeof(uint32), 1, stream);
count += fread(&OffsetMCIN, sizeof(uint32), 1, stream);
count += fread(&OffsetMTEX, sizeof(uint32), 1, stream);
count += fread(&OffsetMMDX, sizeof(uint32), 1, stream);
count += fread(&OffsetMMID, sizeof(uint32), 1, stream);
count += fread(&OffsetMWMO, sizeof(uint32), 1, stream);
count += fread(&OffsetMWID, sizeof(uint32), 1, stream);
count += fread(&OffsetMDDF, sizeof(uint32), 1, stream);
count += fread(&OffsetMODF, sizeof(uint32), 1, stream);
count += fread(&OffsetMFBO, sizeof(uint32), 1, stream);
count += fread(&OffsetMH2O, sizeof(uint32), 1, stream);
count += fread(&OffsetMTFX, sizeof(uint32), 1, stream);
if (count != 12)
printf("MHDR::Read: Failed to read some data expected 12, read %d\n", count);
}
void ModelHeader::Read(FILE* stream)
{
int count = 0;
count += fread(&Magic, sizeof(char), 4, stream);
Magic[4] = '\0'; // null-terminate it.
count += fread(&Version, sizeof(uint32), 1, stream);
count += fread(&LengthModelName, sizeof(uint32), 1, stream);
count += fread(&OffsetName, sizeof(uint32), 1, stream);
count += fread(&ModelFlags, sizeof(uint32), 1, stream);
count += fread(&CountGlobalSequences, sizeof(uint32), 1, stream);
count += fread(&OffsetGlobalSequences, sizeof(uint32), 1, stream);
count += fread(&CountAnimations, sizeof(uint32), 1, stream);
count += fread(&OffsetAnimations, sizeof(uint32), 1, stream);
count += fread(&CountAnimationLookup, sizeof(uint32), 1, stream);
count += fread(&OffsetAnimationLookup, sizeof(uint32), 1, stream);
count += fread(&CountBones, sizeof(uint32), 1, stream);
count += fread(&OffsetBones, sizeof(uint32), 1, stream);
count += fread(&CountKeyBoneLookup, sizeof(uint32), 1, stream);
count += fread(&OffsetKeyBoneLookup, sizeof(uint32), 1, stream);
count += fread(&CountVertices, sizeof(uint32), 1, stream);
count += fread(&OffsetVertices, sizeof(uint32), 1, stream);
count += fread(&CountViews, sizeof(uint32), 1, stream);
count += fread(&CountColors, sizeof(uint32), 1, stream);
count += fread(&OffsetColors, sizeof(uint32), 1, stream);
count += fread(&CountTextures, sizeof(uint32), 1, stream);
count += fread(&OffsetTextures, sizeof(uint32), 1, stream);
count += fread(&CountTransparency, sizeof(uint32), 1, stream);
count += fread(&OffsetTransparency, sizeof(uint32), 1, stream);
count += fread(&CountUvAnimation, sizeof(uint32), 1, stream);
count += fread(&OffsetUvAnimation, sizeof(uint32), 1, stream);
count += fread(&CountTexReplace, sizeof(uint32), 1, stream);
count += fread(&OffsetTexReplace, sizeof(uint32), 1, stream);
count += fread(&CountRenderFlags, sizeof(uint32), 1, stream);
count += fread(&OffsetRenderFlags, sizeof(uint32), 1, stream);
count += fread(&CountBoneLookup, sizeof(uint32), 1, stream);
count += fread(&OffsetBoneLookup, sizeof(uint32), 1, stream);
count += fread(&CountTexLookup, sizeof(uint32), 1, stream);
count += fread(&OffsetTexLookup, sizeof(uint32), 1, stream);
count += fread(&CountTexUnits, sizeof(uint32), 1, stream);
count += fread(&OffsetTexUnits, sizeof(uint32), 1, stream);
count += fread(&CountTransLookup, sizeof(uint32), 1, stream);
count += fread(&OffsetTransLookup, sizeof(uint32), 1, stream);
count += fread(&CountUvAnimLookup, sizeof(uint32), 1, stream);
count += fread(&OffsetUvAnimLookup, sizeof(uint32), 1, stream);
VertexBox[0] = Vector3::Read(stream);
VertexBox[1] = Vector3::Read(stream);
count += fread(&VertexRadius, sizeof(float), 1, stream);
BoundingBox[0] = Vector3::Read(stream);
BoundingBox[1] = Vector3::Read(stream);
count += fread(&BoundingRadius, sizeof(float), 1, stream);
count += fread(&CountBoundingTriangles, sizeof(uint32), 1, stream);
count += fread(&OffsetBoundingTriangles, sizeof(uint32), 1, stream);
count += fread(&CountBoundingVertices, sizeof(uint32), 1, stream);
count += fread(&OffsetBoundingVertices, sizeof(uint32), 1, stream);
count += fread(&CountBoundingNormals, sizeof(uint32), 1, stream);
count += fread(&OffsetBoundingNormals, sizeof(uint32), 1, stream);
if (count != 51)
printf("ModelHeader::Read: Failed to read some data expected 51, read %d\n", count);
}
WorldModelHeader WorldModelHeader::Read(FILE* stream)
{
WorldModelHeader ret;
int count = 0;
count += fread(&ret.CountMaterials, sizeof(uint32), 1, stream);
count += fread(&ret.CountGroups, sizeof(uint32), 1, stream);
count += fread(&ret.CountPortals, sizeof(uint32), 1, stream);
count += fread(&ret.CountLights, sizeof(uint32), 1, stream);
count += fread(&ret.CountModels, sizeof(uint32), 1, stream);
count += fread(&ret.CountDoodads, sizeof(uint32), 1, stream);
count += fread(&ret.CountSets, sizeof(uint32), 1, stream);
count += fread(&ret.AmbientColorUnk, sizeof(uint32), 1, stream);
count += fread(&ret.WmoId, sizeof(uint32), 1, stream);
ret.BoundingBox[0] = Vector3::Read(stream);
ret.BoundingBox[1] = Vector3::Read(stream);
count += fread(&ret.LiquidTypeRelated, sizeof(uint32), 1, stream);
if (count != 10)
printf("WorldModelHeader::Read: Failed to read some data expected 10, read %d\n", count);
return ret;
}
DoodadInstance DoodadInstance::Read(FILE* stream)
{
DoodadInstance ret;
int count = 0;
count += fread(&ret.FileOffset, sizeof(uint32), 1, stream);
ret.Position = Vector3::Read(stream);
count += fread(&ret.QuatW, sizeof(float), 1, stream);
count += fread(&ret.QuatX, sizeof(float), 1, stream);
count += fread(&ret.QuatY, sizeof(float), 1, stream);
count += fread(&ret.QuatZ, sizeof(float), 1, stream);
count += fread(&ret.Scale, sizeof(float), 1, stream);
count += fread(&ret.LightColor, sizeof(uint32), 1, stream);
if (count != 7)
printf("DoodadInstance::Read: Failed to read some data expected 7, read %d\n", count);
return ret;
}
DoodadSet DoodadSet::Read(FILE* stream)
{
DoodadSet ret;
char name[21];
int count = 0;
count += fread(&name, sizeof(char), 20, stream);
name[20] = '\0';
ret.Name = name;
count += fread(&ret.FirstInstanceIndex, sizeof(uint32), 1, stream);
count += fread(&ret.CountInstances, sizeof(uint32), 1, stream);
count += fread(&ret.UnknownZero, sizeof(uint32), 1, stream);
if (count != 23)
printf("DoodadSet::Read: Failed to read some data expected 23, read %d\n", count);
return ret;
}
LiquidHeader LiquidHeader::Read(FILE* stream)
{
LiquidHeader ret;
int count = 0;
count += fread(&ret.CountXVertices, sizeof(uint32), 1, stream);
count += fread(&ret.CountYVertices, sizeof(uint32), 1, stream);
count += fread(&ret.Width, sizeof(uint32), 1, stream);
count += fread(&ret.Height, sizeof(uint32), 1, stream);
ret.BaseLocation = Vector3::Read(stream);
count += fread(&ret.MaterialId, sizeof(uint16), 1, stream);
if (count != 5)
printf("LiquidHeader::Read: Failed to read some data expected 5, read %d\n", count);
return ret;
}
LiquidData LiquidData::Read(FILE* stream, LiquidHeader& header)
{
LiquidData ret;
ret.HeightMap = new float*[header.CountXVertices];
for (uint32 i = 0; i < header.CountXVertices; ++i)
ret.HeightMap[i] = new float[header.CountYVertices];
ret.RenderFlags = new uint8*[header.Width];
for (uint32 i = 0; i < header.Width; ++i)
ret.RenderFlags[i] = new uint8[header.Height];
for (uint32 y = 0; y < header.CountYVertices; y++)
{
for (uint32 x = 0; x < header.CountXVertices; x++)
{
uint32 discard;
float tmp;
if (fread(&discard, sizeof(uint32), 1, stream) == 1 &&
fread(&tmp, sizeof(float), 1, stream) == 1)
{
ret.HeightMap[x][y] = tmp;
}
}
}
for (uint32 y = 0; y < header.Height; y++)
{
for (uint32 x = 0; x < header.Width; x++)
{
uint8 tmp = 0;
if (fread(&tmp, sizeof(uint8), 1, stream) == 1)
ret.RenderFlags[x][y] = tmp;
}
}
return ret;
}
H2ORenderMask H2ORenderMask::Read(FILE* stream)
{
H2ORenderMask ret;
int32 count;
if ((count = fread(&ret.Mask, sizeof(uint8), 8, stream)) != 8)
printf("H2OHeader::Read: Failed to read some data expected 8, read %d\n", count);
return ret;
}
bool MCNKLiquidData::IsWater(int x, int y, float height)
{
if (!Heights)
return false;
if (!Mask.ShouldRender(x, y))
return false;
float diff = Heights[x][y] - height;
if (diff > Constants::MaxStandableHeight)
return true;
return false;
}
H2OHeader H2OHeader::Read(FILE* stream)
{
H2OHeader ret;
int count = 0;
count += fread(&ret.OffsetInformation, sizeof(uint32), 1, stream);
count += fread(&ret.LayerCount, sizeof(uint32), 1, stream);
count += fread(&ret.OffsetRender, sizeof(uint32), 1, stream);
if (count != 3)
printf("H2OHeader::Read: Failed to read some data expected 3, read %d\n", count);
return ret;
}
H2OInformation H2OInformation::Read(FILE* stream)
{
H2OInformation ret;
int count = 0;
count += fread(&ret.LiquidType, sizeof(uint16), 1, stream);
count += fread(&ret.Flags, sizeof(uint16), 1, stream);
count += fread(&ret.HeightLevel1, sizeof(float), 1, stream);
count += fread(&ret.HeightLevel2, sizeof(float), 1, stream);
count += fread(&ret.OffsetX, sizeof(uint8), 1, stream);
count += fread(&ret.OffsetY, sizeof(uint8), 1, stream);
count += fread(&ret.Width, sizeof(uint8), 1, stream);
count += fread(&ret.Height, sizeof(uint8), 1, stream);
count += fread(&ret.OffsetMask2, sizeof(uint32), 1, stream);
count += fread(&ret.OffsetHeightmap, sizeof(uint32), 1, stream);
if (count != 10)
printf("H2OInformation::Read: Failed to read some data expected 10, read %d\n", count);
return ret;
}
char* Utils::GetPlainName(const char* FileName)
{
char* temp;
if ((temp = (char*)strrchr(FileName, '\\')) != nullptr)
FileName = temp + 1;
return (char*)FileName;
}
WMOGroupHeader WMOGroupHeader::Read( FILE* stream )
{
WMOGroupHeader ret;
int count = 0;
count += fread(&ret.OffsetGroupName, sizeof(uint32), 1, stream);
count += fread(&ret.OffsetDescriptiveName, sizeof(uint32), 1, stream);
count += fread(&ret.Flags, sizeof(uint32), 1, stream);
ret.BoundingBox[0] = Vector3::Read(stream);
ret.BoundingBox[1] = Vector3::Read(stream);
count += fread(&ret.OffsetPortals, sizeof(uint32), 1, stream);
count += fread(&ret.CountPortals, sizeof(uint32), 1, stream);
count += fread(&ret.CountBatches, sizeof(uint16), 4, stream);
count += fread(&ret.Fogs, sizeof(uint8), 4, stream);
count += fread(&ret.LiquidTypeRelated, sizeof(uint32), 1, stream);
count += fread(&ret.WmoId, sizeof(uint32), 1, stream);
if (count != 15)
printf("WMOGroupHeader::Read: Failed to read some data expected 15, read %d\n", count);
return ret;
}
-403
View File
@@ -1,403 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UTILS_H
#define UTILS_H
#include <cstdio>
#include <sstream>
#include <string>
#include "DetourNavMesh.h"
#include "G3D/Matrix4.h"
#include "Constants.h"
#include "Define.h"
struct WorldModelDefinition;
class DoodadDefinition;
class DoodadInstance;
#define ASSERT(assertion) { if (!(assertion)) {fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__, __FUNCTION__, #assertion, st.c_str()); *((volatile int*)nullptr) = 0; } }
struct Vector3
{
Vector3() {}
Vector3(float X, float Y, float Z) : x(X), y(Y), z(Z) {}
float x;
float y;
float z;
Vector3 operator +(Vector3 const& other) const
{
return Vector3(x + other.x, y + other.y, z + other.z);
}
Vector3 operator -(Vector3 const& other) const
{
return Vector3(x - other.x, y - other.y, z - other.z);
}
template<typename T>
Vector3 operator *(T s) const
{
return Vector3(x * s, y * s, z * s);
}
static Vector3 Read(FILE* file);
};
struct TilePos
{
TilePos(int x, int y) : X(x), Y(y) {}
int X;
int Y;
};
template<typename T>
struct Triangle
{
Triangle() {}
Triangle(Constants::TriangleType type, T v0, T v1, T v2) : V0(v0), V1(v1), V2(v2), Type(type) {}
T V0;
T V1;
T V2;
Constants::TriangleType Type;
};
class MapChunkHeader
{
public:
MapChunkHeader() {}
uint32 Flags;
uint32 IndexX;
uint32 IndexY;
uint32 Layers;
uint32 DoodadRefs;
uint32 OffsetMCVT;
uint32 OffsetMCNR;
uint32 OffsetMCLY;
uint32 OffsetMCRF;
uint32 OffsetMCAL;
uint32 SizeMCAL;
uint32 OffsetMCSH;
uint32 SizeMCSH;
uint32 AreaId;
uint32 MapObjectRefs;
uint32 Holes;
uint32* LowQualityTextureMap;
uint32 PredTex;
uint32 NumberEffectDoodad;
uint32 OffsetMCSE;
uint32 SoundEmitters;
uint32 OffsetMCLQ;
uint32 SizeMCLQ;
Vector3 Position;
uint32 OffsetMCCV;
void Read(FILE* stream);
};
class MHDR
{
public:
MHDR() {}
uint32 Flags;
uint32 OffsetMCIN;
uint32 OffsetMTEX;
uint32 OffsetMMDX;
uint32 OffsetMMID;
uint32 OffsetMWMO;
uint32 OffsetMWID;
uint32 OffsetMDDF;
uint32 OffsetMODF;
uint32 OffsetMFBO;
uint32 OffsetMH2O;
uint32 OffsetMTFX;
void Read(FILE* stream);
};
class ModelHeader
{
public:
char Magic[5];
uint32 Version;
uint32 LengthModelName;
uint32 OffsetName;
uint32 ModelFlags;
uint32 CountGlobalSequences;
uint32 OffsetGlobalSequences;
uint32 CountAnimations;
uint32 OffsetAnimations;
uint32 CountAnimationLookup;
uint32 OffsetAnimationLookup;
uint32 CountBones;
uint32 OffsetBones;
uint32 CountKeyBoneLookup;
uint32 OffsetKeyBoneLookup;
uint32 CountVertices;
uint32 OffsetVertices;
uint32 CountViews;
uint32 CountColors;
uint32 OffsetColors;
uint32 CountTextures;
uint32 OffsetTextures;
uint32 CountTransparency;
uint32 OffsetTransparency;
uint32 CountUvAnimation;
uint32 OffsetUvAnimation;
uint32 CountTexReplace;
uint32 OffsetTexReplace;
uint32 CountRenderFlags;
uint32 OffsetRenderFlags;
uint32 CountBoneLookup;
uint32 OffsetBoneLookup;
uint32 CountTexLookup;
uint32 OffsetTexLookup;
uint32 CountTexUnits;
uint32 OffsetTexUnits;
uint32 CountTransLookup;
uint32 OffsetTransLookup;
uint32 CountUvAnimLookup;
uint32 OffsetUvAnimLookup;
Vector3 VertexBox[2];
float VertexRadius;
Vector3 BoundingBox[2];
float BoundingRadius;
uint32 CountBoundingTriangles;
uint32 OffsetBoundingTriangles;
uint32 CountBoundingVertices;
uint32 OffsetBoundingVertices;
uint32 CountBoundingNormals;
uint32 OffsetBoundingNormals;
void Read(FILE* stream);
};
class WorldModelHeader
{
public:
WorldModelHeader() {}
uint32 CountMaterials;
uint32 CountGroups;
uint32 CountPortals;
uint32 CountLights;
uint32 CountModels;
uint32 CountDoodads;
uint32 CountSets;
uint32 AmbientColorUnk;
uint32 WmoId;
Vector3 BoundingBox[2];
uint32 LiquidTypeRelated;
static WorldModelHeader Read(FILE* stream);
};
class DoodadInstance
{
public:
DoodadInstance() {}
uint32 FileOffset;
std::string File;
Vector3 Position;
float QuatW;
float QuatX;
float QuatY;
float QuatZ;
float Scale;
uint32 LightColor;
static DoodadInstance Read(FILE* stream);
};
class DoodadSet
{
public:
DoodadSet() {}
std::string Name;
uint32 FirstInstanceIndex;
uint32 CountInstances;
uint32 UnknownZero;
static DoodadSet Read(FILE* stream);
};
class LiquidHeader
{
public:
LiquidHeader() {}
uint32 CountXVertices;
uint32 CountYVertices;
uint32 Width;
uint32 Height;
Vector3 BaseLocation;
uint16 MaterialId;
static LiquidHeader Read(FILE* stream);
};
class LiquidData
{
public:
LiquidData() {}
float** HeightMap;
uint8** RenderFlags;
bool ShouldRender(int x, int y)
{
return RenderFlags[x][y] != 0x0F;
}
static LiquidData Read(FILE* stream, LiquidHeader& header);
};
class H2ORenderMask
{
public:
H2ORenderMask() {}
uint8 Mask[8];
bool ShouldRender(int x, int y)
{
return (Mask[y] >> x & 1) != 0;
}
static H2ORenderMask Read(FILE* stream);
};
class MCNKLiquidData
{
public:
MCNKLiquidData() {}
MCNKLiquidData(float** heights, H2ORenderMask mask) : Heights(heights), Mask(mask) {}
float** Heights;
H2ORenderMask Mask;
bool IsWater(int x, int y, float height);
};
class H2OHeader
{
public:
H2OHeader() {}
uint32 OffsetInformation;
uint32 LayerCount;
uint32 OffsetRender;
static H2OHeader Read(FILE* stream);
};
class H2OInformation
{
public:
H2OInformation() {}
uint16 LiquidType;
uint16 Flags;
float HeightLevel1;
float HeightLevel2;
uint8 OffsetX;
uint8 OffsetY;
uint8 Width;
uint8 Height;
uint32 OffsetMask2;
uint32 OffsetHeightmap;
static H2OInformation Read(FILE* stream);
};
class WMOGroupHeader
{
public:
WMOGroupHeader() {}
uint32 OffsetGroupName;
uint32 OffsetDescriptiveName;
uint32 Flags;
Vector3 BoundingBox[2];
uint32 OffsetPortals;
uint32 CountPortals;
uint16 CountBatches[4];
uint8 Fogs[4];
uint32 LiquidTypeRelated;
uint32 WmoId;
static WMOGroupHeader Read(FILE* stream);
};
// Dummy class to act as an interface.
class IDefinition
{
public:
Vector3 Position;
Vector3 Rotation;
virtual float Scale() const { return 1.0f; };
};
struct MmapTileHeader
{
uint32 mmapMagic;
uint32 dtVersion;
uint32 mmapVersion;
uint32 size;
bool usesLiquids;
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
};
class Utils
{
public:
static void Reverse(char word[]);
static std::string ReadString(FILE* file);
static uint32 Size(FILE* file);
static Vector3 ToRecast(const Vector3& val );
static std::string GetAdtPath(const std::string& world, int x, int y);
static std::string FixModelPath(const std::string& path);
/// They say its better to declare template functions in the header files.
template <typename T>
static std::string ToString(T val)
{
std::stringstream ss;
ss << val;
return ss.str();
}
static float ToRadians(float degrees);
static std::string GetPathBase(const std::string& path);
static Vector3 GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int /*x*/, int /*y*/, bool translate = true);
static float Distance(float x, float y);
template<typename T>
static bool IsAllZero(T* arr, uint32 size)
{
for (uint32 i = 0; i < size; ++i)
if (arr[i])
return false;
return true;
}
static std::string Replace( std::string str, const std::string& oldStr, const std::string& newStr );
static void CreateDir( const std::string& Path );
static void SaveToDisk(FILE* stream, const std::string& path);
static Vector3 ToWoWCoords(const Vector3& vec );
static std::string GetExtension( std::string path );
static char* GetPlainName(const char* FileName);
static Vector3 TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate = true);
static Vector3 VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal = false );
static Vector3 TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate = true );
};
#endif
-77
View File
@@ -1,77 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WDT.h"
#include "Chunk.h"
#include "ChunkedData.h"
#include "Utils.h"
#include "WorldModelHandler.h"
WDT::WDT(std::string file) : IsGlobalModel(false), IsValid(false), Model(nullptr)
{
Data = new ChunkedData(file, 2);
ReadTileTable();
ReadGlobalModel();
}
void WDT::ReadGlobalModel()
{
Chunk* fileChunk = Data->GetChunkByName("MWMO");
Chunk* defChunk = Data->GetChunkByName("MODF");
if (!fileChunk || !defChunk)
return;
IsGlobalModel = true;
ModelDefinition = WorldModelDefinition::Read(defChunk->GetStream());
ModelFile = Utils::ReadString(fileChunk->GetStream());
Model = new WorldModelRoot(ModelFile);
}
void WDT::ReadTileTable()
{
Chunk* chunk = Data->GetChunkByName("MAIN");
if (!chunk)
return;
IsValid = true;
FILE* stream = chunk->GetStream();
for (int y = 0; y < 64; ++y)
{
for (int x = 0; x < 64; ++x)
{
const uint32 hasTileFlag = 0x1;
uint32 flags;
uint32 discard;
int count = 0;
count += fread(&flags, sizeof(uint32), 1, stream);
count += fread(&discard, sizeof(uint32), 1, stream);
if (count != 2)
printf("WDT::ReadTileTable: Failed to read some data expected 2, read %d\n", count);
if (flags & hasTileFlag)
TileTable.push_back(TilePos(x, y));
}
}
}
bool WDT::HasTile( int x, int y )
{
for (std::vector<TilePos>::iterator itr = TileTable.begin(); itr != TileTable.end(); ++itr)
if (itr->X == x && itr->Y == y)
return true;
return false;
}
-46
View File
@@ -1,46 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WDT_H
#define WDT_H
#include <string>
#include <vector>
#include "ChunkedData.h"
#include "WorldModelHandler.h"
#include "WorldModelRoot.h"
#include "Utils.h"
class WDT
{
public:
WDT(std::string file);
ChunkedData* Data;
std::vector<TilePos> TileTable;
bool IsGlobalModel;
bool IsValid;
std::string ModelFile;
WorldModelDefinition ModelDefinition;
WorldModelRoot* Model;
bool HasTile(int x, int y);
private:
void ReadGlobalModel();
void ReadTileTable();
};
#endif
@@ -1,160 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WorldModelGroup.h"
#include "Chunk.h"
#include "ChunkedData.h"
#include "Utils.h"
WorldModelGroup::WorldModelGroup( std::string path, int groupIndex ) : GroupIndex(groupIndex), MOBA(nullptr), IsBad(false), HasLiquidData(false)
{
Data = new ChunkedData(path);
if (!Data->Stream)
{
IsBad = true;
return;
}
Chunk* mainChunk = Data->GetChunkByName("MOGP");
int32 firstSub = mainChunk->FindSubChunkOffset("MOPY");
if (firstSub == -1)
return;
Name = Utils::GetPlainName(path.c_str());
FILE* stream = mainChunk->GetStream();
fseek(stream, firstSub, SEEK_SET);
SubData = new ChunkedData(stream, mainChunk->Length - firstSub);
ReadHeader();
ReadMaterials();
ReadTriangles();
ReadVertices();
ReadNormals();
ReadLiquid();
ReadBatches();
}
void WorldModelGroup::ReadNormals()
{
Chunk* chunk = SubData->GetChunkByName("MONR");
if (!chunk)
return;
uint32 normalCount = chunk->Length / 12;
ASSERT(normalCount == Vertices.size() && "normalCount is different than the Vertices count");
Normals.reserve(normalCount);
FILE* stream = chunk->GetStream();
for (uint32 i = 0; i < normalCount; i++)
Normals.push_back(Vector3::Read(stream));
}
void WorldModelGroup::ReadLiquid()
{
Chunk* chunk = SubData->GetChunkByName("MLIQ");
if (!chunk)
return;
HasLiquidData = true;
FILE* stream = chunk->GetStream();
LiquidDataHeader = LiquidHeader::Read(stream);
LiquidDataGeometry = LiquidData::Read(stream, LiquidDataHeader);
}
void WorldModelGroup::ReadVertices()
{
Chunk* chunk = SubData->GetChunkByName("MOVT");
if (!chunk)
return;
uint32 verticeCount = chunk->Length / 12;
Vertices.reserve(verticeCount);
FILE* stream = chunk->GetStream();
for (uint32 i = 0; i < verticeCount; i++)
Vertices.push_back(Vector3::Read(stream));
}
void WorldModelGroup::ReadTriangles()
{
Chunk* chunk = SubData->GetChunkByName("MOVI");
if (!chunk)
return;
uint32 triangleCount = chunk->Length / 6;
ASSERT(triangleCount == TriangleFlags.size() && "triangleCount != TriangleFlags.size()");
FILE* stream = chunk->GetStream();
Triangles.reserve(triangleCount);
for (uint32 i = 0; i < triangleCount; i++)
{
uint16 v0;
uint16 v1;
uint16 v2;
int count = 0;
count += fread(&v0, sizeof(uint16), 1, stream);
count += fread(&v1, sizeof(uint16), 1, stream);
count += fread(&v2, sizeof(uint16), 1, stream);
if (count != 3)
printf("WorldModelGroup::ReadMaterials: Error reading data, expected 3, read %d\n", count);
Triangles.push_back(Triangle<uint16>(Constants::TRIANGLE_TYPE_WMO, v0, v1, v2));
}
}
void WorldModelGroup::ReadMaterials()
{
Chunk* chunk = SubData->GetChunkByName("MOPY");
if (!chunk)
return;
FILE* stream = chunk->GetStream();
uint32 triangleCount = chunk->Length / 2;
TriangleFlags.reserve(triangleCount);
TriangleMaterials.reserve(triangleCount);
for (uint32 i = 0; i < triangleCount; i++)
{
uint8 tmp;
if (fread(&tmp, sizeof(uint8), 1, stream) != 1)
printf("WorldModelGroup::ReadMaterials: Error reading data, expected 1, read 0\n");
TriangleFlags.push_back(tmp);
// Read again for material.
if (fread(&tmp, sizeof(uint8), 1, stream) != 1)
printf("WorldModelGroup::ReadMaterials: Error reading data, expected 1, read 0\n");
TriangleMaterials.push_back(tmp);
}
}
void WorldModelGroup::ReadHeader()
{
Chunk* chunk = Data->GetChunkByName("MOGP");
if (!chunk)
return;
FILE* stream = chunk->GetStream();
Header = WMOGroupHeader::Read(stream);
}
void WorldModelGroup::ReadBatches()
{
Chunk* chunk = Data->GetChunkByName("MOBA");
if (!chunk)
return;
MOBALength = chunk->Length / 2;
MOBA = new uint16[MOBALength];
uint32 count = (uint32)fread(MOBA, sizeof(uint16), MOBALength, chunk->GetStream());
if (count != MOBALength)
printf("WorldModelGroup::ReadBatches: Error reading data, expected %u, read %u\n", MOBALength, count);
}
@@ -1,55 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WMOGROUP_H
#define WMOGROUP_H
#include "ChunkedData.h"
#include "Utils.h"
class WorldModelGroup
{
public:
WorldModelGroup(std::string path, int groupIndex);
ChunkedData* Data;
ChunkedData* SubData;
int GroupIndex;
std::string Name;
WMOGroupHeader Header;
std::vector<uint8> TriangleFlags;
std::vector<uint8> TriangleMaterials;
std::vector<Triangle<uint16>> Triangles;
std::vector<Vector3> Vertices;
std::vector<Vector3> Normals;
// @ToDo: Research.
uint16* MOBA;
uint32 MOBALength;
bool HasLiquidData;
bool IsBad;
LiquidHeader LiquidDataHeader;
LiquidData LiquidDataGeometry;
private:
void ReadNormals();
void ReadLiquid();
void ReadVertices();
void ReadTriangles();
void ReadMaterials();
void ReadHeader();
void ReadBatches();
};
#endif
@@ -1,234 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WorldModelHandler.h"
#include "Cache.h"
#include "Chunk.h"
#include "Define.h"
#include "G3D/Matrix4.h"
#include "G3D/Quat.h"
#include "Model.h"
#include "WorldModelRoot.h"
#include <cstdio>
WorldModelDefinition WorldModelDefinition::Read( FILE* file )
{
WorldModelDefinition ret;
int count = 0;
count += fread(&ret.MwidIndex, sizeof(uint32), 1, file);
count += fread(&ret.UniqueId, sizeof(uint32), 1, file);
ret.Position = Vector3::Read(file);
ret.Rotation = Vector3::Read(file);
ret.UpperExtents = Vector3::Read(file);
ret.LowerExtents = Vector3::Read(file);
count += fread(&ret.Flags, sizeof(uint16), 1, file);
count += fread(&ret.DoodadSet, sizeof(uint16), 1, file);
uint32 discard;
count += fread(&discard, sizeof(uint32), 1, file);
if (count != 5)
printf("WorldModelDefinition::Read: Error reading data, expected 5, read %d\n", count);
return ret;
}
WorldModelHandler::WorldModelHandler( ADT* adt ) : ObjectDataHandler(adt), _definitions(nullptr), _paths(nullptr)
{
ReadModelPaths();
ReadDefinitions();
}
void WorldModelHandler::ProcessInternal( MapChunk* mcnk )
{
if (!IsSane())
return;
uint32 refCount = mcnk->Header.MapObjectRefs;
FILE* stream = mcnk->Source->GetStream();
fseek(stream, mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET);
// Start looping at the last Doodad Ref index
for (uint32 i = mcnk->Header.DoodadRefs; i < refCount; i++)
{
int32 index;
if (fread(&index, sizeof(int32), 1, stream) != 1)
printf("WorldModelDefinition::Read: Error reading data, expected 1, read 0\n");
if (index < 0 || uint32(index) >= _definitions->size())
continue;
WorldModelDefinition wmo = (*_definitions)[index];
if (_drawn.find(wmo.UniqueId) != _drawn.end())
continue;
_drawn.insert(wmo.UniqueId);
if (wmo.MwidIndex >= _paths->size())
continue;
std::string path = (*_paths)[wmo.MwidIndex];
WorldModelRoot* model = Cache->WorldModelCache.Get(path);
if (!model)
{
model = new WorldModelRoot(path);
Cache->WorldModelCache.Insert(path, model);
}
Vertices.reserve(1000);
Triangles.reserve(1000);
InsertModelGeometry(Vertices, Triangles, wmo, model);
}
// Restore the stream position
fseek(stream, mcnk->Source->Offset, SEEK_SET);
}
void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::vector<Triangle<uint32>>& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate )
{
for (std::vector<WorldModelGroup>::iterator group = root->Groups.begin(); group != root->Groups.end(); ++group)
{
uint32 vertOffset = verts.size();
for (std::vector<Vector3>::iterator itr2 = group->Vertices.begin(); itr2 != group->Vertices.end(); ++itr2)
{
Vector3 v = Utils::TransformDoodadVertex(def, *itr2, translate);
// If translate is false, then we were called directly from the TileBuilder to add data to it's _Geometry member, hence, we have to manually convert the vertices to Recast format.
verts.push_back(translate ? v : Utils::ToRecast(v)); // Transform the vertex to world space
}
for (uint32 i = 0; i < group->Triangles.size(); ++i)
{
// only include colliding tris
if ((group->TriangleFlags[i] & 0x04) != 0 && group->TriangleMaterials[i] != 0xFF)
continue;
Triangle<uint16> tri = group->Triangles[i];
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WMO, tri.V0 + vertOffset, tri.V1 + vertOffset, tri.V2 + vertOffset));
}
}
if (def.DoodadSet < root->DoodadSets.size())
{
DoodadSet set = root->DoodadSets[def.DoodadSet];
std::vector<DoodadInstance> instances;
instances.reserve(set.CountInstances);
for (uint32 i = set.FirstInstanceIndex; i < (set.CountInstances + set.FirstInstanceIndex); i++)
{
if (i >= root->DoodadInstances.size())
break;
instances.push_back(root->DoodadInstances[i]);
}
for (std::vector<DoodadInstance>::iterator instance = instances.begin(); instance != instances.end(); ++instance)
{
Model* model = Cache->ModelCache.Get(instance->File);
if (!model)
{
model = new Model(instance->File);
Cache->ModelCache.Insert(instance->File, model);
}
if (!model->IsCollidable)
continue;
int vertOffset = verts.size();
for (std::vector<Vector3>::iterator itr2 = model->Vertices.begin(); itr2 != model->Vertices.end(); ++itr2)
{
Vector3 v = Utils::TransformDoodadVertex(def, Utils::TransformWmoDoodad(*instance, def, *itr2, false), translate);
verts.push_back(translate ? v : Utils::ToRecast(v));
}
for (std::vector<Triangle<uint16>>::iterator itr2 = model->Triangles.begin(); itr2 != model->Triangles.end(); ++itr2)
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WMO, itr2->V0 + vertOffset, itr2->V1 + vertOffset, itr2->V2 + vertOffset));
}
for (std::vector<WorldModelGroup>::iterator group = root->Groups.begin(); group != root->Groups.end(); ++group)
{
if (!group->HasLiquidData)
continue;
const LiquidHeader& liquidHeader = group->LiquidDataHeader;
LiquidData& liquidDataGeometry = group->LiquidDataGeometry;
for (uint32 y = 0; y < liquidHeader.Height; y++)
{
for (uint32 x = 0; x < liquidHeader.Width; x++)
{
if (!liquidDataGeometry.ShouldRender(x, y))
continue;
uint32 vertOffset = verts.size();
Vector3 v1 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
liquidDataGeometry.HeightMap[x][y], x, y, translate);
Vector3 v2 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
liquidDataGeometry.HeightMap[x + 1][y], x + 1, y, translate);
Vector3 v3 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
liquidDataGeometry.HeightMap[x][y + 1], x, y + 1, translate);
Vector3 v4 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
liquidDataGeometry.HeightMap[x + 1][y + 1], x + 1, y + 1, translate);
verts.push_back(translate ? v1 : Utils::ToRecast(v1));
verts.push_back(translate ? v2 : Utils::ToRecast(v2));
verts.push_back(translate ? v3 : Utils::ToRecast(v3));
verts.push_back(translate ? v4 : Utils::ToRecast(v4));
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset, vertOffset + 2, vertOffset + 1));
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset + 2, vertOffset + 3, vertOffset + 1));
}
}
}
}
}
void WorldModelHandler::ReadDefinitions()
{
Chunk* chunk = Source->ObjectData->GetChunkByName("MODF");
if (!chunk)
return;
const int32 definitionSize = 64;
uint32 definitionCount = chunk->Length / definitionSize;
_definitions = new std::vector<WorldModelDefinition>;
_definitions->reserve(definitionCount);
FILE* stream = chunk->GetStream();
for (uint32 i = 0; i < definitionCount; i++)
_definitions->push_back(WorldModelDefinition::Read(stream));
}
void WorldModelHandler::ReadModelPaths()
{
Chunk* mwid = Source->ObjectData->GetChunkByName("MWID");
Chunk* mwmo = Source->ObjectData->GetChunkByName("MWMO");
if (!mwid || !mwmo)
return;
uint32 paths = mwid->Length / 4;
_paths = new std::vector<std::string>;
_paths->reserve(paths);
for (uint32 i = 0; i < paths; i++)
{
FILE* stream = mwid->GetStream();
fseek(stream, i * 4, SEEK_CUR);
uint32 offset;
if (fread(&offset, sizeof(uint32), 1, stream) != 1)
printf("WorldModelDefinition::Read: Error reading data, expected 1, read 0\n");
FILE* dataStream = mwmo->GetStream();
fseek(dataStream, offset + mwmo->Offset, SEEK_SET);
_paths->push_back(Utils::ReadString(dataStream));
}
}
WorldModelHandler::~WorldModelHandler()
{
delete _definitions;
delete _paths;
}
@@ -1,64 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WMODEL_HNDL_H
#define WMODEL_HNDL_H
#include "Define.h"
#include "ObjectDataHandler.h"
#include "Utils.h"
#include "WorldModelRoot.h"
#include <set>
#include <vector>
class ADT;
struct WorldModelDefinition : public IDefinition
{
public:
WorldModelDefinition() {}
uint32 MwidIndex;
uint32 UniqueId;
Vector3 UpperExtents;
Vector3 LowerExtents;
uint16 Flags;
uint16 DoodadSet;
static WorldModelDefinition Read(FILE* file);
};
class WorldModelHandler : public ObjectDataHandler
{
public:
WorldModelHandler(ADT* adt);
~WorldModelHandler();
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32>> Triangles;
bool IsSane() { return _definitions && _paths; }
static void InsertModelGeometry(std::vector<Vector3>& verts, std::vector<Triangle<uint32>>& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate = true);
protected:
void ProcessInternal(MapChunk* data);
private:
void ReadDefinitions();
void ReadModelPaths();
std::set<uint32> _drawn;
std::vector<WorldModelDefinition>* _definitions;
std::vector<std::string>* _paths;
};
#endif
@@ -1,96 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WorldModelRoot.h"
#include "ChunkedData.h"
#include "Utils.h"
WorldModelRoot::WorldModelRoot( std::string path )
{
Data = new ChunkedData(path);
Path = path;
ReadHeader();
ReadGroups();
ReadDoodadInstances();
ReadDoodadSets();
}
WorldModelRoot::~WorldModelRoot()
{
delete Data;
}
void WorldModelRoot::ReadGroups()
{
std::string pathBase = Utils::GetPathBase(Path);
Groups.reserve(Header.CountGroups);
for (uint32 i = 0; i < Header.CountGroups; i++)
{
char name[200];
sprintf(name, "%s_%03u.wmo", pathBase.c_str(), i);
WorldModelGroup group(name, i);
if (!group.IsBad)
Groups.push_back(group);
}
}
void WorldModelRoot::ReadDoodadSets()
{
Chunk* chunk = Data->GetChunkByName("MODS");
if (!chunk)
return;
FILE* stream = chunk->GetStream();
ASSERT(chunk->Length / 32 == Header.CountSets && "chunk.Length / 32 == Header.CountSets");
DoodadSets.reserve(Header.CountSets);
for (uint32 i = 0; i < Header.CountSets; i++)
DoodadSets.push_back(DoodadSet::Read(stream));
}
void WorldModelRoot::ReadDoodadInstances()
{
Chunk* chunk = Data->GetChunkByName("MODD");
Chunk* nameChunk = Data->GetChunkByName("MODN");
if (!chunk || !nameChunk)
return;
const uint32 instanceSize = 40;
uint32 countInstances = chunk->Length / instanceSize;
DoodadInstances.reserve(countInstances);
for (uint32 i = 0; i < countInstances; i++)
{
FILE* stream = chunk->GetStream();
fseek(stream, instanceSize * i, SEEK_CUR);
DoodadInstance instance = DoodadInstance::Read(stream);
FILE* nameStream = nameChunk->GetStream();
if (instance.FileOffset >= nameChunk->Length)
continue;
fseek(nameStream, instance.FileOffset, SEEK_CUR);
instance.File = Utils::ReadString(nameStream);
DoodadInstances.push_back(instance);
}
}
void WorldModelRoot::ReadHeader()
{
Chunk* chunk = Data->GetChunkByName("MOHD");
if (!chunk)
return;
FILE* stream = chunk->GetStream();
Header = WorldModelHeader::Read(stream);
}
-44
View File
@@ -1,44 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WMOROOT_H
#define WMOROOT_H
#include <string>
#include <vector>
#include "ChunkedData.h"
#include "Utils.h"
#include "WorldModelGroup.h"
class WorldModelRoot
{
public:
WorldModelRoot(std::string path);
~WorldModelRoot();
std::string Path;
ChunkedData* Data;
WorldModelHeader Header;
std::vector<DoodadInstance> DoodadInstances;
std::vector<DoodadSet> DoodadSets;
std::vector<WorldModelGroup> Groups;
private:
void ReadGroups();
void ReadDoodadSets();
void ReadDoodadInstances();
void ReadHeader();
};
#endif
-6
View File
@@ -1,6 +0,0 @@
Experimental mesh extractor.
Original work in C# by stschake
Thanks to:
Subv
~
For helping in the porting to C++
+110 -45
View File
@@ -26,15 +26,43 @@
namespace MMAP namespace MMAP
{ {
TileBuilder::TileBuilder(MapBuilder* mapBuilder, bool skipLiquid, bool bigBaseUnit, bool debugOutput) :
m_bigBaseUnit(bigBaseUnit),
m_debugOutput(debugOutput),
m_mapBuilder(mapBuilder),
m_terrainBuilder(nullptr),
m_workerThread(&TileBuilder::WorkerThread, this),
m_rcContext(nullptr)
{
m_terrainBuilder = new TerrainBuilder(skipLiquid);
m_rcContext = new rcContext(false);
}
TileBuilder::~TileBuilder()
{
WaitCompletion();
delete m_terrainBuilder;
delete m_rcContext;
}
void TileBuilder::WaitCompletion()
{
if (m_workerThread.joinable())
m_workerThread.join();
}
MapBuilder::MapBuilder(Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep, bool skipLiquid, MapBuilder::MapBuilder(Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep, bool skipLiquid,
bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds, bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
bool debugOutput, bool bigBaseUnit, int mapid, const char* offMeshFilePath) : bool debugOutput, bool bigBaseUnit, int mapid, const char* offMeshFilePath, unsigned int threads) :
m_debugOutput (debugOutput), m_debugOutput (debugOutput),
m_offMeshFilePath (offMeshFilePath), m_offMeshFilePath (offMeshFilePath),
m_threads (threads),
m_skipContinents (skipContinents), m_skipContinents (skipContinents),
m_skipJunkMaps (skipJunkMaps), m_skipJunkMaps (skipJunkMaps),
m_skipBattlegrounds (skipBattlegrounds), m_skipBattlegrounds (skipBattlegrounds),
m_skipLiquid (skipLiquid),
m_maxWalkableAngle (maxWalkableAngle), m_maxWalkableAngle (maxWalkableAngle),
m_maxWalkableAngleNotSteep (maxWalkableAngleNotSteep), m_maxWalkableAngleNotSteep (maxWalkableAngleNotSteep),
m_bigBaseUnit (bigBaseUnit), m_bigBaseUnit (bigBaseUnit),
@@ -48,6 +76,9 @@ namespace MMAP
m_rcContext = new rcContext(false); m_rcContext = new rcContext(false);
// At least 1 thread is needed
m_threads = std::max(1u, m_threads);
discoverTiles(); discoverTiles();
} }
@@ -170,29 +201,26 @@ namespace MMAP
} }
/**************************************************************************/ /**************************************************************************/
void MapBuilder::buildAllMaps(unsigned int threads) void MapBuilder::buildMaps(Optional<uint32> mapID)
{ {
printf("Using %u threads to extract mmaps\n", threads); printf("Using %u threads to generate mmaps\n", m_threads);
for (unsigned int i = 0; i < threads; ++i) for (unsigned int i = 0; i < m_threads; ++i)
{ {
_workerThreads.emplace_back(&MapBuilder::WorkerThread, this); m_tileBuilders.push_back(new TileBuilder(this, m_skipLiquid, m_bigBaseUnit, m_debugOutput));
} }
m_tiles.sort([](MapTiles a, MapTiles b) if (mapID)
{ {
return a.m_tiles->size() > b.m_tiles->size(); buildMap(*mapID);
}); }
else
for (auto & m_tile : m_tiles)
{ {
uint32 mapId = m_tile.m_mapId; // Build all maps if no map id has been specified
if (!shouldSkipMap(mapId)) for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
{ {
if (threads > 0) if (!shouldSkipMap(it->m_mapId))
_queue.Push(mapId); buildMap(it->m_mapId);
else
buildMap(mapId);
} }
} }
@@ -205,10 +233,10 @@ namespace MMAP
_queue.Cancel(); _queue.Cancel();
for (auto& thread : _workerThreads) for (auto& builder : m_tileBuilders)
{ delete builder;
thread.join();
} m_tileBuilders.clear();
} }
/**************************************************************************/ /**************************************************************************/
@@ -337,7 +365,8 @@ namespace MMAP
getTileBounds(tileX, tileY, data.solidVerts.getCArray(), data.solidVerts.size() / 3, bmin, bmax); getTileBounds(tileX, tileY, data.solidVerts.getCArray(), data.solidVerts.size() / 3, bmin, bmax);
// build navmesh tile // build navmesh tile
buildMoveMapTile(mapId, tileX, tileY, data, bmin, bmax, navMesh); TileBuilder tileBuilder = TileBuilder(this, m_skipLiquid, m_bigBaseUnit, m_debugOutput);
tileBuilder.buildMoveMapTile(mapId, tileX, tileY, data, bmin, bmax, navMesh);
fclose(file); fclose(file);
} }
@@ -352,22 +381,39 @@ namespace MMAP
return; return;
} }
buildTile(mapID, tileX, tileY, navMesh); // ToDo: delete the old tile as the user clearly wants to rebuild it
TileBuilder tileBuilder = TileBuilder(this, m_skipLiquid, m_bigBaseUnit, m_debugOutput);
tileBuilder.buildTile(mapID, tileX, tileY, navMesh);
dtFreeNavMesh(navMesh); dtFreeNavMesh(navMesh);
_cancelationToken = true;
_queue.Cancel();
} }
void MapBuilder::WorkerThread() void TileBuilder::WorkerThread()
{ {
while (true) while (true)
{ {
uint32 mapId = 0; TileInfo tileInfo;
_queue.WaitAndPop(mapId); m_mapBuilder->_queue.WaitAndPop(tileInfo);
if (_cancelationToken) if (m_mapBuilder->_cancelationToken)
return; return;
buildMap(mapId); dtNavMesh* navMesh = dtAllocNavMesh();
if (!navMesh->init(&tileInfo.m_navMeshParams))
{
printf("[Map %04i] Failed creating navmesh for tile %i,%i !\n", tileInfo.m_mapId, tileInfo.m_tileX, tileInfo.m_tileY);
dtFreeNavMesh(navMesh);
return;
}
buildTile(tileInfo.m_mapId, tileInfo.m_tileX, tileInfo.m_tileY, navMesh);
dtFreeNavMesh(navMesh);
} }
} }
@@ -397,22 +443,28 @@ namespace MMAP
// unpack tile coords // unpack tile coords
StaticMapTree::unpackTileID(tile, tileX, tileY); StaticMapTree::unpackTileID(tile, tileX, tileY);
if (!shouldSkipTile(mapID, tileX, tileY)) TileInfo tileInfo;
buildTile(mapID, tileX, tileY, navMesh); tileInfo.m_mapId = mapID;
tileInfo.m_tileX = tileX;
++m_totalTilesProcessed; tileInfo.m_tileY = tileY;
memcpy(&tileInfo.m_navMeshParams, navMesh->getParams(), sizeof(dtNavMeshParams));
_queue.Push(tileInfo);
} }
dtFreeNavMesh(navMesh); dtFreeNavMesh(navMesh);
} }
printf("[Map %03i] Complete!\n", mapID);
} }
/**************************************************************************/ /**************************************************************************/
void MapBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh) void TileBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh)
{ {
printf("%u%% [Map %03i] Building tile [%02u,%02u]\n", percentageDone(m_totalTiles, m_totalTilesProcessed), mapID, tileX, tileY); if(shouldSkipTile(mapID, tileX, tileY))
{
++m_mapBuilder->m_totalTilesProcessed;
return;
}
printf("%u%% [Map %04i] Building tile [%02u,%02u]\n", m_mapBuilder->currentPercentageDone(), mapID, tileX, tileY);
MeshData meshData; MeshData meshData;
@@ -424,7 +476,10 @@ namespace MMAP
// if there is no data, give up now // if there is no data, give up now
if (!meshData.solidVerts.size() && !meshData.liquidVerts.size()) if (!meshData.solidVerts.size() && !meshData.liquidVerts.size())
{
++m_mapBuilder->m_totalTilesProcessed;
return; return;
}
// remove unused vertices // remove unused vertices
TerrainBuilder::cleanVertices(meshData.solidVerts, meshData.solidTris); TerrainBuilder::cleanVertices(meshData.solidVerts, meshData.solidTris);
@@ -436,16 +491,21 @@ namespace MMAP
allVerts.append(meshData.solidVerts); allVerts.append(meshData.solidVerts);
if (!allVerts.size()) if (!allVerts.size())
{
++m_mapBuilder->m_totalTilesProcessed;
return; return;
}
// get bounds of current tile // get bounds of current tile
float bmin[3], bmax[3]; float bmin[3], bmax[3];
getTileBounds(tileX, tileY, allVerts.getCArray(), allVerts.size() / 3, bmin, bmax); m_mapBuilder->getTileBounds(tileX, tileY, allVerts.getCArray(), allVerts.size() / 3, bmin, bmax);
m_terrainBuilder->loadOffMeshConnections(mapID, tileX, tileY, meshData, m_offMeshFilePath); m_terrainBuilder->loadOffMeshConnections(mapID, tileX, tileY, meshData, m_mapBuilder->m_offMeshFilePath);
// build navmesh tile // build navmesh tile
buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh); buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
++m_mapBuilder->m_totalTilesProcessed;
} }
/**************************************************************************/ /**************************************************************************/
@@ -524,7 +584,7 @@ namespace MMAP
} }
/**************************************************************************/ /**************************************************************************/
void MapBuilder::buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY, void TileBuilder::buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY,
MeshData& meshData, float bmin[3], float bmax[3], MeshData& meshData, float bmin[3], float bmax[3],
dtNavMesh* navMesh) dtNavMesh* navMesh)
{ {
@@ -549,7 +609,7 @@ namespace MMAP
const TileConfig tileConfig = TileConfig(m_bigBaseUnit); const TileConfig tileConfig = TileConfig(m_bigBaseUnit);
int TILES_PER_MAP = tileConfig.TILES_PER_MAP; int TILES_PER_MAP = tileConfig.TILES_PER_MAP;
float BASE_UNIT_DIM = tileConfig.BASE_UNIT_DIM; float BASE_UNIT_DIM = tileConfig.BASE_UNIT_DIM;
rcConfig config = GetMapSpecificConfig(mapID, bmin, bmax, tileConfig); rcConfig config = m_mapBuilder->GetMapSpecificConfig(mapID, bmin, bmax, tileConfig);
// this sets the dimensions of the heightfield - should maybe happen before border padding // this sets the dimensions of the heightfield - should maybe happen before border padding
rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height); rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height);
@@ -852,7 +912,7 @@ namespace MMAP
} }
/**************************************************************************/ /**************************************************************************/
void MapBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) void MapBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) const
{ {
// this is for elevation // this is for elevation
if (verts && vertCount) if (verts && vertCount)
@@ -871,7 +931,7 @@ namespace MMAP
} }
/**************************************************************************/ /**************************************************************************/
bool MapBuilder::shouldSkipMap(uint32 mapID) bool MapBuilder::shouldSkipMap(uint32 mapID) const
{ {
if (m_mapid >= 0) if (m_mapid >= 0)
return static_cast<uint32>(m_mapid) != mapID; return static_cast<uint32>(m_mapid) != mapID;
@@ -927,7 +987,7 @@ namespace MMAP
} }
/**************************************************************************/ /**************************************************************************/
bool MapBuilder::isTransportMap(uint32 mapID) bool MapBuilder::isTransportMap(uint32 mapID) const
{ {
switch (mapID) switch (mapID)
{ {
@@ -967,7 +1027,7 @@ namespace MMAP
} }
/**************************************************************************/ /**************************************************************************/
bool MapBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) bool TileBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const
{ {
char fileName[255]; char fileName[255];
sprintf(fileName, "mmaps/%03u%02i%02i.mmtile", mapID, tileY, tileX); sprintf(fileName, "mmaps/%03u%02i%02i.mmtile", mapID, tileY, tileX);
@@ -990,7 +1050,7 @@ namespace MMAP
return true; return true;
} }
rcConfig MapBuilder::GetMapSpecificConfig(uint32 mapID, float bmin[3], float bmax[3], const TileConfig &tileConfig) rcConfig MapBuilder::GetMapSpecificConfig(uint32 mapID, float bmin[3], float bmax[3], const TileConfig &tileConfig) const
{ {
rcConfig config; rcConfig config;
memset(&config, 0, sizeof(rcConfig)); memset(&config, 0, sizeof(rcConfig));
@@ -1039,11 +1099,16 @@ namespace MMAP
} }
/**************************************************************************/ /**************************************************************************/
uint32 MapBuilder::percentageDone(uint32 totalTiles, uint32 totalTilesBuilt) uint32 MapBuilder::percentageDone(uint32 totalTiles, uint32 totalTilesBuilt) const
{ {
if (totalTiles) if (totalTiles)
return totalTilesBuilt * 100 / totalTiles; return totalTilesBuilt * 100 / totalTiles;
return 0; return 0;
} }
uint32 MapBuilder::currentPercentageDone() const
{
return percentageDone(m_totalTiles, m_totalTilesProcessed);
}
} }
+78 -38
View File
@@ -94,43 +94,33 @@ namespace MMAP
int TILES_PER_MAP; int TILES_PER_MAP;
}; };
class MapBuilder struct TileInfo
{
TileInfo() : m_mapId(uint32(-1)), m_tileX(), m_tileY(), m_navMeshParams() {}
uint32 m_mapId;
uint32 m_tileX;
uint32 m_tileY;
dtNavMeshParams m_navMeshParams;
};
// ToDo: move this to its own file. For now it will stay here to keep the changes to a minimum, especially in the cpp file
class MapBuilder;
class TileBuilder
{ {
public: public:
MapBuilder(Optional<float> maxWalkableAngle, TileBuilder(MapBuilder* mapBuilder,
Optional<float> maxWalkableAngleNotSteep, bool skipLiquid,
bool skipLiquid = false, bool bigBaseUnit,
bool skipContinents = false, bool debugOutput);
bool skipJunkMaps = true,
bool skipBattlegrounds = false,
bool debugOutput = false,
bool bigBaseUnit = false,
int mapid = -1,
const char* offMeshFilePath = nullptr);
~MapBuilder(); TileBuilder(TileBuilder&&) = default;
~TileBuilder();
// builds all mmap tiles for the specified map id (ignores skip settings)
void buildMap(uint32 mapID);
void buildMeshFromFile(char* name);
// builds an mmap tile for the specified map and its mesh
void buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY);
// builds list of maps, then builds all of mmap tiles (based on the skip settings)
void buildAllMaps(unsigned int threads);
void WorkerThread(); void WorkerThread();
void WaitCompletion();
private:
// detect maps and tiles
void discoverTiles();
std::set<uint32>* getTileList(uint32 mapID);
void buildNavMesh(uint32 mapID, dtNavMesh*& navMesh);
void buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh); void buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh);
// move map building // move map building
void buildMoveMapTile(uint32 mapID, void buildMoveMapTile(uint32 mapID,
uint32 tileX, uint32 tileX,
@@ -140,18 +130,66 @@ namespace MMAP
float bmax[3], float bmax[3],
dtNavMesh* navMesh); dtNavMesh* navMesh);
bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const;
private:
bool m_bigBaseUnit;
bool m_debugOutput;
MapBuilder* m_mapBuilder;
TerrainBuilder* m_terrainBuilder;
std::thread m_workerThread;
// build performance - not really used for now
rcContext* m_rcContext;
};
class MapBuilder
{
friend class TileBuilder;
public:
MapBuilder(Optional<float> maxWalkableAngle,
Optional<float> maxWalkableAngleNotSteep,
bool skipLiquid,
bool skipContinents,
bool skipJunkMaps,
bool skipBattlegrounds,
bool debugOutput,
bool bigBaseUnit,
int mapid,
char const* offMeshFilePath,
unsigned int threads);
~MapBuilder();
void buildMeshFromFile(char* name);
// builds an mmap tile for the specified map and its mesh
void buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY);
// builds list of maps, then builds all of mmap tiles (based on the skip settings)
void buildMaps(Optional<uint32> mapID);
private:
// builds all mmap tiles for the specified map id (ignores skip settings)
void buildMap(uint32 mapID);
// detect maps and tiles
void discoverTiles();
std::set<uint32>* getTileList(uint32 mapID);
void buildNavMesh(uint32 mapID, dtNavMesh*& navMesh);
void getTileBounds(uint32 tileX, uint32 tileY, void getTileBounds(uint32 tileX, uint32 tileY,
float* verts, int vertCount, float* verts, int vertCount,
float* bmin, float* bmax); float* bmin, float* bmax) const;
void getGridBounds(uint32 mapID, uint32& minX, uint32& minY, uint32& maxX, uint32& maxY) const; void getGridBounds(uint32 mapID, uint32& minX, uint32& minY, uint32& maxX, uint32& maxY) const;
bool shouldSkipMap(uint32 mapID); bool shouldSkipMap(uint32 mapID) const;
bool isTransportMap(uint32 mapID); bool isTransportMap(uint32 mapID) const;
bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY);
rcConfig GetMapSpecificConfig(uint32 mapID, float bmin[3], float bmax[3], const TileConfig &tileConfig); rcConfig GetMapSpecificConfig(uint32 mapID, float bmin[3], float bmax[3], const TileConfig &tileConfig) const;
uint32 percentageDone(uint32 totalTiles, uint32 totalTilesDone); uint32 percentageDone(uint32 totalTiles, uint32 totalTilesDone) const;
uint32 currentPercentageDone() const;
TerrainBuilder* m_terrainBuilder{nullptr}; TerrainBuilder* m_terrainBuilder{nullptr};
TileList m_tiles; TileList m_tiles;
@@ -159,9 +197,11 @@ namespace MMAP
bool m_debugOutput; bool m_debugOutput;
const char* m_offMeshFilePath; const char* m_offMeshFilePath;
unsigned int m_threads;
bool m_skipContinents; bool m_skipContinents;
bool m_skipJunkMaps; bool m_skipJunkMaps;
bool m_skipBattlegrounds; bool m_skipBattlegrounds;
bool m_skipLiquid;
Optional<float> m_maxWalkableAngle; Optional<float> m_maxWalkableAngle;
Optional<float> m_maxWalkableAngleNotSteep; Optional<float> m_maxWalkableAngleNotSteep;
@@ -174,8 +214,8 @@ namespace MMAP
// build performance - not really used for now // build performance - not really used for now
rcContext* m_rcContext{nullptr}; rcContext* m_rcContext{nullptr};
std::vector<std::thread> _workerThreads; std::vector<TileBuilder*> m_tileBuilders;
ProducerConsumerQueue<uint32> _queue; ProducerConsumerQueue<TileInfo> _queue;
std::atomic<bool> _cancelationToken; std::atomic<bool> _cancelationToken;
}; };
} }
+4 -5
View File
@@ -56,8 +56,7 @@ bool checkDirectories(bool debugOutput)
dirFiles.clear(); dirFiles.clear();
if (getDirContents(dirFiles, "mmaps") == LISTFILE_DIRECTORY_NOT_FOUND) if (getDirContents(dirFiles, "mmaps") == LISTFILE_DIRECTORY_NOT_FOUND)
{ {
printf("'mmaps' directory does not exist\n"); return boost::filesystem::create_directory("mmaps");
return false;
} }
dirFiles.clear(); dirFiles.clear();
@@ -329,7 +328,7 @@ int main(int argc, char** argv)
} }
MapBuilder builder(maxAngle, maxAngleNotSteep, skipLiquid, skipContinents, skipJunkMaps, MapBuilder builder(maxAngle, maxAngleNotSteep, skipLiquid, skipContinents, skipJunkMaps,
skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath); skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath, threads);
uint32 start = getMSTime(); uint32 start = getMSTime();
if (file) if (file)
@@ -337,9 +336,9 @@ int main(int argc, char** argv)
else if (tileX > -1 && tileY > -1 && mapnum >= 0) else if (tileX > -1 && tileY > -1 && mapnum >= 0)
builder.buildSingleTile(mapnum, tileX, tileY); builder.buildSingleTile(mapnum, tileX, tileY);
else if (mapnum >= 0) else if (mapnum >= 0)
builder.buildMap(uint32(mapnum)); builder.buildMaps(uint32(mapnum));
else else
builder.buildAllMaps(threads); builder.buildMaps({});
if (!silent) if (!silent)
printf("Finished. MMAPS were built in %u ms!\n", GetMSTimeDiffToNow(start)); printf("Finished. MMAPS were built in %u ms!\n", GetMSTimeDiffToNow(start));
+11 -4
View File
@@ -22,14 +22,21 @@
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
if (argc != 3) std::string src = "Buildings";
std::string dest = "vmaps";
if (argc > 3)
{ {
std::cout << "usage: " << argv[0] << " <raw data dir> <vmap dest dir>" << std::endl; std::cout << "usage: " << argv[0] << " <raw data dir> <vmap dest dir>" << std::endl;
return 1; return 1;
} }
else
std::string src = argv[1]; {
std::string dest = argv[2]; if (argc > 1)
src = argv[1];
if (argc > 2)
dest = argv[2];
}
std::cout << "using " << src << " as source directory and writing output to " << dest << std::endl; std::cout << "using " << src << " as source directory and writing output to " << dest << std::endl;