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:
@@ -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: |
|
||||||
|
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
@@ -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"* ]]
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Vendored
-1
@@ -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";
|
||||||
|
|||||||
Vendored
+36
-28
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Vendored
+26
-17
@@ -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
|
||||||
|
|||||||
Vendored
+103
@@ -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
|
||||||
|
|
||||||
Vendored
+103
@@ -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
|
||||||
|
|
||||||
Vendored
+62
-16
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 ""
|
||||||
|
|||||||
@@ -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!")
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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()
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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()
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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(¶ms, 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(¶ms, 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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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));
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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(¶ms, 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(¶ms);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -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));
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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(¶ms, 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(¶ms, &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(¶ms, 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(¶ms, &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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
Experimental mesh extractor.
|
|
||||||
Original work in C# by stschake
|
|
||||||
Thanks to:
|
|
||||||
Subv
|
|
||||||
~
|
|
||||||
For helping in the porting to C++
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user