diff --git a/.gitignore b/.gitignore index 754b7124..97aa43f5 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,10 @@ build/ *.out *.app +# Projects and Solutions +*.vcxproj +*.sln + # CMake CMakeCache.txt CMakeFiles @@ -96,6 +100,10 @@ src/libraries/external/boost_* *.ipdb *.iobj *.filters +*.idb # sapphire version src/servers/Server_Common/Version\.cpp + +# edit and continue files +/enc_temp_folder \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 5a08c891..6c5c62cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,17 +6,19 @@ before_install: - sudo apt-get update - sudo apt-get install -y software-properties-common - sudo apt-get update - - sudo apt-get install gcc-4.9 g++-4.9 gcc-4.9-multilib g++-4.9-multilib cmake3 -y + - sudo apt-get install gcc-7 g++-7 gcc-7-multilib g++-7-multilib cmake3 -y - sudo apt-get install libboost-dev libboost-all-dev libmysqlclient-dev -y - - sudo apt-get install libmysqlcppconn-dev -y + - sudo apt-get install libmysqlcppconn-dev -y + compiler: - - gcc + - g++ # Build steps script: + - g++ --version - mkdir build - cd build - - cmake .. -DSAPPHIRE_BOOST_VER="1.54.0" -DCMAKE_CXX_COMPILER=g++-4.9 -DCMAKE_C_COMPILER=gcc-4.9 && make -j 3 + - cmake .. -DSAPPHIRE_BOOST_VER="1.54.0" -DCMAKE_CXX_COMPILER=g++-7 && make -j 3 - cd .. - bash sql_import.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index d9e90ef2..997abb3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,4 +65,4 @@ add_subdirectory("src/tools/exd_common_gen") add_subdirectory("src/tools/exd_struct_gen") add_subdirectory("src/tools/exd_struct_test") add_subdirectory("src/tools/quest_parser") - +add_subdirectory("src/tools/pcb_reader") diff --git a/bin/config/settings_zone.xml b/bin/config/settings_zone.xml index fee76340..b1ab6081 100644 --- a/bin/config/settings_zone.xml +++ b/bin/config/settings_zone.xml @@ -25,6 +25,6 @@ <<<Welcome to Sapphire>>> This is a very good server You can change these messages by editing MotDArray in config/settings_zone.xml - + diff --git a/bin/web/assets/css/global.css b/bin/web/assets/css/global.css index de6b97e4..290a0199 100644 --- a/bin/web/assets/css/global.css +++ b/bin/web/assets/css/global.css @@ -1,18 +1,21 @@ -body{ - font-family:Verdana; - font-size:10pt; - line-height:14pt; - height:100%; - background-image:url(../../assets/img/background.png); - background-color:#282828; +html { + min-height: 100%; } -div.contentContainer{ +body { + font-family: Meiryo, Verdana, sans-serif; + font-size: 12px; + line-height: 14px; + height: 100%; + overflow: hidden; +} + +.contentContainer{ width:50%; float:left; } -div.info{ +.info{ width:320px; height:100%; margin-left:auto; @@ -22,7 +25,7 @@ div.info{ background-color:lightgrey; } -div.infoFooter{ +.infoFooter{ width:400px; margin-left:auto; margin-right:auto; @@ -135,3 +138,26 @@ p.pageSubTitle{ margin:0 auto; } +.commit-history { + padding-left: 20px; +} + +.commit-history li a { + color: #fff; +} + +.commit-history li a:hover { + color: #bbb; +} + +.s-left-half { + overflow-y: auto; +} + +.s-link-badge { + font-size: 15px; +} + +h2 { + font-size: 19px; +} \ No newline at end of file diff --git a/bin/web/assets/css/styles.css b/bin/web/assets/css/styles.css index 0d03eddc..5e8f52ec 100644 --- a/bin/web/assets/css/styles.css +++ b/bin/web/assets/css/styles.css @@ -1,5 +1,138 @@ -div#TopDiv{ - padding:10px; +.s-logo { + padding: 25px 65px 15px 65px; +} + +.s-logo > img { + width: 100%; +} + +/* + Consider using vh? +*/ +.s-left-half { + left: 0; + background: #232326; + /* box-shadow: inset -4px 0px 4px -3px #1a1a1ab3; */ + color: white; +} + +.s-right-half { + right: 0; + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00233B', endColorstr='#090915',GradientType=0 ); + background: linear-gradient(#00233B 0%, #090915 100%); + border-left: 6px solid #16161b; + padding: 0; +} + +.s-full-split { + position: absolute; + top: 0; + bottom: 0; + float: left; + z-index: 10; +} + +.s-login-box { + background: #16161b; + position: relative; + z-index: 15; + padding: 0; + overflow: hidden; + width: 100%; + float: none; +} + +.s-login-box-form { + padding: 0 35px 8px 25px; + overflow: hidden; +} + +.s-login-input-wrapper { + color: white; + display: block; + width: 100%; + margin-bottom: 15px; + font-weight: normal; + font-size: 14px; + color: #fff; +} + +.s-login-input-wrapper > input { + background: #444; + border: 0; + border-bottom: 3px solid #595959; + padding: 7px 0 7px 7px; + width: 100%; + margin-top: 8px; + font-size: 13.5px; + color: white; +} + +.s-login-input-wrapper > input:focus { + border-color: #1868C2; +} + +.s-login-input-wrapper > input:active { + border-color: #1868C2; +} + +.s-login-input-wrapper > input:hover { + border-color: #1868C2; +} + +.btn.btn-default { + border: 0; + color: white; + border-radius: 0; + font-weight: normal; + text-shadow: none; + box-shadow: none; + border-color: #1868C2; + color: white !important; +} + + +.s-login-btn { + width: 150px; + background: #0e6bc9; + right: -7px; /* ugh. refer to padding-left on input above - more bounding box issues... */ + position: relative; +} + +.s-login-btn:hover { + width: 150px; + background: #3593f2; +} + +.s-acc-btn { + width: 100%; + background: #3B3B3B; + padding: 5px 0; + margin-top: 4px; +} + +.s-acc-btn:hover { + background: #6b6b6b; +} + +.s-error-text { + color: #ff3333; + margin: 3px; +} + +.s-gears { + position: absolute; + right: 0; + bottom: 0; + width: 35%; + max-width: 350px; + overflow: hidden; +} + +.s-gears > img { + width: 100%; + position: relative; + bottom: -40px; } img{ @@ -12,8 +145,39 @@ h2.text-center{ color:#fff; } -h1.text-center{ - color:#FFF; +.s-login-call{ + color: #fff; + margin-top: 15px; + font-size: 20px; +} + +.s-link-badge-wrapper { + clear: both; + +} + +.s-link-badge { + background: #fff; + line-height: 48px; + text-indent: 55px; + display: inline-block; + padding: 0; + font-size: 17px; + margin-top: 25px; + color: white; + border-bottom: 3px solid #43348D; + margin-bottom: 15px; +} + +.s-link-badge-discord { + background: #7082E1 url("../img/fa-discord-icon.png") 10px 7px no-repeat; + margin-right: 60px; /* Ideally we'd just use pull-right with the last col-xs-5 but IE7 bounding box render??? */ +} + +.s-link-badge-github { + background: #fff url("../img/github-icon.png") 10px 7px no-repeat; + color: #333; + border-bottom-color: #808080; } div.login-card{ @@ -30,11 +194,7 @@ input.input-sm{ margin-right:auto; } -div#Conttwo.container{ - display:block; - width:300px; - background-color:rgba(17, 17, 17, 0.77); -} + div#Split{ padding:2px; diff --git a/bin/web/assets/img/fa-discord-icon.png b/bin/web/assets/img/fa-discord-icon.png new file mode 100644 index 00000000..0c3aede3 Binary files /dev/null and b/bin/web/assets/img/fa-discord-icon.png differ diff --git a/bin/web/assets/img/github-icon.png b/bin/web/assets/img/github-icon.png new file mode 100644 index 00000000..28716639 Binary files /dev/null and b/bin/web/assets/img/github-icon.png differ diff --git a/bin/web/assets/img/graffletopia-gears.png b/bin/web/assets/img/graffletopia-gears.png new file mode 100644 index 00000000..466a5625 Binary files /dev/null and b/bin/web/assets/img/graffletopia-gears.png differ diff --git a/bin/web/assets/img/sapphire_logo.png b/bin/web/assets/img/sapphire_logo.png index a7970d0c..56827cd8 100644 Binary files a/bin/web/assets/img/sapphire_logo.png and b/bin/web/assets/img/sapphire_logo.png differ diff --git a/bin/web/assets/img/sapphire_logo_resize.png b/bin/web/assets/img/sapphire_logo_resize.png new file mode 100644 index 00000000..f0cd9a2d Binary files /dev/null and b/bin/web/assets/img/sapphire_logo_resize.png differ diff --git a/bin/web/createUser.html b/bin/web/createUser.html index 5d73e5d2..fe9398e0 100644 --- a/bin/web/createUser.html +++ b/bin/web/createUser.html @@ -23,7 +23,7 @@ var parsed = JSON.parse(response); window.external.Boot(parsed.sId, parsed.lobbyHost, parsed.frontierHost); }catch(err){ - document.getElementById("Error").innerHTML = "Create User failed."; + document.getElementById("Error").innerHTML = "User creation failed."; } } } @@ -46,25 +46,55 @@ -
-
-
-
-

Create Account

-

Username:

- -
-

Password:

- -
- -

-
-

Back to Login

-
-
+
+ +

Github stuff here soon!

+
+
+ +
+ + Back to Login +
+
+ +
+
+ + \ No newline at end of file diff --git a/bin/web/login.html b/bin/web/login.html index 6d32528d..24a0d591 100644 --- a/bin/web/login.html +++ b/bin/web/login.html @@ -2,13 +2,13 @@ - - - Sapphire login - - - - + + + Sapphire - Login + + + + -
-
-
-
-

Login To Account

-

Username:

- -
-

Password:

- -
- -

-
-

Create Account

-
-
- - +
+ +

Recent Activity

+ +
+
+ +
+ + Create Account +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/bin/web/sapphire_logo.png b/bin/web/sapphire_logo.png deleted file mode 100644 index a7970d0c..00000000 Binary files a/bin/web/sapphire_logo.png and /dev/null differ diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake index 760de187..ebf42d84 100644 --- a/cmake/compiler.cmake +++ b/cmake/compiler.cmake @@ -8,11 +8,19 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHc") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") - - # edit and continue + if(CMAKE_BUILD_TYPE STREQUAL "Debug") - message(STATUS "Disabling /SAFESEH") + # disabling SAFESEH + message(STATUS "Disabling Safe Exception Handlers..") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") + + # edit and continue + message(STATUS "Enabling Edit and Continue..") + add_definitions(/ZI) + + # incremental linking + message(STATUS "Enabling Incremental Linking..") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /INCREMENTAL") endif() endif() diff --git a/scripts/chai/CmnDef/CmnDefInnBed.chai b/scripts/chai/CmnDef/CmnDefInnBed.chai index 4ea1ba9c..64b72573 100644 --- a/scripts/chai/CmnDef/CmnDefInnBed.chai +++ b/scripts/chai/CmnDef/CmnDefInnBed.chai @@ -40,7 +40,7 @@ class CmnDefInnBedDef def Scene00100( player ) //Wake up { - player.eventPlay( this.id, 100, 0xF32E48F8/*flags*/, 0/*unk*/, 0/*unk*/, + player.eventPlay( this.id, 100, 0x800/*flags*/, 0/*unk*/, 0/*unk*/, fun( player, eventId, param1, param2, param3 ) { @@ -59,4 +59,4 @@ class CmnDefInnBedDef }; -GLOBAL CmnDefInnBed = CmnDefInnBedDef(); \ No newline at end of file +GLOBAL CmnDefInnBed = CmnDefInnBedDef(); diff --git a/sql/infolinkshell.sql b/sql/infolinkshell.sql index 66e7b224..a9e54d6c 100644 --- a/sql/infolinkshell.sql +++ b/sql/infolinkshell.sql @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `infolinkshell`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `infolinkshell` ( - `LinkshellId` int(20) NOT NULL AUTO_INCREMENT, + `LinkshellId` bigint(20) NOT NULL AUTO_INCREMENT, `MasterCharacterId` int(20) DEFAULT NULL, `CharacterIdList` blob, `LinkshellName` varchar(32) DEFAULT NULL, diff --git a/src/servers/Server_Common/Common.h b/src/servers/Server_Common/Common.h index f608e8bc..1229e02e 100644 --- a/src/servers/Server_Common/Common.h +++ b/src/servers/Server_Common/Common.h @@ -572,7 +572,8 @@ namespace Core { MpGain = 11, TpLoss = 12, TpGain = 13, - GpGain = 14 + GpGain = 14, + Mount = 38 }; enum class ActionHitSeverityType : uint8_t @@ -921,10 +922,11 @@ namespace Core { GearSetEquipMsg = 0x321, - ToggleOrchestrionUnlock = 0x396 + ToggleOrchestrionUnlock = 0x396, + Dismount = 0x3a0 }; - enum struct ChatType : uint32_t + enum struct ChatType : uint16_t { LogKindError, ServerDebug, @@ -1038,6 +1040,12 @@ namespace Core { Visor = 0x40, }; + enum SkillType : uint8_t + { + Normal = 0x1, + MountSkill = 0xD, + }; + struct ServerEntry { uint32_t serverId; diff --git a/src/servers/Server_Common/Crypt/base64.cpp b/src/servers/Server_Common/Crypt/base64.cpp index 3ad4db0d..8037dec4 100644 --- a/src/servers/Server_Common/Crypt/base64.cpp +++ b/src/servers/Server_Common/Crypt/base64.cpp @@ -93,7 +93,7 @@ std::string Core::Util::base64_decode( std::string const& encoded_string ) { char_array_4[i++] = encoded_string[in_]; in_++; if( i == 4 ) { for( i = 0; i < 4; i++ ) - char_array_4[i] = base64_chars.find( char_array_4[i] ); + char_array_4[i] = static_cast< uint8_t >( base64_chars.find( char_array_4[i] ) ); char_array_3[0] = ( char_array_4[0] << 2 ) + ( ( char_array_4[1] & 0x30 ) >> 4 ); char_array_3[1] = ( ( char_array_4[1] & 0xf ) << 4 ) + ( ( char_array_4[2] & 0x3c ) >> 2 ); @@ -110,7 +110,7 @@ std::string Core::Util::base64_decode( std::string const& encoded_string ) { char_array_4[j] = 0; for( j = 0; j < 4; j++ ) - char_array_4[j] = base64_chars.find( char_array_4[j] ); + char_array_4[j] = static_cast< uint8_t >( base64_chars.find( char_array_4[j] ) ); char_array_3[0] = ( char_array_4[0] << 2 ) + ( ( char_array_4[1] & 0x30 ) >> 4 ); char_array_3[1] = ( ( char_array_4[1] & 0xf ) << 4 ) + ( ( char_array_4[2] & 0x3c ) >> 2 ); diff --git a/src/servers/Server_Common/Exd/ExdData.cpp b/src/servers/Server_Common/Exd/ExdData.cpp index f7822502..9ac2197a 100644 --- a/src/servers/Server_Common/Exd/ExdData.cpp +++ b/src/servers/Server_Common/Exd/ExdData.cpp @@ -88,7 +88,7 @@ bool Core::Data::ExdData::loadZoneInfo() uint16_t weather_rate = getField< uint16_t >( fields, 10 ) > 75 ? 0 : getField< uint16_t >( fields, 10 ); auto weatherRateFields = weatherRate.get_row( weather_rate ); - int32_t aetheryte_index = getField< int32_t >( fields, 20 ); + int32_t aetheryte_index = getField< int32_t >( fields, 23 ); ZoneInfo info{ 0 }; diff --git a/src/servers/Server_Common/Network/GamePacket.cpp b/src/servers/Server_Common/Network/GamePacket.cpp index f468e90d..c67f4fb6 100644 --- a/src/servers/Server_Common/Network/GamePacket.cpp +++ b/src/servers/Server_Common/Network/GamePacket.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "Server_Common/Util/Util.h" Core::Network::Packets::GamePacket::GamePacket( uint16_t subType, uint16_t size, uint32_t id1, uint32_t id2, uint16_t type ) { @@ -97,16 +98,5 @@ void Core::Network::Packets::GamePacket::savePacket() std::string Core::Network::Packets::GamePacket::toString() const { - - std::string str = "\n"; - for( uint32_t i = 0; i < getSize(); i++ ) - { - str += boost::str( boost::format( "%|02X|" ) % ( int32_t ) ( m_dataBuf[i] & 0xFF ) ) + " "; - - if( ( i + 1 ) % 16 == 0 ) - str += "\n"; - } - str += "\n"; - - return str; + return Core::Util::binaryToHexDump( const_cast( &m_dataBuf[0] ), getSize() ); } diff --git a/src/servers/Server_Common/Network/PacketDef/Ipcs.h b/src/servers/Server_Common/Network/PacketDef/Ipcs.h index 84cc7db2..da8be023 100644 --- a/src/servers/Server_Common/Network/PacketDef/Ipcs.h +++ b/src/servers/Server_Common/Network/PacketDef/Ipcs.h @@ -46,7 +46,7 @@ namespace Packets { { Ping = 0x0065, Init = 0x0066, - Chat = 0x0067, + Chat = 0x00B9, ChatBanned = 0x006B, Logout = 0x0077, CFNotify = 0x0078, @@ -73,15 +73,13 @@ namespace Packets { Effect = 0x00FB, // updated 4.1 GCAffiliation = 0x00FC, - HateList = 0x011A, PlayerSpawn = 0x011C, // updated 4.1 NpcSpawn = 0x011D, // updated 4.1 ActorMove = 0x011E, // updated 4.1 - - UpdateClassInfo = 0x111D, - ActorSetPos = 0x0120, // updated 4.1 ActorCast = 0x0123, // updated 4.1 + HateList = 0x0126, // updated 4.1 + UpdateClassInfo = 0x012A, // updated 4.1 InitUI = 0x012B, // updated 4.1 ActorOwner = 0x012D, // updated 4.1 PlayerStats = 0x0138, // updated 4.1 @@ -103,9 +101,6 @@ namespace Packets { InventoryActionAck = 0x1139, UpdateInventorySlot = 0x0153, // updated 4.1 - - - EventPlay = 0x0160, // updated 4.1 EventStart = 0x0169, // updated 4.1 EventFinish = 0x016A, // updated 4.1 @@ -119,11 +114,11 @@ namespace Packets { QuestFinish = 0x0180, // updated 4.1 - QuestTracker = 0x018D, // updated 4.1 ActorSpawn = 0x0190, // todo: split into playerspawn/actorspawn and use opcode 0x110/0x111 ActorFreeSpawn = 0x0191, // unchanged for sb InitZone = 0x019A, // unchanged for sb + Mount = 0x019F, WeatherChange = 0x01AF, // updated for sb PlayerTitleList = 0x01BD, // updated for 4.1 Discovery = 0x01BE, // updated for 4.1 diff --git a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h index c715b588..d5cb7675 100644 --- a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h @@ -42,8 +42,8 @@ struct FFXIVIpcInit : FFXIVIpcBasePacket */ struct FFXIVIpcChat : FFXIVIpcBasePacket { - /* 0000 */ Common::ChatType chatType; - uint8_t padding[16]; //Maybe this is SubCode, or some kind of talker ID... + /* 0000 */ uint8_t padding[14]; //Maybe this is SubCode, or some kind of talker ID... + Common::ChatType chatType; char name[32]; char msg[1012]; }; @@ -81,7 +81,7 @@ struct FFXIVIpcPlayTime : FFXIVIpcBasePacket */ struct PlayerEntry { uint64_t contentId; - char bytes[12]; + uint8_t bytes[12]; uint16_t zoneId; uint16_t zoneId1; char bytes1[8]; @@ -604,7 +604,8 @@ struct FFXIVIpcActorSetPos : FFXIVIpcBasePacket struct FFXIVIpcActorCast : FFXIVIpcBasePacket { uint16_t action_id; - uint16_t unknown; + Common::SkillType skillType; + uint8_t unknown; uint32_t unknown_1; // Also action id float cast_time; uint32_t target_id; @@ -1303,6 +1304,15 @@ struct FFXIVIpcEquipDisplayFlags : FFXIVIpcBasePacket uint8_t bitmask; }; +/** +* Structural representation of the packet sent by the server +* to mount a player +*/ +struct FFXIVIpcMount : FFXIVIpcBasePacket +{ + uint32_t id; +}; + } /* Server */ } /* Packets */ diff --git a/src/servers/Server_Common/Util/Util.cpp b/src/servers/Server_Common/Util/Util.cpp index 83ad69e5..b92d61a9 100644 --- a/src/servers/Server_Common/Util/Util.cpp +++ b/src/servers/Server_Common/Util/Util.cpp @@ -1,9 +1,9 @@ #include "Util.h" #include +#include std::string Core::Util::binaryToHexString( uint8_t* pBinData, uint16_t size ) { - std::string outStr; for( uint32_t i = 0; i < size; i++ ) @@ -15,6 +15,67 @@ std::string Core::Util::binaryToHexString( uint8_t* pBinData, uint16_t size ) } +std::string Core::Util::binaryToHexDump( uint8_t* pBinData, uint16_t size ) +{ + int bytesPerLine = 16; + constexpr char hexChars[] = "0123456789ABCDEF"; + + int offsetBlock = 8 + 3; + int byteBlock = offsetBlock + bytesPerLine * 3 + ( bytesPerLine - 1 ) / 8 + 2; + int lineLength = byteBlock + bytesPerLine + 1; + + std::string line ( lineLength, ' ' ); + int numLines = ( size + bytesPerLine - 1 ) / bytesPerLine; + + + std::string outStr; + + for( uint32_t i = 0; i < size; i += bytesPerLine ) + { + line[0] = hexChars[( i >> 28 ) & 0xF]; + line[1] = hexChars[( i >> 24 ) & 0xF]; + line[2] = hexChars[( i >> 20 ) & 0xF]; + line[3] = hexChars[( i >> 16 ) & 0xF]; + line[4] = hexChars[( i >> 12 ) & 0xF]; + line[5] = hexChars[( i >> 8 ) & 0xF]; + line[6] = hexChars[( i >> 4 ) & 0xF]; + line[7] = hexChars[( i >> 0 ) & 0xF]; + + int hexColumn = offsetBlock; + int charColumn = byteBlock; + + for( int j = 0; j < bytesPerLine; j++ ) + { + if( j > 0 && ( j & 7 ) == 0) + { + hexColumn++; + } + + if( i + j >= size ) + { + line[hexColumn] = ' '; + line[hexColumn + 1] = ' '; + line[charColumn] = ' '; + } + else + { + uint8_t by = pBinData[i + j]; + line[hexColumn] = hexChars[( by >> 4 ) & 0xF]; + line[hexColumn + 1] = hexChars[by & 0xF]; + line[charColumn] = by < 32 ? '.' : static_cast( by ); + } + + hexColumn += 3; + charColumn++; + } + + outStr += line + "\n"; + } + + return outStr; + +} + uint64_t Core::Util::getTimeMs() { std::chrono::milliseconds epoch = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch()); diff --git a/src/servers/Server_Common/Util/Util.h b/src/servers/Server_Common/Util/Util.h index 306b3d94..2c38f55f 100644 --- a/src/servers/Server_Common/Util/Util.h +++ b/src/servers/Server_Common/Util/Util.h @@ -9,6 +9,8 @@ namespace Util { std::string binaryToHexString( uint8_t* pBinData, uint16_t size ); +std::string binaryToHexDump( uint8_t* pBinData, uint16_t size ); + uint64_t getTimeMs(); uint64_t getTimeSeconds(); diff --git a/src/servers/Server_Lobby/CMakeLists.txt b/src/servers/Server_Lobby/CMakeLists.txt index 198fdb19..8a1f35d3 100644 --- a/src/servers/Server_Lobby/CMakeLists.txt +++ b/src/servers/Server_Lobby/CMakeLists.txt @@ -20,11 +20,6 @@ set_target_properties(server_lobby PROPERTIES RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/" ) -if(MSVC) - message(STATUS "Enabling Edit and Continue..") - set_property(TARGET server_lobby APPEND_STRING PROPERTY COMPILE_FLAGS " /INCREMENTAL /ZI") -endif() - if (UNIX) target_link_libraries(server_lobby Common xivdat pthread mysqlclient mysqlConnector dl z) else() diff --git a/src/servers/Server_Lobby/GameConnection.cpp b/src/servers/Server_Lobby/GameConnection.cpp index 21f45ef3..a2b0d0b2 100644 --- a/src/servers/Server_Lobby/GameConnection.cpp +++ b/src/servers/Server_Lobby/GameConnection.cpp @@ -152,7 +152,7 @@ void Core::Network::GameConnection::getCharList( FFXIVARR_PACKET_RAW& packet, ui auto charList = g_restConnector.getCharList( ( char * )m_pSession->getSessionId() ); - int32_t charIndex = 0; + uint32_t charIndex = 0; for( uint8_t i = 0; i < 4; i++ ) { diff --git a/src/servers/Server_Lobby/ServerLobby.cpp b/src/servers/Server_Lobby/ServerLobby.cpp index 6c151da4..9d0a6d3c 100644 --- a/src/servers/Server_Lobby/ServerLobby.cpp +++ b/src/servers/Server_Lobby/ServerLobby.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -58,7 +59,8 @@ namespace Core { g_log.info( "===========================================================" ); g_log.info( "Sapphire Server Project " ); - g_log.info( "Version: x.y.z" ); + g_log.info( "Version: " + Version::VERSION ); + g_log.info( "Git Hash: " + Version::GIT_HASH ); g_log.info( "Compiled: " __DATE__ " " __TIME__ ); g_log.info( "===========================================================" ); @@ -89,7 +91,7 @@ namespace Core { return false; } std::vector args( argv + 1, argv + argc ); - for( auto i = 0; i + 1 < args.size(); i += 2 ) + for( size_t i = 0; i + 1 < args.size(); i += 2 ) { std::string arg( "" ); std::string val( "" ); diff --git a/src/servers/Server_Lobby/client_http.hpp b/src/servers/Server_Lobby/client_http.hpp index c7b9137b..656b8d01 100644 --- a/src/servers/Server_Lobby/client_http.hpp +++ b/src/servers/Server_Lobby/client_http.hpp @@ -266,7 +266,7 @@ namespace SimpleWeb { if( content_length>num_additional_bytes ) { auto timer = get_timeout_timer(); boost::asio::async_read( *socket, response->content_buffer, - boost::asio::transfer_exactly( content_length - num_additional_bytes ), + boost::asio::transfer_exactly( static_cast< size_t >( content_length - num_additional_bytes ) ), [this, timer]( const boost::system::error_code& ec, size_t /*bytes_transferred*/ ) { if( timer ) timer->cancel(); @@ -307,7 +307,7 @@ namespace SimpleWeb { line.pop_back(); std::streamsize length = stol( line, 0, 16 ); - auto num_additional_bytes = static_cast( response->content_buffer.size() - bytes_transferred ); + auto num_additional_bytes = response->content_buffer.size() - bytes_transferred; auto post_process = [this, &response, &streambuf, length] { std::ostream stream( &streambuf ); @@ -332,7 +332,7 @@ namespace SimpleWeb { if( ( 2 + length )>num_additional_bytes ) { auto timer = get_timeout_timer(); boost::asio::async_read( *socket, response->content_buffer, - boost::asio::transfer_exactly( 2 + length - num_additional_bytes ), + boost::asio::transfer_exactly( static_cast< size_t >( 2 + length - num_additional_bytes ) ), [this, post_process, timer]( const boost::system::error_code& ec, size_t /*bytes_transferred*/ ) { if( timer ) timer->cancel(); diff --git a/src/servers/Server_REST/CMakeLists.txt b/src/servers/Server_REST/CMakeLists.txt index 9edf1680..21e9db77 100644 --- a/src/servers/Server_REST/CMakeLists.txt +++ b/src/servers/Server_REST/CMakeLists.txt @@ -19,11 +19,6 @@ set_target_properties(server_rest PROPERTIES RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/" ) -if(MSVC) - message(STATUS "Enabling Edit and Continue..") - set_property(TARGET server_rest APPEND_STRING PROPERTY COMPILE_FLAGS " /INCREMENTAL /ZI") -endif() - if (UNIX) target_link_libraries (server_rest Common xivdat pthread mysqlclient mysqlConnector dl z) else() diff --git a/src/servers/Server_REST/PlayerMinimal.cpp b/src/servers/Server_REST/PlayerMinimal.cpp index bb14d319..3ec7f734 100644 --- a/src/servers/Server_REST/PlayerMinimal.cpp +++ b/src/servers/Server_REST/PlayerMinimal.cpp @@ -171,7 +171,7 @@ namespace Core { uint16_t size = static_cast< uint16_t >( m_lookMap.size() ); - for( int32_t i = 0; i < m_lookMap.size(); i++ ) + for( uint32_t i = 0; i < m_lookMap.size(); i++ ) { customize[i] = m_lookMap[i]; } diff --git a/src/servers/Server_REST/main.cpp b/src/servers/Server_REST/main.cpp index 153bfe86..e03a32d1 100644 --- a/src/servers/Server_REST/main.cpp +++ b/src/servers/Server_REST/main.cpp @@ -78,7 +78,7 @@ bool loadSettings( int32_t argc, char* argv[] ) } std::vector args( argv + 1, argv + argc ); - for( auto i = 0; i + 1 < args.size(); i += 2 ) + for( size_t i = 0; i + 1 < args.size(); i += 2 ) { std::string arg( "" ); std::string val( "" ); @@ -171,7 +171,7 @@ bool loadSettings( int32_t argc, char* argv[] ) params.port = m_pConfig->getValue< uint16_t >( "Settings.General.Mysql.Port", 3306 ); params.username = m_pConfig->getValue< std::string >( "Settings.General.Mysql.Username", "root" ); - server.config.port = std::stoul( m_pConfig->getValue( "Settings.General.HttpPort", "80" ) ); + server.config.port = static_cast< unsigned short >( std::stoul( m_pConfig->getValue( "Settings.General.HttpPort", "80" ) ) ); if( !g_database.initialize( params ) ) { @@ -619,7 +619,7 @@ int main(int argc, char* argv[]) auto path = boost::filesystem::canonical( web_root_path / "news.xml" ); //Check if path is within web_root_path if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) || - !equal( web_root_path.begin(), web_root_path.end(), path.begin() ) ) + !std::equal( web_root_path.begin(), web_root_path.end(), path.begin() ) ) throw invalid_argument( "path must be within root path" ); if( !( boost::filesystem::exists( path ) && boost::filesystem::is_regular_file( path ) ) ) throw invalid_argument( "file does not exist" ); @@ -660,7 +660,7 @@ int main(int argc, char* argv[]) auto path = boost::filesystem::canonical( web_root_path / "headlines.xml" ); //Check if path is within web_root_path if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) || - !equal( web_root_path.begin(), web_root_path.end(), path.begin() ) ) + !std::equal( web_root_path.begin(), web_root_path.end(), path.begin() ) ) throw invalid_argument( "path must be within root path" ); if( !( boost::filesystem::exists( path ) && boost::filesystem::is_regular_file( path ) ) ) throw invalid_argument( "file does not exist" ); @@ -705,7 +705,7 @@ int main(int argc, char* argv[]) auto path = boost::filesystem::canonical( web_root_path / request->path ); //Check if path is within web_root_path if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) || - !equal( web_root_path.begin(), web_root_path.end(), path.begin() ) ) + !std::equal( web_root_path.begin(), web_root_path.end(), path.begin() ) ) throw invalid_argument( "path must be within root path" ); if( boost::filesystem::is_directory( path ) ) path /= "index.html"; @@ -731,7 +731,7 @@ int main(int argc, char* argv[]) else throw invalid_argument( "could not read file" ); } - catch( const exception &e ) + catch( const exception & ) { string content = "Path not found: " + request->path; *response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << content.length() << "\r\n\r\n" << content; diff --git a/src/servers/Server_REST/server_http.hpp b/src/servers/Server_REST/server_http.hpp index 82ee541a..b8e8e8a9 100644 --- a/src/servers/Server_REST/server_http.hpp +++ b/src/servers/Server_REST/server_http.hpp @@ -273,7 +273,7 @@ namespace SimpleWeb { try { content_length=stoull(it->second); } - catch(const std::exception &e) { + catch( const std::exception & ) { if(on_error) on_error(request, boost::system::error_code(boost::system::errc::protocol_error, boost::system::generic_category())); return; @@ -282,7 +282,7 @@ namespace SimpleWeb { //Set timeout on the following boost::asio::async-read or write function auto timer=this->get_timeout_timer(socket, config.timeout_content); boost::asio::async_read(*socket, request->streambuf, - boost::asio::transfer_exactly(content_length-num_additional_bytes), + boost::asio::transfer_exactly(static_cast< size_t >(content_length-num_additional_bytes)), [this, socket, request, timer] (const boost::system::error_code& ec, size_t /*bytes_transferred*/) { if(timer) @@ -388,7 +388,7 @@ namespace SimpleWeb { try { http_version=stof(request->http_version); } - catch(const std::exception &e){ + catch( const std::exception & ){ if(on_error) on_error(request, boost::system::error_code(boost::system::errc::protocol_error, boost::system::generic_category())); return; @@ -410,7 +410,7 @@ namespace SimpleWeb { try { resource_function(response, request); } - catch(const std::exception &e) { + catch( const std::exception & ) { if(on_error) on_error(request, boost::system::error_code(boost::system::errc::operation_canceled, boost::system::generic_category())); return; diff --git a/src/servers/Server_Zone/Action/ActionCast.cpp b/src/servers/Server_Zone/Action/ActionCast.cpp index a28125c7..c27b9db2 100644 --- a/src/servers/Server_Zone/Action/ActionCast.cpp +++ b/src/servers/Server_Zone/Action/ActionCast.cpp @@ -53,7 +53,7 @@ void Core::Action::ActionCast::onStart() GamePacketNew< FFXIVIpcActorCast, ServerZoneIpcType > castPacket( m_pSource->getId() ); castPacket.data().action_id = m_id; - castPacket.data().unknown = 1; + castPacket.data().skillType = Common::SkillType::Normal; castPacket.data().unknown_1 = m_id; castPacket.data().cast_time = static_cast< float >( m_castTime / 1000 ); // This is used for the cast bar above the target bar of the caster. castPacket.data().target_id = m_pTarget->getId(); diff --git a/src/servers/Server_Zone/Action/ActionMount.cpp b/src/servers/Server_Zone/Action/ActionMount.cpp new file mode 100644 index 00000000..50462d19 --- /dev/null +++ b/src/servers/Server_Zone/Action/ActionMount.cpp @@ -0,0 +1,111 @@ +#include "ActionMount.h" + +#include +#include +#include +#include +#include + +#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket142.h" +#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h" +#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket144.h" +#include "src/servers/Server_Zone/Actor/Player.h" +#include "src/servers/Server_Zone/Script/ScriptManager.h" + +using namespace Core::Common; +using namespace Core::Network; +using namespace Core::Network::Packets; +using namespace Core::Network::Packets::Server; + +extern Core::Data::ExdData g_exdData; +extern Core::Logger g_log; +extern Core::Scripting::ScriptManager g_scriptMgr; + +Core::Action::ActionMount::ActionMount() +{ + m_handleActionType = Common::HandleActionType::Event; +} + +Core::Action::ActionMount::ActionMount( Entity::ActorPtr pActor, uint32_t mountId ) +{ + m_startTime = 0; + m_id = mountId; + m_handleActionType = HandleActionType::Spell; + m_castTime = 1000; + m_pSource = pActor; + m_bInterrupt = false; +} + +Core::Action::ActionMount::~ActionMount() +{ + +} + +void Core::Action::ActionMount::onStart() +{ + if( !m_pSource ) + return; + + m_pSource->getAsPlayer()->sendDebug( "ActionMount::onStart()" ); + m_startTime = Util::getTimeMs(); + + GamePacketNew< FFXIVIpcActorCast, ServerZoneIpcType > castPacket( m_pSource->getId() ); + + castPacket.data().action_id = m_id; + castPacket.data().skillType = Common::SkillType::MountSkill; + castPacket.data().unknown_1 = m_id; + castPacket.data().cast_time = static_cast< float >( m_castTime / 1000 ); // This is used for the cast bar above the target bar of the caster. + castPacket.data().target_id = m_pSource->getAsPlayer()->getId(); + + m_pSource->sendToInRangeSet( castPacket, true ); + m_pSource->getAsPlayer()->setStateFlag( PlayerStateFlag::Casting ); + m_pSource->getAsPlayer()->sendStateFlags(); + +} + +void Core::Action::ActionMount::onFinish() +{ + if( !m_pSource ) + return; + + auto pPlayer = m_pSource->getAsPlayer(); + pPlayer->sendDebug( "ActionMount::onFinish()" ); + + pPlayer->unsetStateFlag( PlayerStateFlag::Casting ); + pPlayer->sendStateFlags(); + + GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket(pPlayer->getId()); + effectPacket.data().targetId = pPlayer->getId(); + effectPacket.data().actionAnimationId = m_id; + effectPacket.data().unknown_62 = 13; // Affects displaying action name next to number in floating text + effectPacket.data().actionTextId = 4; + effectPacket.data().numEffects = 1; + effectPacket.data().rotation = Math::Util::floatToUInt16Rot(pPlayer->getRotation()); + effectPacket.data().effectTarget = INVALID_GAME_OBJECT_ID; + effectPacket.data().effects[0].effectType = ActionEffectType::Mount; + effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::CritDamage; + effectPacket.data().effects[0].value = m_id; + + pPlayer->sendToInRangeSet(effectPacket, true); + + pPlayer->mount( m_id ); +} + +void Core::Action::ActionMount::onInterrupt() +{ + if( !m_pSource ) + return; + + m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Occupied1 ); + m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Casting ); + m_pSource->getAsPlayer()->sendStateFlags(); + + auto control = ActorControlPacket142( m_pSource->getId(), ActorControlType::CastInterrupt, + 0x219, 1, m_id, 0 ); + + // Note: When cast interrupt from taking too much damage, set the last value to 1. This enables the cast interrupt effect. Example: + // auto control = ActorControlPacket142( m_pSource->getId(), ActorControlType::CastInterrupt, 0x219, 1, m_id, 0 ); + + m_pSource->sendToInRangeSet( control, true ); + +} diff --git a/src/servers/Server_Zone/Action/ActionMount.h b/src/servers/Server_Zone/Action/ActionMount.h new file mode 100644 index 00000000..cdd68e3d --- /dev/null +++ b/src/servers/Server_Zone/Action/ActionMount.h @@ -0,0 +1,28 @@ +#ifndef _ACTIONMOUNT_H_ +#define _ACTIONMOUNT_H_ + +#include "src/servers/Server_Zone/Forwards.h" +#include "Action.h" + +namespace Core { namespace Action { + + class ActionMount : public Action + { + private: + + public: + ActionMount(); + ~ActionMount(); + + ActionMount( Entity::ActorPtr pActor, uint32_t mountId ); + + void onStart() override; + void onFinish() override; + void onInterrupt() override; + + }; + +} +} + +#endif \ No newline at end of file diff --git a/src/servers/Server_Zone/Actor/Actor.cpp b/src/servers/Server_Zone/Actor/Actor.cpp index 33f20c6b..4c3addc8 100644 --- a/src/servers/Server_Zone/Actor/Actor.cpp +++ b/src/servers/Server_Zone/Actor/Actor.cpp @@ -685,7 +685,7 @@ void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint32_t actionId, u case ActionEffectType::Damage: { - effectPacket.data().effects[0].value = param1; + effectPacket.data().effects[0].value = static_cast< uint16_t >( param1 ); effectPacket.data().effects[0].effectType = ActionEffectType::Damage; effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage; effectPacket.data().effects[0].unknown_3 = 7; diff --git a/src/servers/Server_Zone/Actor/BattleNpc.cpp b/src/servers/Server_Zone/Actor/BattleNpc.cpp index d8f098e9..6e64015a 100644 --- a/src/servers/Server_Zone/Actor/BattleNpc.cpp +++ b/src/servers/Server_Zone/Actor/BattleNpc.cpp @@ -451,7 +451,7 @@ void Core::Entity::BattleNpc::onDeath() // todo: this is actually retarded, we need real rand() - srand( time( NULL ) ); + srand( static_cast< unsigned int> ( time( NULL ) ) ); auto pPlayer = pHateEntry->m_pActor->getAsPlayer(); pPlayer->gainExp( exp ); diff --git a/src/servers/Server_Zone/Actor/CalcBattle.cpp b/src/servers/Server_Zone/Actor/CalcBattle.cpp index 5bc0d252..ce2e3a84 100644 --- a/src/servers/Server_Zone/Actor/CalcBattle.cpp +++ b/src/servers/Server_Zone/Actor/CalcBattle.cpp @@ -38,7 +38,7 @@ float CalcBattle::calculateBaseStat( PlayerPtr pPlayer ) // SB Base Stat Formula (Aligned) if ( level > 60 ) { - base = ( ( ( level == 61 ) ? 224 : 220 ) + ( level - 61 ) * 8); + base = static_cast< float >( ( ( ( level == 61 ) ? 224 : 220 ) + ( level - 61 ) * 8) ); } // HW Base Stat Formula (Aligned) else if ( level > 50 ) @@ -77,7 +77,7 @@ uint32_t CalcBattle::calculateMaxHp( PlayerPtr pPlayer ) // These values are not precise. if ( level >= 60 ) - approxBaseHp = 2600 + ( level - 60 ) * 100; + approxBaseHp = static_cast< float >( 2600 + ( level - 60 ) * 100 ); else if ( level >= 50 ) approxBaseHp = 1700 + ( ( level - 50 ) * ( 1700 * 1.04325f ) ); else diff --git a/src/servers/Server_Zone/Actor/Player.cpp b/src/servers/Server_Zone/Actor/Player.cpp index 6bd7395b..c1bddb39 100644 --- a/src/servers/Server_Zone/Actor/Player.cpp +++ b/src/servers/Server_Zone/Actor/Player.cpp @@ -347,7 +347,7 @@ void Core::Entity::Player::teleport( uint16_t aetheryteId, uint8_t type ) void Core::Entity::Player::forceZoneing( uint32_t zoneId ) { - m_queuedZoneing = boost::make_shared< QueuedZoning >( zoneId, getPos(), Util::getTimeMs(), 0 ); + m_queuedZoneing = boost::make_shared< QueuedZoning >( zoneId, getPos(), Util::getTimeMs(), 0.f ); //performZoning( zoneId, Common::ZoneingType::None, getPos() ); } @@ -1439,6 +1439,33 @@ uint8_t Core::Entity::Player::getEquipDisplayFlags() const return m_equipDisplayFlags; } +void Core::Entity::Player::mount( uint32_t id ) +{ +// TODO: Fix me for SQL rewrite +/* m_mount = id; + sendToInRangeSet( ActorControlPacket142( getId(), ActorControlType::SetStatus, static_cast< uint8_t >( Entity::Actor::ActorStatus::Mounted )), true ); + sendToInRangeSet( ActorControlPacket143( getId(), 0x39e, 12 ), true ); //? + + GamePacketNew< FFXIVIpcMount, ServerZoneIpcType > mountPacket( getId() ); + mountPacket.data().id = m_mount; + sendToInRangeSet( mountPacket, true );*/ +} + +void Core::Entity::Player::dismount() +{ +// TODO: Fix me for SQL rewrite +/* sendToInRangeSet( ActorControlPacket142( getId(), ActorControlType::SetStatus, static_cast< uint8_t >( Entity::Actor::ActorStatus::Idle )), true ); + sendToInRangeSet( ActorControlPacket143( getId(), ActorControlType::Dismount, 1 ), true ); + m_mount = 0;*/ +} + +uint8_t Core::Entity::Player::getCurrentMount() const +{ +// TODO: Fix me for SQL rewrite +// return m_mount; + return 0; +} + void Core::Entity::Player::autoAttack( ActorPtr pTarget ) { diff --git a/src/servers/Server_Zone/Actor/Player.h b/src/servers/Server_Zone/Actor/Player.h index 32ab455a..ac607372 100644 --- a/src/servers/Server_Zone/Actor/Player.h +++ b/src/servers/Server_Zone/Actor/Player.h @@ -197,9 +197,9 @@ public: // Inventory / Item / Currency ////////////////////////////////////////////////////////////////////////////////////////////////////// /*! add an item to the first free slot in one of the 4 main containers */ - bool tryAddItem( uint16_t catalogId, uint16_t quantity ); + bool tryAddItem( uint16_t catalogId, uint32_t quantity ); /*! add an item to a given container */ - bool addItem( uint16_t containerId, uint16_t catalogId, uint16_t quantity ); + bool addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity ); /*! equip an item to a specified slot */ void equipItem( Inventory::EquipSlot equipSlotId, ItemPtr pItem, bool sendModel ); /*! remove an item from an equipment slot */ @@ -338,8 +338,14 @@ public: void setTitle( uint16_t titleId ); /*! change gear param state */ void setEquipDisplayFlags( uint8_t state ); - /*! get gear param state and send update to inRangeSet */ + /*! get gear param state */ uint8_t getEquipDisplayFlags() const; + /*! mount the specified mount and send the packets */ + void mount( uint32_t id ); + /*! dismount the current mount and send the packets */ + void dismount(); + /*! get the current mount */ + uint8_t getCurrentMount() const; void calculateStats() override; void sendStats(); diff --git a/src/servers/Server_Zone/Actor/PlayerInventory.cpp b/src/servers/Server_Zone/Actor/PlayerInventory.cpp index b5380d82..acc6632c 100644 --- a/src/servers/Server_Zone/Actor/PlayerInventory.cpp +++ b/src/servers/Server_Zone/Actor/PlayerInventory.cpp @@ -189,10 +189,10 @@ void Core::Entity::Player::removeCrystal( uint8_t type, uint32_t amount ) queuePacket( invUpPacket ); } -bool Core::Entity::Player::tryAddItem( uint16_t catalogId, uint16_t quantity ) +bool Core::Entity::Player::tryAddItem( uint16_t catalogId, uint32_t quantity ) { - for( uint8_t i = 0; i < 4; i++ ) + for( uint16_t i = 0; i < 4; i++ ) { if( m_pInventory->addItem( i, -1, catalogId, quantity ) != -1 ) { @@ -202,7 +202,7 @@ bool Core::Entity::Player::tryAddItem( uint16_t catalogId, uint16_t quantity ) return false; } -bool Core::Entity::Player::addItem( uint16_t containerId, uint16_t catalogId, uint16_t quantity ) +bool Core::Entity::Player::addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity ) { if( m_pInventory->addItem( containerId, -1, catalogId, quantity ) != -1 ) return true; diff --git a/src/servers/Server_Zone/Actor/PlayerQuest.cpp b/src/servers/Server_Zone/Actor/PlayerQuest.cpp index 8155ea3d..a3119bb7 100644 --- a/src/servers/Server_Zone/Actor/PlayerQuest.cpp +++ b/src/servers/Server_Zone/Actor/PlayerQuest.cpp @@ -864,7 +864,6 @@ void Core::Entity::Player::updateQuest( uint16_t questId, uint8_t sequence ) { if( hasQuest( questId ) ) { - uint8_t index = getQuestIndex( questId ); auto pNewQuest = m_activeQuests[index]; GamePacketNew< FFXIVIpcQuestUpdate, ServerZoneIpcType > pe_qa( getId() ); @@ -926,7 +925,7 @@ void Core::Entity::Player::sendQuestTracker() if( m_questTracking[ii] >= 0 ) { trackerPacket.data().entry[ii].active = 1; - trackerPacket.data().entry[ii].questIndex = m_questTracking[ii]; + trackerPacket.data().entry[ii].questIndex = static_cast< uint8_t >( m_questTracking[ii] ); } } queuePacket( trackerPacket ); @@ -1030,7 +1029,7 @@ bool Core::Entity::Player::giveQuestRewards( uint32_t questId, uint32_t optional exp = questInfo->reward_exp_factor; - uint16_t rewardItemCount = questInfo->reward_item.size(); + auto rewardItemCount = questInfo->reward_item.size(); uint16_t optionalItemCount = questInfo->reward_item_optional.size() > 0 ? 1 : 0; uint32_t gilReward = questInfo->reward_gil; diff --git a/src/servers/Server_Zone/CMakeLists.txt b/src/servers/Server_Zone/CMakeLists.txt index 53b40337..2c056c0a 100644 --- a/src/servers/Server_Zone/CMakeLists.txt +++ b/src/servers/Server_Zone/CMakeLists.txt @@ -35,11 +35,6 @@ set_target_properties(server_zone PROPERTIES RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/" ) -if(MSVC) - message(STATUS "Enabling Edit and Continue..") - set_property(TARGET server_zone APPEND_STRING PROPERTY COMPILE_FLAGS " /INCREMENTAL /ZI") -endif() - if (UNIX) target_link_libraries ( server_zone Common xivdat pthread mysqlclient mysqlConnector dl z ) else() diff --git a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp index 3a8805ed..0284a1e9 100644 --- a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp +++ b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp @@ -44,12 +44,13 @@ Core::DebugCommandHandler::DebugCommandHandler() registerCommand( "set", &DebugCommandHandler::set, "Loads and injects a premade Packet.", 1 ); registerCommand( "get", &DebugCommandHandler::get, "Loads and injects a premade Packet.", 1 ); registerCommand( "add", &DebugCommandHandler::add, "Loads and injects a premade Packet.", 1 ); - registerCommand( "inject", &DebugCommandHandler::injectPacket, "Loads and injects a premade Packet.", 1 ); - registerCommand( "injectc", &DebugCommandHandler::injectChatPacket, "Loads and injects a premade Packet.", 1 ); - registerCommand( "script_reload", &DebugCommandHandler::scriptReload, "Loads and injects a premade Packet.", 1 ); + registerCommand( "inject", &DebugCommandHandler::injectPacket, "Loads and injects a premade packet.", 1 ); + registerCommand( "injectc", &DebugCommandHandler::injectChatPacket, "Loads and injects a premade chat packet.", 1 ); + registerCommand( "script_reload", &DebugCommandHandler::scriptReload, "Reload all server scripts", 1 ); registerCommand( "nudge", &DebugCommandHandler::nudge, "Nudges you forward/up/down", 1 ); registerCommand( "info", &DebugCommandHandler::serverInfo, "Send server info", 0 ); - + registerCommand( "unlock", &DebugCommandHandler::unlockCharacter, "Unlock character", 1 ); + registerCommand( "help", &DebugCommandHandler::help, "Shows registered commands", 0 ); } // clear all loaded commands @@ -121,6 +122,18 @@ void Core::DebugCommandHandler::scriptReload( char * data, Core::Entity::PlayerP pPlayer->sendDebug( "Scripts reloaded." ); } +void Core::DebugCommandHandler::help( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr< Core::DebugCommand > command ) +{ + pPlayer->sendDebug( "Registered debug commands:" ); + for ( auto cmd : m_commandMap ) + { + if ( pPlayer->getGmRank( ) >= cmd.second->m_gmLevel ) + { + pPlayer->sendDebug( " - " + cmd.first + " - " + cmd.second->getHelpText( ) ); + } + } +} + void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlayer, boost::shared_ptr command ) { std::string subCommand = ""; @@ -258,6 +271,14 @@ void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlaye pPlayer->sendModel(); pPlayer->sendDebug( "Model updated" ); } + else if ( subCommand == "mount" ) + { + int32_t id; + sscanf( params.c_str(), "%d", &id ); + + pPlayer->dismount(); + pPlayer->mount( id ); + } else { pPlayer->sendUrgent( subCommand + " is not a valid SET command." ); @@ -494,3 +515,8 @@ void Core::DebugCommandHandler::serverInfo( char * data, Core::Entity::PlayerPtr pPlayer->sendDebug( "Compiled: " __DATE__ " " __TIME__ ); pPlayer->sendDebug( "Sessions: " + std::to_string( g_serverZone.getSessionCount() ) ); } + +void Core::DebugCommandHandler::unlockCharacter( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr< Core::DebugCommand > command ) +{ + pPlayer->unlock( ); +} diff --git a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.h b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.h index 12ff13b3..17dc3258 100644 --- a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.h +++ b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.h @@ -27,6 +27,9 @@ public: // execute command if registered void execCommand( char * data, Entity::PlayerPtr pPlayer ); + // help command + void help( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr command ); + // command handler callbacks void set( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr command ); void get( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr command ); @@ -39,6 +42,9 @@ public: void nudge( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr command ); void serverInfo( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr command ); + void unlockCharacter( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr command ); + void targetInfo( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr command ); + }; } diff --git a/src/servers/Server_Zone/Forwards.h b/src/servers/Server_Zone/Forwards.h index c0f48782..2eaaa75e 100644 --- a/src/servers/Server_Zone/Forwards.h +++ b/src/servers/Server_Zone/Forwards.h @@ -44,6 +44,7 @@ namespace Core TYPE_FORWARD( Action ); TYPE_FORWARD( ActionTeleport ); TYPE_FORWARD( ActionCast ); + TYPE_FORWARD( ActionMount ); TYPE_FORWARD( EventAction ); } diff --git a/src/servers/Server_Zone/Inventory/Inventory.cpp b/src/servers/Server_Zone/Inventory/Inventory.cpp index 2b552583..2a859076 100644 --- a/src/servers/Server_Zone/Inventory/Inventory.cpp +++ b/src/servers/Server_Zone/Inventory/Inventory.cpp @@ -108,7 +108,7 @@ Core::Inventory::InvSlotPairVec Core::Inventory::getSlotsOfItemsInInventory( uin for( auto item : inv->getItemMap() ) { if( item.second && item.second->getId() == catalogId ) - outVec.push_back( std::make_pair( i, item.first ) ); + outVec.push_back( std::make_pair( i, static_cast< int8_t >( item.first ) ) ); } } return outVec; @@ -118,7 +118,7 @@ Core::Inventory::InvSlotPair Core::Inventory::getFreeBagSlot() { for( auto i : { Bag0, Bag1, Bag2, Bag3 } ) { - int16_t freeSlot = m_inventoryMap[i]->getFreeSlot(); + auto freeSlot = static_cast< int8_t >( m_inventoryMap[i]->getFreeSlot() ); if( freeSlot != -1 ) return std::make_pair( i, freeSlot ); @@ -457,7 +457,7 @@ int16_t Core::Inventory::addItem( uint16_t inventoryId, int8_t slotId, uint32_t return -1; } - int16_t rSlotId = -1; + int8_t rSlotId = -1; //if( itemInfo->stack_size > 1 ) //{ diff --git a/src/servers/Server_Zone/Linkshell/LinkshellMgr.cpp b/src/servers/Server_Zone/Linkshell/LinkshellMgr.cpp index 077f42d0..ffcfc9af 100644 --- a/src/servers/Server_Zone/Linkshell/LinkshellMgr.cpp +++ b/src/servers/Server_Zone/Linkshell/LinkshellMgr.cpp @@ -29,7 +29,7 @@ bool Core::LinkshellMgr::loadLinkshells() do { - uint32_t linkshellId = field[0].get< uint32_t >(); + uint64_t linkshellId = field[0].get< uint64_t >(); uint32_t masterId = field[1].get< uint32_t >(); std::string name = field[3].getString(); diff --git a/src/servers/Server_Zone/Linkshell/LinkshellMgr.h b/src/servers/Server_Zone/Linkshell/LinkshellMgr.h index d5083506..8237bb55 100644 --- a/src/servers/Server_Zone/Linkshell/LinkshellMgr.h +++ b/src/servers/Server_Zone/Linkshell/LinkshellMgr.h @@ -12,7 +12,7 @@ typedef boost::shared_ptr< Linkshell > LinkshellPtr; class LinkshellMgr { private: - std::map< uint32_t, LinkshellPtr > m_linkshellIdMap; + std::map< uint64_t, LinkshellPtr > m_linkshellIdMap; std::map< std::string, LinkshellPtr > m_linkshellNameMap; LinkshellPtr getLinkshellByName( const std::string& name ); diff --git a/src/servers/Server_Zone/Network/GameConnection.cpp b/src/servers/Server_Zone/Network/GameConnection.cpp index f4c799e8..ec971e24 100644 --- a/src/servers/Server_Zone/Network/GameConnection.cpp +++ b/src/servers/Server_Zone/Network/GameConnection.cpp @@ -206,7 +206,7 @@ void Core::Network::GameConnection::handleZonePacket( const Packets::GamePacket& g_log.debug( sessionStr + " Undefined Zone IPC : Unknown ( " + boost::str( boost::format( "%|04X|" ) % static_cast< uint32_t >( pPacket.getSubType() & 0xFFFF ) ) + " )" ); - g_log.debug( pPacket.toString() ); + g_log.debug( "\n" + pPacket.toString() ); } } diff --git a/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp b/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp index cf0b030a..3254fec7 100644 --- a/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp +++ b/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp @@ -106,6 +106,11 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in pPlayer->changeTarget( targetId ); break; } + case 0x65: + { + pPlayer->dismount(); + break; + } case 0x68: // Remove status (clicking it off) { // todo: check if status can be removed by client from exd @@ -120,7 +125,7 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in } case 0x12E: // Set player title { - pPlayer->setTitle( param1 ); + pPlayer->setTitle( static_cast< uint16_t >( param1 ) ); break; } case 0x12F: // Get title list @@ -211,8 +216,8 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in auto fromAetheryte = g_exdData.getAetheryteInfo( g_exdData.m_zoneInfoMap[pPlayer->getZoneId()].aetheryte_index ); // calculate cost - does not apply for favorite points or homepoints neither checks for aether tickets - auto cost = ( sqrt( pow( fromAetheryte->map_coord_x - targetAetheryte->map_coord_x, 2 ) + - pow( fromAetheryte->map_coord_y - targetAetheryte->map_coord_y, 2 ) ) / 2 ) + 100; + auto cost = static_cast< uint16_t > ( ( sqrt( pow( fromAetheryte->map_coord_x - targetAetheryte->map_coord_x, 2 ) + + pow( fromAetheryte->map_coord_y - targetAetheryte->map_coord_y, 2 ) ) / 2 ) + 100 ); // cap at 999 gil cost = cost > 999 ? 999 : cost; diff --git a/src/servers/Server_Zone/Network/Handlers/EventHandlers.cpp b/src/servers/Server_Zone/Network/Handlers/EventHandlers.cpp index d310ffc4..e8c8ced0 100644 --- a/src/servers/Server_Zone/Network/Handlers/EventHandlers.cpp +++ b/src/servers/Server_Zone/Network/Handlers/EventHandlers.cpp @@ -141,7 +141,7 @@ void Core::Network::GameConnection::eventHandler( const Packets::GamePacket& inP GamePacketNew< FFXIVIpcEventLinkshell, ServerZoneIpcType > linkshellEvent( pPlayer->getId() ); linkshellEvent.data().eventId = eventId; - linkshellEvent.data().scene = subEvent; + linkshellEvent.data().scene = static_cast< uint8_t >(subEvent); linkshellEvent.data().param3 = 1; linkshellEvent.data().unknown1 = 0x15a; pPlayer->queuePacket( linkshellEvent ); diff --git a/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp b/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp index 231f9b00..e2a09f87 100644 --- a/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp +++ b/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp @@ -282,13 +282,16 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac } case GmCommand::Teri: { - if( param1 < 128 ) - pPlayer->sendUrgent( "Zone ID out of range." ); + auto zoneInfo = g_zoneMgr.getZone( param1 ); + if ( !zoneInfo ) + { + pPlayer->sendUrgent( "Invalid zone " + std::to_string( param1 ) ); + } else { targetPlayer->setPosition( targetPlayer->getPos() ); targetPlayer->performZoning( param1, targetPlayer->getPos(), 0 ); - pPlayer->sendNotice( targetPlayer->getName() + " was warped to Zone " + std::to_string( param1 ) ); + pPlayer->sendNotice( targetPlayer->getName() + " was warped to zone " + std::to_string( param1 ) + " (" + zoneInfo->getName( ) + ")" ); } break; } diff --git a/src/servers/Server_Zone/Network/Handlers/SkillHandler.cpp b/src/servers/Server_Zone/Network/Handlers/SkillHandler.cpp index 457aa855..e83219f0 100644 --- a/src/servers/Server_Zone/Network/Handlers/SkillHandler.cpp +++ b/src/servers/Server_Zone/Network/Handlers/SkillHandler.cpp @@ -25,9 +25,10 @@ #include "src/servers/Server_Zone/Forwards.h" #include "src/servers/Server_Zone/Action/Action.h" -#include "src/servers/Server_Zone/Action/ActionTeleport.h" #include "src/servers/Server_Zone/Action/ActionCast.h" +#include "src/servers/Server_Zone/Action/ActionMount.h" #include "src/servers/Server_Zone/Script/ScriptManager.h" +#include "Server_Zone/Network/PacketWrappers/MoveActorPacket.h" extern Core::Scripting::ScriptManager g_scriptMgr; @@ -41,12 +42,19 @@ using namespace Core::Network::Packets::Server; void Core::Network::GameConnection::skillHandler( const Packets::GamePacket& inPacket, Entity::PlayerPtr pPlayer ) { + uint8_t type = inPacket.getValAt< uint32_t >( 0x21 ); uint32_t action = inPacket.getValAt< uint32_t >( 0x24 ); uint32_t useCount = inPacket.getValAt< uint32_t >( 0x28 ); uint64_t targetId = inPacket.getValAt< uint64_t >( 0x30 ); + pPlayer->sendDebug( "Skill type:" + std::to_string( type ) ); + + switch( type ) + { + case Common::SkillType::Normal: + if( action < 1000000 ) // normal action { std::string actionIdStr = boost::str( boost::format( "%|04X|" ) % action ); @@ -104,4 +112,19 @@ void Core::Network::GameConnection::skillHandler( const Packets::GamePacket& inP } + break; + + case Common::SkillType::MountSkill: + + pPlayer->sendDebug( "Request mount " + std::to_string( action ) ); + + Action::ActionMountPtr pActionMount( new Action::ActionMount(pPlayer, action) ); + pPlayer->setCurrentAction( pActionMount ); + pPlayer->sendDebug("setCurrentAction()"); + pPlayer->getCurrentAction()->onStart(); + + break; + + } + } \ No newline at end of file diff --git a/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h b/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h index 60b69f1d..e28f87e1 100644 --- a/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h +++ b/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h @@ -64,6 +64,9 @@ private: memcpy( m_data.orchestrionMask, player->getOrchestrionBitmask(), sizeof( m_data.orchestrionMask ) ); + memset( m_data.mountGuideMask, 0xFF, sizeof( m_data.mountGuideMask) ); + memset( m_data.fishingGuideMask, 0xFF, sizeof( m_data.fishingGuideMask ) ); + memcpy( m_data.unlockBitmask, player->getUnlockBitmask(), sizeof( m_data.unlockBitmask ) ); memcpy( m_data.discovery, player->getDiscoveryBitmask(), sizeof( m_data.discovery ) ); diff --git a/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h b/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h index f96160f6..1c3e8eed 100644 --- a/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h +++ b/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h @@ -111,6 +111,8 @@ namespace Server { m_data.displayFlags |= Entity::Actor::DisplayFlags::Visor; } + m_data.currentMount = pPlayer->getCurrentMount(); + m_data.targetId = pPlayer->getTargetId(); //m_data.type = 1; //m_data.unknown_33 = 4; diff --git a/src/servers/Server_Zone/Script/ScriptManager.cpp b/src/servers/Server_Zone/Script/ScriptManager.cpp index 61c331bd..bc42558c 100644 --- a/src/servers/Server_Zone/Script/ScriptManager.cpp +++ b/src/servers/Server_Zone/Script/ScriptManager.cpp @@ -91,7 +91,7 @@ bool Core::Scripting::ScriptManager::onTalk( Core::Entity::PlayerPtr pPlayer, ui std::string objName = Event::getEventName( eventId ); pPlayer->sendDebug("Actor: " + - std::to_string( actorId ) + + std::to_string( actorId ) + " -> " + std::to_string( Core::Event::mapEventActorToRealActor( static_cast< uint32_t >( actorId ) ) ) + " \neventId: " + std::to_string( eventId ) + " (0x" + boost::str( boost::format( "%|08X|" ) @@ -114,18 +114,18 @@ bool Core::Scripting::ScriptManager::onTalk( Core::Entity::PlayerPtr pPlayer, ui } catch( std::exception& e ) { + pPlayer->sendDebug( e.what( ) ); if( eventType == Common::EventType::Quest ) { auto questInfo = g_exdData.getQuestInfo( eventId ); if( questInfo ) { - pPlayer->sendDebug( "Quest not implemented: " + questInfo->name + "\n" + e.what() ); + pPlayer->sendUrgent( "Quest not implemented: " + questInfo->name ); return false; } } - pPlayer->sendDebug( e.what() ); return false; } return true; diff --git a/src/servers/Server_Zone/Script/ScriptManagerInit.cpp b/src/servers/Server_Zone/Script/ScriptManagerInit.cpp index d36a7dbe..55c2135f 100644 --- a/src/servers/Server_Zone/Script/ScriptManagerInit.cpp +++ b/src/servers/Server_Zone/Script/ScriptManagerInit.cpp @@ -52,6 +52,7 @@ int Core::Scripting::ScriptManager::init() m_pChaiHandler->add( chaiscript::fun( &Entity::Player::returnToHomepoint ), "returnToHomepoint" ); m_pChaiHandler->add( chaiscript::fun( &Entity::Player::teleport ), "teleport" ); m_pChaiHandler->add( chaiscript::fun( &Entity::Player::prepareZoning ), "prepareZoning" ); + m_pChaiHandler->add( chaiscript::fun( &Entity::Player::isInCombat ), "isInCombat" ); m_pChaiHandler->add( chaiscript::fun( &Entity::Player::getCurrency ), "getCurrency" ); m_pChaiHandler->add( chaiscript::fun( &Entity::Player::addCurrency ), "addCurrency" ); diff --git a/src/servers/Server_Zone/ServerZone.cpp b/src/servers/Server_Zone/ServerZone.cpp index ab57f760..8e64737c 100644 --- a/src/servers/Server_Zone/ServerZone.cpp +++ b/src/servers/Server_Zone/ServerZone.cpp @@ -4,6 +4,7 @@ #include "ServerZone.h" +#include #include #include #include @@ -375,7 +376,8 @@ void Core::ServerZone::printBanner() const { g_log.info("===========================================================" ); g_log.info( "Sapphire Server Project " ); - g_log.info( "Version: x.y.z" ); + g_log.info( "Version: " + Version::VERSION ); + g_log.info( "Git Hash: " + Version::GIT_HASH ); g_log.info( "Compiled: " __DATE__ " " __TIME__ ); g_log.info( "===========================================================" ); } diff --git a/src/tools/exd_common_gen/CMakeLists.txt b/src/tools/exd_common_gen/CMakeLists.txt index 2d5839d9..986a5342 100644 --- a/src/tools/exd_common_gen/CMakeLists.txt +++ b/src/tools/exd_common_gen/CMakeLists.txt @@ -27,6 +27,9 @@ if (UNIX) target_link_libraries (exd_common_gen Common xivdat pthread mysqlclient dl z) else() target_link_libraries (exd_common_gen Common xivdat libmysql zlib1) + + # ignore unchecked iterators warnings from msvc + add_definitions(-D_SCL_SECURE_NO_WARNINGS) endif() target_link_libraries(exd_common_gen ${Boost_LIBRARIES} ${Boost_LIBRARIES}) diff --git a/src/tools/pcb_reader/CMakeLists.txt b/src/tools/pcb_reader/CMakeLists.txt index 9bd07e39..a73b4816 100644 --- a/src/tools/pcb_reader/CMakeLists.txt +++ b/src/tools/pcb_reader/CMakeLists.txt @@ -1,23 +1,39 @@ -set( CMAKE_CXX_FLAGS "-std=c++11 -m32") +cmake_minimum_required(VERSION 2.6) +cmake_policy(SET CMP0015 NEW) +project(Tool_pcb_reader2) -include_directories("../../") +set(SAPPHIRE_BOOST_VER 1.63.0) +set(SAPPHIRE_BOOST_FOLDER_NAME boost_1_63_0) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/") + +include_directories("../../lib/ChaiScript-6.0.0/include/") + +include_directories("../../sapphire/datReader/") +include_directories("../../sapphire/") include_directories("../") file(GLOB SERVER_PUBLIC_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*") -file(GLOB SERVER_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}*.cpp") +file(GLOB SERVER_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}*.c*") -SET(Boost_USE_STATIC_LIBS ON) -set(Boost_INCLUDE_DIR /opt/build_libs/boost_1_60_0) -set(Boost_LIBRARY_DIR /opt/build_libs/boost_1_60_0/stage/lib) -set(SERVER_COMMON_DIR ../../servers/Server_Common) -find_package(Boost COMPONENTS log log_setup thread date_time filesystem system REQUIRED) -include_directories(${Boost_INCLUDE_DIR}) -link_directories(${Boost_LIBRARY_DIR}) -link_directories(${SERVER_COMMON_DIR}) -#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ".") -add_executable(pcb_parser2 ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES}) +#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "../bin/") +add_executable(pcb_reader2 ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES}) -target_link_libraries (pcb_parser2 server_common.a pthread mysqlclient dl z) -target_link_libraries(pcb_parser2 ${Boost_LIBRARIES} ${Boost_LIBRARIES}) +set_target_properties(pcb_reader2 PROPERTIES + CXX_STANDARD 14 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS ON + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../bin/" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../bin/" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../bin/" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../bin/" +) + +if (UNIX) + target_link_libraries (pcb_reader2 Common xivdat pthread mysqlclient dl z) +else() + target_link_libraries (pcb_reader2 Common xivdat libmysql zlib1) +endif() + +target_link_libraries(pcb_reader2 ${Boost_LIBRARIES} ${Boost_LIBRARIES}) diff --git a/src/tools/pcb_reader/lgb.h b/src/tools/pcb_reader/lgb.h new file mode 100644 index 00000000..eb337ef6 --- /dev/null +++ b/src/tools/pcb_reader/lgb.h @@ -0,0 +1,280 @@ +#ifndef _LGB_H +#define _LGB_H + +#include +#include +#include +#include +#include +#include +#include + +#include "matrix4.h" +#include "vec3.h" +#include "sgb.h" + +// all credit to +// https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Lgb/ +// this is simply their work ported to c++ since we dont c# +struct LGB_FILE; +struct LGB_FILE_HEADER; +struct LGB_GROUP; +struct LGB_GROUP_HEADER; + +enum class LgbEntryType : uint32_t +{ + BgParts = 1, + Light = 3, + Vfx = 4, + PositionMarker = 5, + Gimmick = 6, + SharedGroup6 = 6,// secondary variable is set to 2 + Sound = 7, + EventNpc = 8, + BattleNpc = 9, + Aetheryte = 12, + EnvSpace = 13, + Gathering = 14, + SharedGroup15 = 15,// secondary variable is set to 13 + Treasure = 16, + Weapon = 39, + PopRange = 40, + ExitRange = 41, + MapRange = 43, + NaviMeshRange = 44, + EventObject = 45, + EnvLocation = 47, + EventRange = 49, + QuestMarker = 51, + CollisionBox = 57, + DoorRange = 58, + LineVfx = 59, + ClientPath = 65, + ServerPath = 66, + GimmickRange = 67, + TargetMarker = 68, + ChairMarker = 69, + ClickableRange = 70, + PrefetchRange = 71, + FateRange = 72, + SphereCastRange = 75, +}; + +class LGB_MODEL_ENTRY +{ +public: + char* m_buf; + uint32_t m_offset; + + LGB_MODEL_ENTRY() + { + m_buf = nullptr; + m_offset = 0; + }; + LGB_MODEL_ENTRY( char* buf, uint32_t offset ) + { + m_buf = buf; + m_offset = offset; + }; + virtual ~LGB_MODEL_ENTRY() {}; +}; + + +struct LGB_BGPARTS_HEADER +{ + LgbEntryType type; + uint32_t unknown2; + uint32_t nameOffset; + vec3 translation; + vec3 rotation; + vec3 scale; + uint32_t modelFileOffset; + uint32_t collisionFileOffset; + uint32_t unknown4; + uint32_t unknown5; + uint32_t unknown6; + uint32_t unknown7; + uint32_t unknown8; + uint32_t unknown9; +}; + +class LGB_BGPARTS_ENTRY : public LGB_MODEL_ENTRY +{ +public: + LGB_BGPARTS_HEADER header; + std::string name; + std::string modelFileName; + std::string collisionFileName; + LGB_BGPARTS_ENTRY() {}; + LGB_BGPARTS_ENTRY( char* buf, uint32_t offset ) + { + header = *reinterpret_cast( buf + offset ); + name = std::string( buf + offset + header.nameOffset ); + modelFileName = std::string( buf + offset + header.modelFileOffset ); + collisionFileName = std::string( buf + offset + header.collisionFileOffset ); + //std::cout << "BGPARTS_ENTRY " << name << "\n"; + //std::cout << " " << modelFileName << "\n"; + //std::cout << " " << collisionFileName << "\n"; + }; +}; + +struct LGB_GIMMICK_HEADER +{ + LgbEntryType type; + uint32_t unknown; + uint32_t nameOffset; + vec3 translation; + vec3 rotation; + vec3 scale; + uint32_t gimmickFileOffset; + char unknownBytes[100]; +}; + +class LGB_GIMMICK_ENTRY : public LGB_MODEL_ENTRY +{ +public: + LGB_GIMMICK_HEADER header; + std::string name; + std::string gimmickFileName; + + LGB_GIMMICK_ENTRY( char* buf, uint32_t offset ) + { + header = *reinterpret_cast( buf + offset ); + name = std::string( buf + offset + header.nameOffset ); + gimmickFileName = std::string( buf + offset + header.gimmickFileOffset ); + }; +}; + +struct LGB_GROUP_HEADER +{ + uint32_t unknown; + int32_t groupNameOffset; + int32_t entriesOffset; + int32_t entryCount; + uint32_t unknown2; + uint32_t unknown3; + uint32_t unknown4; + uint32_t unknown5; + uint32_t unknown6; + uint32_t unknown7; + uint32_t unknown8; + uint32_t unknown9; + uint32_t unknown10; +}; + +struct LGB_GROUP +{ + LGB_FILE* parent; + LGB_GROUP_HEADER header; + std::string name; + std::vector> entries; + + LGB_GROUP( char* buf, LGB_FILE* parentStruct, uint32_t offset ) + { + parent = parentStruct; + header = *reinterpret_cast( buf + offset ); + name = std::string( buf + offset + header.groupNameOffset ); + //entries.resize( header.entryCount ); + //std::cout << name << std::endl; + const auto entriesOffset = offset + header.entriesOffset; + for( auto i = 0; i < header.entryCount; ++i ) + { + const auto entryOffset = entriesOffset + *reinterpret_cast( buf + ( entriesOffset + i * 4 ) ); + + try + { + const auto type = *reinterpret_cast( buf + entryOffset ); + if( type == LgbEntryType::BgParts ) + { + entries.push_back( std::make_shared( buf, entryOffset ) ); + } + else if( type == LgbEntryType::Gimmick ) + { + entries.push_back( std::make_shared( buf, entryOffset ) ); + } + /* + else + { + //entries[i] = nullptr; + } + */ + } + catch( std::exception& e ) + { + std::cout << name << " " << e.what() << std::endl; + } + } + }; +}; + +struct LGB_FILE_HEADER +{ + char magic[4]; // LGB 1 + uint32_t fileSize; + uint32_t unknown; + char magic2[4]; // LGP1 + uint32_t unknown2; + uint32_t unknown3; + uint32_t unknown4; + uint32_t unknown5; + int32_t groupCount; +}; + +struct LGB_FILE +{ + LGB_FILE_HEADER header; + std::vector groups; + + LGB_FILE( char* buf ) + { + header = *reinterpret_cast( buf ); + if( strncmp( &header.magic[0], "LGB1", 4 ) != 0 || strncmp( &header.magic2[0], "LGP1", 4 ) != 0 ) + throw std::runtime_error( "Invalid LGB file!" ); + + //groups.resize(header.groupCount); + + constexpr auto baseOffset = sizeof( header ); + for( auto i = 0; i < header.groupCount; ++i ) + { + const auto groupOffset = baseOffset + *reinterpret_cast( buf + ( baseOffset + i * 4 ) ); + const auto group = LGB_GROUP( buf, this, groupOffset ); + groups.push_back( group ); + } + }; +}; + +/* +#if __cplusplus >= 201703L +#include +std::map getLgbFiles( const std::string& dir ) +{ + namespace fs = std::experimental::filesystem; + std::map fileMap; + for( const auto& path : fs::recursive_directory_iterator( dir ) ) + { + if( path.path().extension() == ".lgb" ) + { + const auto& strPath = path.path().string(); + auto f = fopen( strPath.c_str(), "rb" ); + fseek( f, 0, SEEK_END ); + const auto size = ftell( f ); + std::vector bytes( size ); + rewind( f ); + fread( bytes.data(), 1, size, f ); + fclose( f ); + try + { + LGB_FILE lgbFile( bytes.data() ); + fileMap.insert( std::make_pair( strPath, lgbFile ) ); + } + catch( std::exception& e ) + { + std::cout << "Unable to load " << strPath << std::endl; + } + } + } + return fileMap; +} +#endif +*/ +#endif diff --git a/src/tools/pcb_reader/main.cpp b/src/tools/pcb_reader/main.cpp index 6da22cd5..647d08e5 100644 --- a/src/tools/pcb_reader/main.cpp +++ b/src/tools/pcb_reader/main.cpp @@ -1,10 +1,28 @@ #include -#include -#include +#include +#include #include "pcb.h" +#include "lgb.h" +#include "sgb.h" + +#include +#include +#include +#include +#include +#include #include +#include +#include + +using namespace std::chrono_literals; + +struct face +{ + int32_t f1, f2, f3; +}; int parseBlockEntry( char* data, std::vector& entries, int gOff ) { @@ -14,7 +32,7 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff { PCB_BLOCK_ENTRY block_entry; memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) ); - isgroup = block_entry.header.type == 0x30 ? true : false; + isgroup = block_entry.header.type == 0x30; //printf( " BLOCKHEADER_%X: type: %i, group_size: %i\n", gOff + offset, block_entry.header.type, block_entry.header.group_size ); @@ -22,12 +40,11 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff { parseBlockEntry( data + offset + 0x30, entries, gOff + offset ); offset += block_entry.header.group_size; - } else { - printf( "\tnum_v16: %i, num_indices: %i, num_vertices: %i\n\n", - block_entry.header.num_v16, block_entry.header.num_indices, block_entry.header.num_vertices ); + /* printf( "\tnum_v16: %i, num_indices: %i, num_vertices: %i\n\n", + block_entry.header.num_v16, block_entry.header.num_indices, block_entry.header.num_vertices );*/ int doffset = sizeof( block_entry.header ) + offset; uint16_t block_size = sizeof( block_entry.header ) + block_entry.header.num_vertices * 3 * 4 + @@ -52,207 +69,365 @@ int parseBlockEntry( char* data, std::vector& entries, int gOff if( block_entry.header.num_indices != 0 ) { block_entry.data.indices.resize( block_entry.header.num_indices ); - int32_t size_indexbuffer = block_entry.header.num_indices * 6; + int32_t size_indexbuffer = block_entry.header.num_indices * 12; memcpy( &block_entry.data.indices[0], data + doffset, size_indexbuffer ); doffset += size_indexbuffer; } entries.push_back( block_entry ); - - /* printf( "Vertices: \n" ); - for( auto& entry1 : block_entry.data.vertices ) - { - printf( "\t %f, %f, %f \n", - entry1.x, entry1.y, entry1.z ); - } - - float x_base = abs( float( block_entry.header.x1 - block_entry.header.x ) ); - float y_base = abs( float( block_entry.header.y1 - block_entry.header.y ) ); - float z_base = abs( float( block_entry.header.z1 - block_entry.header.z ) ); - - printf( "Vertices I16: \n" ); - for( auto& entry1 : block_entry.data.vertices_i16 ) - { - uint16_t var1 = entry1.x; - uint16_t var2 = entry1.y; - uint16_t var3 = entry1.z; - float x = ( var1 ); - float y = ( var2 ); - float z = ( var3 ); - printf( "\t%f, ", ( x / 0xFFFF ) * x_base + block_entry.header.x ); - printf( "%f, ", ( y / 0xFFFF ) * y_base + block_entry.header.y ); - printf( "%f ", ( z / 0xFFFF ) * z_base + block_entry.header.z ); - printf( "\n" ); - - }*/ } } return 0; } -int main() +std::string zoneNameToPath( const std::string& name ) { - char *data; - - uint32_t offset = 0; - //r1f1_b1_dor00.pcb - - //std::string filename( "f1h0_s_rof0003.pcb" ); - std::string filename( "tr0924.pcb" ); - FILE *fp = nullptr; - fp = fopen( filename.c_str(), "rb" ); - if( fp == nullptr ) + char teri = name[0]; + char region = name[1]; + char type = name[2]; + char zone = name[3]; + static std::map teriMap { - return 0; - } + { 'r', "roc" }, + { 'w', "wil" }, + { 'l', "lak" }, + { 'o', "ocn" }, + { 'f', "fst" }, + { 'a', "air" }, + { 's', "sea" }, + { 'z', "zon" } + }; - fseek( fp, 0, SEEK_END ); - int32_t size = ftell( fp ); - data = new char[size]; - rewind( fp ); - fread( data, sizeof( char ), size, fp ); - fclose( fp ); - - PCB_FILE pcb_file; - memcpy( &pcb_file.header, data, sizeof( pcb_file.header ) ); - offset += sizeof( pcb_file.header ); - - - - std::vector entries; - - bool isgroup = true; - while( isgroup ) + static std::map typeMap { - PCB_BLOCK_ENTRY block_entry; - memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) ); - isgroup = block_entry.header.type == 0x30 ? true : false; + { 'f', "fld" }, + { 't', "twn" }, + { 'd', "dun" }, + { 'b', "bah" }, + { 'i', "ind" }, + { 'e', "evt" }, + }; + std::string ret; + const auto& teriRet = teriMap[teri]; + const auto& typeRet = typeMap[type]; + ret += teriRet + "_"; + ret += teri; + ret += region; + ret += "/" + typeRet + "/" + name; + return ret; +} - //printf( "BLOCKHEADER_%X: type: %i, group_size: %i\n", offset, block_entry.header.type, block_entry.header.group_size ); - - if( isgroup ) +int main( int argc, char* argv[] ) +{ + auto startTime = std::chrono::system_clock::now(); + + std::string gamePath = "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv"; + std::string zoneName = "r1f1"; + + if( argc > 1 ) + { + gamePath = argv[1]; + if( argc > 2 ) { - std::vector data_block( block_entry.header.group_size ); - memcpy( &data_block[0], data + offset, block_entry.header.group_size ); - parseBlockEntry( (char*)&data_block[0] + 0x30, entries, offset ); - offset += block_entry.header.group_size; + zoneName = argv[2]; + } + } + const auto& zonePath = zoneNameToPath( zoneName ); + + try + { + xiv::dat::GameData data1( gamePath ); + xiv::exd::ExdData eData( data1 ); + + const xiv::dat::Cat& test = data1.get_category( "bg" ); + + auto test_file = data1.get_file( "bg/ffxiv/" + zonePath + "/level/bg.lgb" ); + auto section = test_file->access_data_sections().at( 0 ); + int32_t list_offset = *(uint32_t*)§ion[0x18]; + int32_t size = *(uint32_t*)§ion[4]; + + std::vector stringList; + + auto test_file1 = data1.get_file( "bg/ffxiv/" + zonePath + "/collision/list.pcb" ); + auto section1 = test_file1->access_data_sections().at( 0 ); + std::string path = "bg/ffxiv/" + zonePath + "/collision/"; + uint32_t offset1 = 0x20; + for( ; ; ) + { + + uint16_t trId = *(uint16_t*)§ion1[offset1]; + + char someString[200]; + sprintf( someString, "%str%04d.pcb", path.c_str(), trId ); + stringList.push_back( std::string( someString ) ); + //std::cout << someString << "\n"; + offset1 += 0x20; + + if( offset1 >= section1.size() ) + { + break; + } + } + + LGB_FILE bgLgb( §ion[0] ); + uint32_t max_index = 0; + + // dont bother if we cant write to a file + auto fp_out = fopen( ( zoneName + ".obj" ).c_str(), "w" ); + if( fp_out ) + { + fprintf( fp_out, "\n" ); + fclose( fp_out ); } else { - parseBlockEntry( data + offset, entries, offset ); + std::string errorMessage( "Cannot create " + zoneName + ".obj\n" + + " Check no programs have a handle to file and run as admin.\n" ); + std::cout << errorMessage; + throw std::runtime_error( errorMessage.c_str() ); + return 0; } - + fp_out = fopen( ( zoneName + ".obj" ).c_str(), "ab+" ); + if( fp_out ) + { + std::map pcbFiles; + std::map sgbFiles; + std::map objCount; + auto loadPcbFile = [&]( const std::string& fileName ) -> bool + { + try + { + //std::cout << fileName << " "; + auto file = data1.get_file( fileName ); + auto sections = file->get_data_sections(); + auto dataSection = §ions.at( 0 )[0]; + //std::cout << sections.size() << "\n"; + + uint32_t offset = 0; + PCB_FILE pcb_file; + memcpy( &pcb_file.header, &dataSection[0], sizeof( pcb_file.header ) ); + offset += sizeof( pcb_file.header ); + pcb_file.entries.resize( pcb_file.header.num_entries ); + bool isgroup = true; + while( isgroup ) + { + PCB_BLOCK_ENTRY block_entry; + memcpy( &block_entry.header, &dataSection[0] + offset, sizeof( block_entry.header ) ); + isgroup = block_entry.header.type == 0x30; + + //printf( "BLOCKHEADER_%X: type: %i, group_size: %i\n", offset, block_entry.header.type, block_entry.header.group_size ); + // + if( isgroup ) + { + parseBlockEntry( &dataSection[0] + offset + 0x30, pcb_file.entries, offset ); + offset += block_entry.header.group_size; + } + else + { + parseBlockEntry( &dataSection[0] + offset, pcb_file.entries, offset ); + } + } + pcbFiles.insert( std::make_pair( fileName, pcb_file ) ); + return true; + } + catch( std::exception& e ) + { + std::cout << "Unable to load collision mesh " << fileName << "\n\tError:\n\t" << e.what() << "\n"; + return false; + } + }; + + auto loadSgbFile = [&]( const std::string& fileName ) -> bool + { + SGB_FILE sgbFile; + try + { + auto file = data1.get_file( fileName ); + auto sections = file->get_data_sections(); + auto dataSection = §ions.at( 0 )[0]; + sgbFile = SGB_FILE( &dataSection[0] ); + sgbFiles.insert( std::make_pair( fileName, sgbFile ) ); + return true; + } + catch( std::exception& e ) + { + std::cout << "Unable to load SGB " << fileName << "\n\tError:\n\t" << e.what() << "\n"; + sgbFiles.insert( std::make_pair( fileName, sgbFile ) ); + } + return false; + }; + auto pushVerts = [&]( const PCB_FILE& pcb_file, const std::string& name, + const vec3* scale = nullptr, + const vec3* rotation = nullptr, + const vec3* translation = nullptr, + const SGB_MODEL_ENTRY* pSgbEntry = nullptr) + { + char name2[0x100]; + memset( name2, 0, 0x100 ); + sprintf( &name2[0], "%s_%u", &name[0], objCount[name]++ ); + fprintf( fp_out, "o %s\n", &name2[0] ); + + uint32_t groupCount = 0; + for( const auto &entry : pcb_file.entries ) + { + float x_base = abs( float( entry.header.x1 - entry.header.x ) ); + float y_base = abs( float( entry.header.y1 - entry.header.y ) ); + float z_base = abs( float( entry.header.z1 - entry.header.z ) ); + + auto makeTranslation = [&]( vec3& v ) + { + if( pSgbEntry ) + { + v.x *= pSgbEntry->header.scale.x; + v.y *= pSgbEntry->header.scale.y; + v.z *= pSgbEntry->header.scale.z; + + v = v * matrix4::rotateX( pSgbEntry->header.rotation.x ); + v = v * matrix4::rotateY( pSgbEntry->header.rotation.y ); + v = v * matrix4::rotateZ( pSgbEntry->header.rotation.z ); + + v.x += pSgbEntry->header.translation.x; + v.y += pSgbEntry->header.translation.y; + v.z += pSgbEntry->header.translation.z; + } + if( scale ) + { + v.x *= scale->x; + v.y *= scale->y; + v.z *= scale->z; + + v = v * matrix4::rotateX( rotation->x ); + v = v * matrix4::rotateY( rotation->y ); + v = v * matrix4::rotateZ( rotation->z ); + + v.x += translation->x; + v.y += translation->y; + v.z += translation->z; + } + + }; + + for( auto &vertex : entry.data.vertices ) + { + vec3 v( vertex.x, vertex.y, vertex.z ); + makeTranslation( v ); + fprintf( fp_out, "v %f %f %f\n", v.x, v.y, v.z ); + } + + for( const auto &link : entry.data.vertices_i16 ) + { + vec3 v( float( link.x ) / 0xFFFF, float( link.y ) / 0xFFFF, float( link.z ) / 0xFFFF ); + + v.x = v.x * x_base + entry.header.x; + v.y = v.y * y_base + entry.header.y; + v.z = v.z * z_base + entry.header.z; + + makeTranslation( v ); + fprintf( fp_out, "v %f %f %f\n", v.x, v.y, v.z ); + } + + //fprintf( fp_out, "g %s_", (name2 + "_" + std::to_string( groupCount++ )).c_str() ); + for( const auto &index : entry.data.indices ) + { + fprintf( fp_out, "f %i %i %i\n", + index.index[0] + max_index + 1, + index.index[1] + max_index + 1, + index.index[2] + max_index + 1 ); + // std::cout << std::to_string( index.unknown[0] )<< " " << std::to_string( index.unknown[1] )<< " " << std::to_string( index.unknown[2]) << std::endl; + } + max_index += entry.data.vertices.size() + entry.data.vertices_i16.size(); + } + }; + + for( const auto& fileName : stringList ) + { + loadPcbFile( fileName ); + pushVerts( pcbFiles[fileName], fileName ); + } + std::cout << "Writing obj file " << "\n"; + std::cout << bgLgb.groups.size() << " groups " << "\n"; + uint32_t totalGroups = 0; + uint32_t totalGroupEntries = 0; + for( const auto& group : bgLgb.groups ) + { + //std::cout << "\t" << group.name << " Size " << group.header.entryCount << "\n"; + totalGroups++; + for( const auto& pEntry : group.entries ) + { + auto pGimmick = dynamic_cast( pEntry.get() ); + auto pBgParts = dynamic_cast( pEntry.get() ); + + std::string fileName( "" ); + fileName.resize( 256 ); + totalGroupEntries++; + + // write files + auto writeOutput = [&]( const std::string& fileName, const vec3* scale, const vec3* rotation, const vec3* translation, const SGB_MODEL_ENTRY* pModel = nullptr) -> bool + { + { + const auto& it = pcbFiles.find( fileName ); + if( it == pcbFiles.end() ) + { + if( fileName.empty() || !loadPcbFile( fileName ) ) + return false; + //std::cout << "\t\tLoaded PCB File " << pBgParts->collisionFileName << "\n"; + } + } + const auto& it = pcbFiles.find( fileName ); + if( it != pcbFiles.end() ) + { + const auto& pcb_file = it->second; + pushVerts( pcb_file, fileName, scale, rotation, translation, pModel ); + } + return true; + }; + + if( pBgParts ) + { + fileName = pBgParts->collisionFileName; + writeOutput( fileName, &pBgParts->header.scale, &pBgParts->header.rotation, &pBgParts->header.translation ); + } + + // gimmick entry + if( pGimmick ) + { + { + const auto& it = sgbFiles.find( pGimmick->gimmickFileName ); + if( it == sgbFiles.end() ) + { + //std::cout << "\tGIMMICK:\n\t\t" << pGimmick->name << " " << pGimmick->gimmickFileName << "\n"; + loadSgbFile( pGimmick->gimmickFileName ); + } + } + const auto& it = sgbFiles.find( pGimmick->gimmickFileName ); + if( it != sgbFiles.end() ) + { + const auto& sgbFile = it->second; + + for( const auto& group : sgbFile.entries ) + { + for( const auto& pEntry : group.entries ) + { + auto pModel = dynamic_cast( pEntry.get() ); + fileName = pModel->collisionFileName; + writeOutput( fileName, &pGimmick->header.scale, &pGimmick->header.rotation, &pGimmick->header.translation, pModel ); + } + } + } + } + } + } + std::cout << "\n\nLoaded " << pcbFiles.size() << " PCB Files \n"; + std::cout << "Total Groups " << totalGroups << " Total entries " << totalGroupEntries << "\n"; + } + std::cout << "Finished exporting " << zoneName << " in " << + std::chrono::duration_cast( std::chrono::system_clock::now() - startTime ).count() << " seconds\n"; } - - for( uint16_t i = 0; i <= pcb_file.header.num_entries; i++ ) + catch( std::exception& e ) { - PCB_BLOCK_ENTRY block_entry; - memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) ); - offset += sizeof( block_entry.header ); - - uint16_t block_size = sizeof( block_entry.header ) + - block_entry.header.num_vertices * 3 * 4 + - block_entry.header.num_v16 * 6 + - block_entry.header.num_indices * 6; - - if( block_entry.header.num_vertices != 0 ) - { - block_entry.data.vertices.resize( block_entry.header.num_vertices ); - - int32_t size_vertexbuffer = block_entry.header.num_vertices * 3; - memcpy( &block_entry.data.vertices[0], data + offset, size_vertexbuffer * 4 ); - offset += size_vertexbuffer * 4; - } - if( block_entry.header.num_v16 != 0 ) - { - block_entry.data.vertices_i16.resize( block_entry.header.num_v16 ); - int32_t size_unknownbuffer = block_entry.header.num_v16 * 6; - memcpy( &block_entry.data.vertices_i16[0], data + offset, size_unknownbuffer ); - offset += block_entry.header.num_v16 * 6; - } - if( block_entry.header.num_indices != 0 ) - { - block_entry.data.indices.resize( block_entry.header.num_indices ); - int32_t size_indexbuffer = block_entry.header.num_indices * 6; - memcpy( &block_entry.data.indices[0], data + offset, size_indexbuffer ); - offset += size_indexbuffer; - } - - // blocks always align to 16 bytes + 8 bytes padding till the next block - int rest = ( offset % 16 ); - if( rest > 0 ) - { - rest = 0x10 - rest; - } - offset += rest ; - - - pcb_file.entries.push_back( block_entry ); + std::cout << e.what() << std::endl; } - - FILE* fp_out1 = fopen( std::string( filename + ".plain" ).c_str(), "w" ); - fprintf( fp_out1, ""); - fclose( fp_out1 ); - - FILE* fp_out = fopen( std::string( filename + ".plain" ).c_str(), "w+" ); - - fprintf( fp_out, "HEADER: num_entries: %i, total_indices: %i, unknown_1: %i\n\n", pcb_file.header.num_entries, pcb_file.header.total_indices, pcb_file.header.unknown_1 ); - - int block_cnt = 0; - for( auto& entry : pcb_file.entries ) - { - - fprintf( fp_out, "BLOCKHEADER_%i: type: %i, group_size: %i\n ", - block_cnt, entry.header.type, entry.header.group_size ); - fprintf( fp_out, "\tAABB: x: %f, y: %f, z: %f\n ", - entry.header.x, entry.header.y, entry.header.z ); - fprintf( fp_out, "\t\t x1: %f, y1: %f, z1: %f\n ", - entry.header.x1, entry.header.y1, entry.header.z1 ); - fprintf( fp_out, "\tnum_v16: %i, num_indices: %i, num_vertices: %i\n\n", - entry.header.num_v16, entry.header.num_indices, entry.header.num_vertices ); - - fprintf( fp_out, "Vertices: \n"); - for( auto& entry1 : entry.data.vertices ) - { - fprintf( fp_out, "\t %f, %f, %f \n", - entry1.x, entry1.y, entry1.z ); - } - - float x_base = abs( float( entry.header.x1 - entry.header.x ) ); - float y_base = abs( float( entry.header.y1 - entry.header.y ) ); - float z_base = abs( float( entry.header.z1 - entry.header.z ) ); - - fprintf( fp_out, "Vertices I16: \n" ); - for( auto& entry1 : entry.data.vertices_i16 ) - { - uint16_t var1 = entry1.x; - uint16_t var2 = entry1.y; - uint16_t var3 = entry1.z; - float x = ( var1 ); - float y = ( var2 ); - float z = ( var3 ); - fprintf( fp_out, "\t%f, ", (x / 0xFFFF) * x_base + entry.header.x ); - fprintf( fp_out, "%f, ", (y / 0xFFFF) * y_base + entry.header.y ); - fprintf( fp_out, "%f ", (z / 0xFFFF) * z_base + entry.header.z ); - fprintf( fp_out, "\n"); - - } - - - - - fprintf( fp_out, "Indices: \n" ); - for( auto& entry1 : entry.data.indices ) - { - fprintf( fp_out, "\t %i, %i, %i - %x,%x,%x \n", - entry1.index[0], entry1.index[1], entry1.index[2], entry1.unknown[0], entry1.unknown[1], entry1.unknown[2] ); - } - fprintf( fp_out, "\n" ); - } - - fclose( fp_out ); - return 0; } diff --git a/src/tools/pcb_reader/matrix4.h b/src/tools/pcb_reader/matrix4.h new file mode 100644 index 00000000..d02d2c84 --- /dev/null +++ b/src/tools/pcb_reader/matrix4.h @@ -0,0 +1,100 @@ +#ifndef _MATRIX4_H +#define _MATRIX4_H + +#include +#include + +// https://github.com/jpd002/Play--Framework/tree/master/include/math +struct matrix4 +{ + // 4x4 + float grid[16]; + matrix4() + { + memset( &grid[0], 0, sizeof( grid ) ); + } + + float operator()( int row, int col ) const + { + return grid[(row * 4) + col]; + } + + float& operator()( int row, int col ) + { + return grid[(row * 4) + col]; + } + static matrix4 rotateX( float angle ) + { + matrix4 ret = matrix4(); + ret(0, 0) = 1.000000000f; + ret(1, 1) = cos(angle); + ret(1, 2) = -sin(angle); + ret(2, 1) = sin(angle); + ret(2, 2) = cos(angle); + ret(3, 3) = 1.000000000f; + return ret; + } + + static matrix4 rotateY( float angle ) + { + matrix4 ret = matrix4(); + ret(0, 0) = cos(angle); + ret(0, 2) = sin(angle); + ret(1, 1) = 1.000000000f; + ret(2, 0) = -sin(angle); + ret(2, 2) = cos(angle); + ret(3, 3) = 1.000000000f; + return ret; + } + + static matrix4 rotateZ( float angle ) + { + matrix4 ret = matrix4(); + ret(0, 0) = cos(angle); + ret(0, 1) = -sin(angle); + ret(1, 0) = sin(angle); + ret(1, 1) = cos(angle); + ret(2, 2) = 1.000000000f; + ret(3, 3) = 1.000000000f; + return ret; + } + + static matrix4 scale( float x, float y, float z ) + { + matrix4 ret = matrix4(); + ret(0, 0) = x; + ret(1, 1) = y; + ret(2, 2) = z; + ret(3, 3) = 1; + + return ret; + } + + static matrix4 translate( float x, float y, float z ) + { + matrix4 ret = matrix4(); + ret(0, 0) = 1; + ret(1, 1) = 1; + ret(2, 2) = 1; + ret(3, 3) = 1; + + ret(3, 0) = x; + ret(3, 1) = y; + ret(3, 2) = z; + return ret; + } + + matrix4 operator *( const matrix4& rhs ) const + { + matrix4 ret; + for( unsigned int i = 0; i < 4; i++ ) + { + ret( i, 0 ) = (*this)(i, 0) * rhs( 0, 0 ) + (*this)(i, 1) * rhs( 1, 0 ) + (*this)(i, 2) * rhs( 2, 0 ) + (*this)(i, 3) * rhs( 3, 0 ); + ret( i, 1 ) = (*this)(i, 0) * rhs( 0, 1 ) + (*this)(i, 1) * rhs( 1, 1 ) + (*this)(i, 2) * rhs( 2, 1 ) + (*this)(i, 3) * rhs( 3, 1 ); + ret( i, 2 ) = (*this)(i, 0) * rhs( 0, 2 ) + (*this)(i, 1) * rhs( 1, 2 ) + (*this)(i, 2) * rhs( 2, 2 ) + (*this)(i, 3) * rhs( 3, 2 ); + ret( i, 3 ) = (*this)(i, 0) * rhs( 0, 3 ) + (*this)(i, 1) * rhs( 1, 3 ) + (*this)(i, 2) * rhs( 2, 3 ) + (*this)(i, 3) * rhs( 3, 3 ); + } + return ret; + } +}; +#endif diff --git a/src/tools/pcb_reader/pcb.h b/src/tools/pcb_reader/pcb.h index a9c65e2e..4b775d84 100644 --- a/src/tools/pcb_reader/pcb.h +++ b/src/tools/pcb_reader/pcb.h @@ -1,3 +1,6 @@ +#ifndef _PCB_H +#define _PCB_H + #include #include @@ -6,7 +9,7 @@ struct PCB_HEADER uint32_t unknown_1; uint32_t unknown_2; uint32_t num_entries; // count starts at 0 - uint32_t total_indices; + uint32_t total_indices; uint64_t padding; }; @@ -15,13 +18,13 @@ struct PCB_BLOCK_HEADER uint32_t type; // 0 for entry, 0x30 for group uint32_t group_size; // when group size in bytes for the group block // bounding box - float x; + float x; float y; float z; float x1; float y1; float z1; - // number of vertices packed into 16 bit + // number of vertices packed into 16 bit uint16_t num_v16; // number of indices uint16_t num_indices; @@ -40,6 +43,7 @@ struct PCB_INDEXDATA { uint8_t index[3]; uint8_t unknown[3]; + uint8_t unknown1[6]; }; struct PCB_VERTEXDATAI16 @@ -67,3 +71,22 @@ struct PCB_FILE PCB_HEADER header; std::vector< PCB_BLOCK_ENTRY > entries; }; + +struct PCB_LIST_ENTRY +{ + uint32_t id; + float x, y, z, x2, y2, z2, rot; +}; + +struct PCB_LIST_BASE_ENTRY +{ + float x, y, z, x2, y2, z2, rot; +}; + +struct PCB_LIST_FILE +{ + uint32_t count; + PCB_LIST_BASE_ENTRY entry; + std::vector entries; +}; +#endif \ No newline at end of file diff --git a/src/tools/pcb_reader/sgb.h b/src/tools/pcb_reader/sgb.h new file mode 100644 index 00000000..8c597d0e --- /dev/null +++ b/src/tools/pcb_reader/sgb.h @@ -0,0 +1,202 @@ +#ifndef _SGB_H +#define _SGB_H + +#include +#include +#include +#include +#include +#include +#include + +#include "vec3.h" + +// +// ported from https://github.com/ufx/SaintCoinach/blob/master/SaintCoinach/Graphics/Sgb/SgbDataType.cs + +struct SGB_FILE; +struct SGB_HEADER; +struct SGB_MODEL_ENTRY; +struct SGB_MODEL_HEADER; +struct SGB_GROUP; +struct SGB_GROUP_HEADER; + + +enum SgbDataType : uint32_t +{ + Unknown0008 = 0x0008, + Group = 0x0100, +}; + +enum SgbGroupEntryType : uint32_t +{ + Model = 0x01, +}; + +struct SGB_GROUP_HEADER +{ + SgbDataType type; + int32_t nameOffset; + uint32_t unknown08; + uint32_t unknown0C; + + uint32_t unknown10; + uint32_t unknown14; + uint32_t unknown18; + uint32_t unknown1C; + + int32_t entryCount; + uint32_t unknown24; + uint32_t unknown28; + uint32_t unknown2C; + + uint32_t unknown30; + uint32_t unknown34; + uint32_t unknown38; + uint32_t unknown3C; + + uint32_t unknown40; + uint32_t unknown44; +}; + +struct SGB_GROUP_ENTRY +{ +public: + char* m_buf; + uint32_t m_offset; + + SGB_GROUP_ENTRY() + { + m_buf = nullptr; + m_offset = 0; + }; + SGB_GROUP_ENTRY( char* buf, uint32_t offset ) + { + m_buf = buf; + m_offset = offset; + }; + virtual ~SGB_GROUP_ENTRY() {}; +}; + +struct SGB_MODEL_HEADER +{ + SgbGroupEntryType type; + uint32_t unknown2; + int32_t nameOffset; + vec3 translation; + vec3 rotation; + vec3 scale; + int32_t modelFileOffset; + int32_t collisionFileOffset; +}; + +struct SGB_MODEL_ENTRY : public SGB_GROUP_ENTRY +{ + SGB_MODEL_HEADER header; + SgbGroupEntryType type; + std::string name; + std::string modelFileName; + std::string collisionFileName; + + SGB_MODEL_ENTRY( char* buf, uint32_t offset ) + { + header = *reinterpret_cast( buf + offset ); + name = std::string( buf + offset + header.nameOffset ); + modelFileName = std::string( buf + offset + header.modelFileOffset ); + collisionFileName = std::string( buf + offset + header.collisionFileOffset ); + } +}; + +struct SGB_GROUP +{ + SGB_GROUP_HEADER header; + std::string name; + SGB_FILE* parent; + std::vector> entries; + + SGB_GROUP( char* buf, SGB_FILE* file, uint32_t fileSize, uint32_t offset ) + { + parent = file; + header = *reinterpret_cast( buf + offset ); + name = std::string( buf + offset + header.nameOffset ); + + auto entriesOffset = offset + sizeof( header ); + + for( auto i = 0; i < header.entryCount; ++i ) + { + auto entryOffset = entriesOffset + *reinterpret_cast( buf + ( entriesOffset + (i * 4) ) ); + if( entryOffset > fileSize ) + throw std::runtime_error( "SGB_GROUP entry offset was larger than SGB file size!" ); + auto type = *reinterpret_cast( buf + entryOffset ); + if( type == SgbGroupEntryType::Model ) + { + entries.push_back( std::make_shared( buf, entryOffset ) ); + } + } + } +}; + +struct SGB_HEADER +{ + char magic[4]; // SGB1 + uint32_t fileSize; + uint32_t unknown1; + char magic2[4]; // SCN1 + + uint32_t unknown10; + int32_t sharedOffset; + uint32_t unknown18; + int32_t offset1C; + + uint32_t unknown20; + uint32_t unknown24; + uint32_t unknown28; + uint32_t unknown2C; + + uint32_t unknown30; + uint32_t unknown34; + uint32_t unknown38; + uint32_t unknown3C; + + uint32_t unknown40; + uint32_t unknown44; + uint32_t unknown48; + uint32_t unknown4C; + + uint32_t unknown50; + uint32_t unknown54; +}; + +struct SGB_FILE +{ + SGB_HEADER header; + std::vector entries; + + SGB_FILE() + { + memset( &header, 0, sizeof( header ) ); + } + SGB_FILE( char* buf ) + { + constexpr int baseOffset = 0x14; + header = *reinterpret_cast( buf ); + + if( strncmp( &header.magic[0], "SGB1", 4 ) != 0 || strncmp( &header.magic2[0], "SCN1", 4 ) != 0 ) + throw std::runtime_error( "Unable to load SGB File!" ); + + try + { + auto group = SGB_GROUP( buf, this, header.fileSize, baseOffset + header.sharedOffset ); + entries.push_back( group ); + auto group2 = SGB_GROUP( buf, this, header.fileSize, baseOffset + header.offset1C ); + entries.push_back( group2 ); + } + catch( std::exception& e ) + { + std::cout << e.what() << "\n"; + } + }; +}; + + +#endif // !_SGB_H diff --git a/src/tools/pcb_reader/vec3.h b/src/tools/pcb_reader/vec3.h new file mode 100644 index 00000000..a8fdfbd1 --- /dev/null +++ b/src/tools/pcb_reader/vec3.h @@ -0,0 +1,31 @@ +#ifndef _VEC3_H +#define _VEC3_H + +#include +#include "matrix4.h" + +struct vec3 +{ + float x, y, z; + vec3() + { + x = 0.0f; + y = 0.0f; + z = 0.0f; + } + vec3(float x, float y, float z) + { + this->x = x; + this->y = y; + this->z = z; + }; +}; +static vec3 operator *(const vec3& lhs, const matrix4& rhs) +{ + vec3 ret; + ret.x = rhs(0, 0) * lhs.x + rhs(0, 1) * lhs.y + rhs(0, 2) * lhs.z; + ret.y = rhs(1, 0) * lhs.x + rhs(1, 1) * lhs.y + rhs(1, 2) * lhs.z; + ret.z = rhs(2, 0) * lhs.x + rhs(2, 1) * lhs.y + rhs(2, 2) * lhs.z; + return ret; +}; +#endif \ No newline at end of file diff --git a/src/tools/quest_parser/main.cpp b/src/tools/quest_parser/main.cpp index f4ec46b1..ff5bc70b 100644 --- a/src/tools/quest_parser/main.cpp +++ b/src/tools/quest_parser/main.cpp @@ -91,7 +91,7 @@ void createScript( boost::shared_ptr< Core::Data::QuestInfo > pQuestData, std::s if( pQuestData->reward_item.size() > 0 ) { rewards += " this.RewardItem = ["; - for( int ca = 0; ca < pQuestData->reward_item.size(); ca++ ) + for( size_t ca = 0; ca < pQuestData->reward_item.size(); ca++ ) { rewards += std::to_string( pQuestData->reward_item.at( ca ) ); if( ca != pQuestData->reward_item.size() - 1 ) @@ -105,7 +105,7 @@ void createScript( boost::shared_ptr< Core::Data::QuestInfo > pQuestData, std::s if( pQuestData->reward_item.size() > 0 ) { rewards += " this.RewardItemCount = ["; - for( int ca = 0; ca < pQuestData->reward_item_count.size(); ca++ ) + for( size_t ca = 0; ca < pQuestData->reward_item_count.size(); ca++ ) { rewards += std::to_string( pQuestData->reward_item_count.at( ca ) ); if( ca != pQuestData->reward_item_count.size() - 1 ) @@ -119,7 +119,7 @@ void createScript( boost::shared_ptr< Core::Data::QuestInfo > pQuestData, std::s if( pQuestData->reward_item_optional.size() > 0 ) { rewards += " this.RewardItemOptional = ["; - for( int ca = 0; ca < pQuestData->reward_item_optional.size(); ca++ ) + for( size_t ca = 0; ca < pQuestData->reward_item_optional.size(); ca++ ) { rewards += std::to_string( pQuestData->reward_item_optional.at( ca ) ); if( ca != pQuestData->reward_item_optional.size() - 1 ) @@ -133,7 +133,7 @@ void createScript( boost::shared_ptr< Core::Data::QuestInfo > pQuestData, std::s if( pQuestData->reward_item_optional_count.size() > 0 ) { rewards += " this.RewardItemOptionalCount = ["; - for( int ca = 0; ca < pQuestData->reward_item_optional_count.size(); ca++ ) + for( size_t ca = 0; ca < pQuestData->reward_item_optional_count.size(); ca++ ) { rewards += std::to_string( pQuestData->reward_item_optional_count.at( ca ) ); if( ca != pQuestData->reward_item_optional_count.size() - 1 ) @@ -151,7 +151,7 @@ void createScript( boost::shared_ptr< Core::Data::QuestInfo > pQuestData, std::s std::vector< std::string > script_entities; std::string sentities = " // Entities found in the script data of the quest\n"; - for( int ca = 0; ca < pQuestData->script_entity.size(); ca ++ ) + for( size_t ca = 0; ca < pQuestData->script_entity.size(); ca ++ ) { if( ( pQuestData->script_entity.at( ca ).find( "HOWTO" ) != std::string::npos ) || ( pQuestData->script_entity.at( ca ).find( "HOW_TO" ) != std::string::npos ) ) continue;