Merge http://www.github.com/SapphireMordred/Sapphire into SQL_REWRITE_OWN
Conflicts: CMakeLists.txt src/servers/Server_Common/Network/PacketDef/Ipcs.h src/servers/Server_Zone/Actor/PlayerQuest.cpp src/servers/Server_Zone/Actor/PlayerSql.cpp
8
.gitignore
vendored
|
@ -44,6 +44,10 @@ build/
|
||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
|
# Projects and Solutions
|
||||||
|
*.vcxproj
|
||||||
|
*.sln
|
||||||
|
|
||||||
# CMake
|
# CMake
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
CMakeFiles
|
CMakeFiles
|
||||||
|
@ -96,6 +100,10 @@ src/libraries/external/boost_*
|
||||||
*.ipdb
|
*.ipdb
|
||||||
*.iobj
|
*.iobj
|
||||||
*.filters
|
*.filters
|
||||||
|
*.idb
|
||||||
|
|
||||||
# sapphire version
|
# sapphire version
|
||||||
src/servers/Server_Common/Version\.cpp
|
src/servers/Server_Common/Version\.cpp
|
||||||
|
|
||||||
|
# edit and continue files
|
||||||
|
/enc_temp_folder
|
10
.travis.yml
|
@ -6,17 +6,19 @@ before_install:
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
- sudo apt-get install -y software-properties-common
|
- sudo apt-get install -y software-properties-common
|
||||||
- sudo apt-get update
|
- 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 libboost-dev libboost-all-dev libmysqlclient-dev -y
|
||||||
- sudo apt-get install libmysqlcppconn-dev -y
|
- sudo apt-get install libmysqlcppconn-dev -y
|
||||||
|
|
||||||
compiler:
|
compiler:
|
||||||
- gcc
|
- g++
|
||||||
|
|
||||||
|
|
||||||
# Build steps
|
# Build steps
|
||||||
script:
|
script:
|
||||||
|
- g++ --version
|
||||||
- mkdir build
|
- mkdir build
|
||||||
- cd 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 ..
|
- cd ..
|
||||||
- bash sql_import.sh
|
- bash sql_import.sh
|
||||||
|
|
|
@ -65,4 +65,4 @@ add_subdirectory("src/tools/exd_common_gen")
|
||||||
add_subdirectory("src/tools/exd_struct_gen")
|
add_subdirectory("src/tools/exd_struct_gen")
|
||||||
add_subdirectory("src/tools/exd_struct_test")
|
add_subdirectory("src/tools/exd_struct_test")
|
||||||
add_subdirectory("src/tools/quest_parser")
|
add_subdirectory("src/tools/quest_parser")
|
||||||
|
add_subdirectory("src/tools/pcb_reader")
|
||||||
|
|
|
@ -25,6 +25,6 @@
|
||||||
<MotD><<<Welcome to Sapphire>>></MotD>
|
<MotD><<<Welcome to Sapphire>>></MotD>
|
||||||
<MotD>This is a very good server</MotD>
|
<MotD>This is a very good server</MotD>
|
||||||
<MotD>You can change these messages by editing MotDArray in config/settings_zone.xml</MotD>
|
<MotD>You can change these messages by editing MotDArray in config/settings_zone.xml</MotD>
|
||||||
</MotdArray>
|
</MotDArray>
|
||||||
</Parameters>
|
</Parameters>
|
||||||
</Settings>
|
</Settings>
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
body{
|
html {
|
||||||
font-family:Verdana;
|
min-height: 100%;
|
||||||
font-size:10pt;
|
|
||||||
line-height:14pt;
|
|
||||||
height:100%;
|
|
||||||
background-image:url(../../assets/img/background.png);
|
|
||||||
background-color:#282828;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div.contentContainer{
|
body {
|
||||||
|
font-family: Meiryo, Verdana, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 14px;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contentContainer{
|
||||||
width:50%;
|
width:50%;
|
||||||
float:left;
|
float:left;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.info{
|
.info{
|
||||||
width:320px;
|
width:320px;
|
||||||
height:100%;
|
height:100%;
|
||||||
margin-left:auto;
|
margin-left:auto;
|
||||||
|
@ -22,7 +25,7 @@ div.info{
|
||||||
background-color:lightgrey;
|
background-color:lightgrey;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.infoFooter{
|
.infoFooter{
|
||||||
width:400px;
|
width:400px;
|
||||||
margin-left:auto;
|
margin-left:auto;
|
||||||
margin-right:auto;
|
margin-right:auto;
|
||||||
|
@ -135,3 +138,26 @@ p.pageSubTitle{
|
||||||
margin:0 auto;
|
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;
|
||||||
|
}
|
|
@ -1,5 +1,138 @@
|
||||||
div#TopDiv{
|
.s-logo {
|
||||||
padding:10px;
|
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{
|
img{
|
||||||
|
@ -12,8 +145,39 @@ h2.text-center{
|
||||||
color:#fff;
|
color:#fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1.text-center{
|
.s-login-call{
|
||||||
color:#FFF;
|
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{
|
div.login-card{
|
||||||
|
@ -30,11 +194,7 @@ input.input-sm{
|
||||||
margin-right:auto;
|
margin-right:auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
div#Conttwo.container{
|
|
||||||
display:block;
|
|
||||||
width:300px;
|
|
||||||
background-color:rgba(17, 17, 17, 0.77);
|
|
||||||
}
|
|
||||||
|
|
||||||
div#Split{
|
div#Split{
|
||||||
padding:2px;
|
padding:2px;
|
||||||
|
|
BIN
bin/web/assets/img/fa-discord-icon.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
bin/web/assets/img/github-icon.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
bin/web/assets/img/graffletopia-gears.png
Normal file
After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 344 KiB After Width: | Height: | Size: 399 KiB |
BIN
bin/web/assets/img/sapphire_logo_resize.png
Normal file
After Width: | Height: | Size: 118 KiB |
|
@ -23,7 +23,7 @@
|
||||||
var parsed = JSON.parse(response);
|
var parsed = JSON.parse(response);
|
||||||
window.external.Boot(parsed.sId, parsed.lobbyHost, parsed.frontierHost);
|
window.external.Boot(parsed.sId, parsed.lobbyHost, parsed.frontierHost);
|
||||||
}catch(err){
|
}catch(err){
|
||||||
document.getElementById("Error").innerHTML = "Create User failed.";
|
document.getElementById("Error").innerHTML = "User creation failed.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,25 +46,55 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body scroll="no">
|
<body scroll="no">
|
||||||
<div id="TopDiv"></div>
|
<div class="s-full-split s-left-half col-xs-7">
|
||||||
<div class="container"><img src="assets/img/sapphire_logo.png" width="40%" height="40%"></div>
|
<div class="clearfix s-link-badge-wrapper">
|
||||||
<div class="container" id="Conttwo">
|
<a href="https://discord.gg/KfrZCkx" class="s-link-badge s-link-badge-discord col-xs-5">
|
||||||
<div></div>
|
Join us on Discord!
|
||||||
<h1 class="text-center">Create Account</h1>
|
</a>
|
||||||
<p class="text-center">Username: </p>
|
<a href="https://github.com/SapphireMordred/Sapphire" class="s-link-badge s-link-badge-github col-xs-5 pull-left">
|
||||||
<td><input type="text" name="username" /></td>
|
Our Github repository
|
||||||
<div id="Split"></div>
|
</a>
|
||||||
<p class="text-center">Password: </p>
|
</div>
|
||||||
<td><input type="password" name="password" /></td>
|
<h2>Github stuff here soon!</h2>
|
||||||
<div id="space"></div>
|
</div>
|
||||||
<button class="btn btn-default" input id="submitButton" onclick="doLogin()">Create User</button>
|
<div class="s-full-split s-right-half col-xs-5">
|
||||||
<p id="Error" class="text-center"></p>
|
<div class="s-logo">
|
||||||
<div id="Split">
|
<img src="assets/img/sapphire_logo_resize.png">
|
||||||
<p id="CreateUser"><a href="login.html"><span style="text-decoration: underline;">Back to Login</span></a></p>
|
</div>
|
||||||
</div>
|
<div class="s-login-box col-xs-12">
|
||||||
</div>
|
<div class="s-login-box-form">
|
||||||
|
<h1 class="text-center s-login-call">Account Creation</h1>
|
||||||
|
<div class="input-control">
|
||||||
|
<label class="s-login-input-wrapper">
|
||||||
|
Username
|
||||||
|
<input type="text" name="username" autofocus>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-control">
|
||||||
|
<label class="s-login-input-wrapper">
|
||||||
|
Password
|
||||||
|
<input type="password" name="password">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-default s-login-btn pull-right" id="CreateUser" onclick="doLogin()">Create Account</button>
|
||||||
|
<p id="Error" class="s-error-text"></p>
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-default s-acc-btn" href="login.html">Back to Login</a>
|
||||||
|
</div>
|
||||||
|
<div class="s-gears">
|
||||||
|
<img class="s-gears" src="assets/img/graffletopia-gears.png" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<script src="assets/js/jquery.min.js"></script>
|
<script src="assets/js/jquery.min.js"></script>
|
||||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
|
||||||
|
<script> // Run only after jq and bootstrap have finished loading
|
||||||
|
|
||||||
|
// Work around non-HTML5 compliant IE autofocus
|
||||||
|
$(function() {
|
||||||
|
$('[autofocus]:not(:focus)').eq(0).focus();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -2,13 +2,13 @@
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Sapphire login</title>
|
<title>Sapphire - Login</title>
|
||||||
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="assets/css/styles.css">
|
<link rel="stylesheet" href="assets/css/styles.css">
|
||||||
<link rel="stylesheet" href="assets/css/global.css">
|
<link rel="stylesheet" href="assets/css/global.css">
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function doLogin(){
|
function doLogin(){
|
||||||
var url = "sapphire-api/lobby/login";
|
var url = "sapphire-api/lobby/login";
|
||||||
|
@ -41,30 +41,81 @@
|
||||||
data = xhr.response;
|
data = xhr.response;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body scroll="no">
|
<body scroll="no">
|
||||||
<div id="TopDiv"></div>
|
<div class="s-full-split s-left-half col-xs-7">
|
||||||
<div class="container"><img src="assets/img/sapphire_logo.png" width="40%" height="40%"></div>
|
<div class="clearfix s-link-badge-wrapper">
|
||||||
<div class="container" id="Conttwo">
|
<a href="https://discord.gg/KfrZCkx" class="s-link-badge s-link-badge-discord col-xs-5">
|
||||||
<div></div>
|
Join us on Discord!
|
||||||
<h1 class="text-center">Login To Account</h1>
|
</a>
|
||||||
<p class="text-center">Username: </p>
|
<a href="https://github.com/SapphireMordred/Sapphire" class="s-link-badge s-link-badge-github col-xs-5 pull-left">
|
||||||
<td><input type="text" name="username" /></td>
|
Our Github repository
|
||||||
<div id="Split"></div>
|
</a>
|
||||||
<p class="text-center">Password: </p>
|
</div>
|
||||||
<td><input type="password" name="password" /></td>
|
<h2>Recent Activity</h2>
|
||||||
<div id="space"></div>
|
<ul id="commit-log" class="commit-history">
|
||||||
<button class="btn btn-default" input id="submitButton" onclick="doLogin()">Login</button>
|
|
||||||
<p id="Error" class="text-center"></p>
|
</ul>
|
||||||
<div id="Split">
|
</div>
|
||||||
<p id="CreateUser"><a href="createUser.html"><span style="text-decoration: underline;">Create Account</span></a></p>
|
<div class="s-full-split s-right-half col-xs-5">
|
||||||
</div>
|
<div class="s-logo">
|
||||||
</div>
|
<img src="assets/img/sapphire_logo_resize.png">
|
||||||
<script src="assets/js/jquery.min.js"></script>
|
</div>
|
||||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
<div class="s-login-box col-xs-12">
|
||||||
|
<div class="s-login-box-form">
|
||||||
|
<h1 class="text-center s-login-call">Login to Account</h1>
|
||||||
|
<div class="input-control">
|
||||||
|
<label class="s-login-input-wrapper">
|
||||||
|
Username
|
||||||
|
<input type="text" name="username" autofocus>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-control">
|
||||||
|
<label class="s-login-input-wrapper">
|
||||||
|
Password
|
||||||
|
<input type="password" name="password">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-default s-login-btn pull-right" id="submitButton" onclick="doLogin()">Login</button>
|
||||||
|
<p id="Error" class="s-error-text"></p>
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-default s-acc-btn" href="createUser.html">Create Account</a>
|
||||||
|
</div>
|
||||||
|
<div class="s-gears">
|
||||||
|
<img class="s-gears" src="assets/img/graffletopia-gears.png" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="TopDiv"></div>
|
||||||
|
<div class="container"></div>
|
||||||
|
|
||||||
|
<script src="assets/js/jquery.min.js"></script>
|
||||||
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
fetch( "https://api.github.com/repos/SapphireMordred/Sapphire/events" ).then( function( resp ) {
|
||||||
|
return resp.json();
|
||||||
|
}).then( function( data ) {
|
||||||
|
data = data.filter( function( e ) {
|
||||||
|
return e.type == "PushEvent";
|
||||||
|
});
|
||||||
|
|
||||||
|
let commitContainer = document.getElementById( 'commit-log' );
|
||||||
|
for ( var evnt of data ) {
|
||||||
|
for ( var commit of evnt.payload.commits ) {
|
||||||
|
let e = document.createElement( 'li' );
|
||||||
|
e.innerHTML = '<a href="https://github.com/SapphireMordred/Sapphire/commit/' + commit.sha + '">' + commit.message + '</a>';
|
||||||
|
|
||||||
|
commitContainer.appendChild( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
Before Width: | Height: | Size: 344 KiB |
|
@ -8,11 +8,19 @@ else()
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHc")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHc")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
|
||||||
|
|
||||||
# edit and continue
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
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")
|
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()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ class CmnDefInnBedDef
|
||||||
|
|
||||||
def Scene00100( player ) //Wake up
|
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 )
|
fun( player, eventId, param1, param2, param3 )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -59,4 +59,4 @@ class CmnDefInnBedDef
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GLOBAL CmnDefInnBed = CmnDefInnBedDef();
|
GLOBAL CmnDefInnBed = CmnDefInnBedDef();
|
||||||
|
|
|
@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `infolinkshell`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8 */;
|
/*!40101 SET character_set_client = utf8 */;
|
||||||
CREATE TABLE `infolinkshell` (
|
CREATE TABLE `infolinkshell` (
|
||||||
`LinkshellId` int(20) NOT NULL AUTO_INCREMENT,
|
`LinkshellId` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
`MasterCharacterId` int(20) DEFAULT NULL,
|
`MasterCharacterId` int(20) DEFAULT NULL,
|
||||||
`CharacterIdList` blob,
|
`CharacterIdList` blob,
|
||||||
`LinkshellName` varchar(32) DEFAULT NULL,
|
`LinkshellName` varchar(32) DEFAULT NULL,
|
||||||
|
|
|
@ -572,7 +572,8 @@ namespace Core {
|
||||||
MpGain = 11,
|
MpGain = 11,
|
||||||
TpLoss = 12,
|
TpLoss = 12,
|
||||||
TpGain = 13,
|
TpGain = 13,
|
||||||
GpGain = 14
|
GpGain = 14,
|
||||||
|
Mount = 38
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ActionHitSeverityType : uint8_t
|
enum class ActionHitSeverityType : uint8_t
|
||||||
|
@ -921,10 +922,11 @@ namespace Core {
|
||||||
|
|
||||||
GearSetEquipMsg = 0x321,
|
GearSetEquipMsg = 0x321,
|
||||||
|
|
||||||
ToggleOrchestrionUnlock = 0x396
|
ToggleOrchestrionUnlock = 0x396,
|
||||||
|
Dismount = 0x3a0
|
||||||
};
|
};
|
||||||
|
|
||||||
enum struct ChatType : uint32_t
|
enum struct ChatType : uint16_t
|
||||||
{
|
{
|
||||||
LogKindError,
|
LogKindError,
|
||||||
ServerDebug,
|
ServerDebug,
|
||||||
|
@ -1038,6 +1040,12 @@ namespace Core {
|
||||||
Visor = 0x40,
|
Visor = 0x40,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SkillType : uint8_t
|
||||||
|
{
|
||||||
|
Normal = 0x1,
|
||||||
|
MountSkill = 0xD,
|
||||||
|
};
|
||||||
|
|
||||||
struct ServerEntry
|
struct ServerEntry
|
||||||
{
|
{
|
||||||
uint32_t serverId;
|
uint32_t serverId;
|
||||||
|
|
|
@ -93,7 +93,7 @@ std::string Core::Util::base64_decode( std::string const& encoded_string ) {
|
||||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||||
if( i == 4 ) {
|
if( i == 4 ) {
|
||||||
for( i = 0; i < 4; i++ )
|
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[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 );
|
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;
|
char_array_4[j] = 0;
|
||||||
|
|
||||||
for( j = 0; j < 4; j++ )
|
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[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 );
|
char_array_3[1] = ( ( char_array_4[1] & 0xf ) << 4 ) + ( ( char_array_4[2] & 0x3c ) >> 2 );
|
||||||
|
|
|
@ -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 );
|
uint16_t weather_rate = getField< uint16_t >( fields, 10 ) > 75 ? 0 : getField< uint16_t >( fields, 10 );
|
||||||
auto weatherRateFields = weatherRate.get_row( weather_rate );
|
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 };
|
ZoneInfo info{ 0 };
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
#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 )
|
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 Core::Network::Packets::GamePacket::toString() const
|
||||||
{
|
{
|
||||||
|
return Core::Util::binaryToHexDump( const_cast<uint8_t *>( &m_dataBuf[0] ), getSize() );
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace Packets {
|
||||||
{
|
{
|
||||||
Ping = 0x0065,
|
Ping = 0x0065,
|
||||||
Init = 0x0066,
|
Init = 0x0066,
|
||||||
Chat = 0x0067,
|
Chat = 0x00B9,
|
||||||
ChatBanned = 0x006B,
|
ChatBanned = 0x006B,
|
||||||
Logout = 0x0077,
|
Logout = 0x0077,
|
||||||
CFNotify = 0x0078,
|
CFNotify = 0x0078,
|
||||||
|
@ -73,15 +73,13 @@ namespace Packets {
|
||||||
Effect = 0x00FB, // updated 4.1
|
Effect = 0x00FB, // updated 4.1
|
||||||
GCAffiliation = 0x00FC,
|
GCAffiliation = 0x00FC,
|
||||||
|
|
||||||
HateList = 0x011A,
|
|
||||||
PlayerSpawn = 0x011C, // updated 4.1
|
PlayerSpawn = 0x011C, // updated 4.1
|
||||||
NpcSpawn = 0x011D, // updated 4.1
|
NpcSpawn = 0x011D, // updated 4.1
|
||||||
ActorMove = 0x011E, // updated 4.1
|
ActorMove = 0x011E, // updated 4.1
|
||||||
|
|
||||||
UpdateClassInfo = 0x111D,
|
|
||||||
|
|
||||||
ActorSetPos = 0x0120, // updated 4.1
|
ActorSetPos = 0x0120, // updated 4.1
|
||||||
ActorCast = 0x0123, // updated 4.1
|
ActorCast = 0x0123, // updated 4.1
|
||||||
|
HateList = 0x0126, // updated 4.1
|
||||||
|
UpdateClassInfo = 0x012A, // updated 4.1
|
||||||
InitUI = 0x012B, // updated 4.1
|
InitUI = 0x012B, // updated 4.1
|
||||||
ActorOwner = 0x012D, // updated 4.1
|
ActorOwner = 0x012D, // updated 4.1
|
||||||
PlayerStats = 0x0138, // updated 4.1
|
PlayerStats = 0x0138, // updated 4.1
|
||||||
|
@ -103,9 +101,6 @@ namespace Packets {
|
||||||
InventoryActionAck = 0x1139,
|
InventoryActionAck = 0x1139,
|
||||||
UpdateInventorySlot = 0x0153, // updated 4.1
|
UpdateInventorySlot = 0x0153, // updated 4.1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EventPlay = 0x0160, // updated 4.1
|
EventPlay = 0x0160, // updated 4.1
|
||||||
EventStart = 0x0169, // updated 4.1
|
EventStart = 0x0169, // updated 4.1
|
||||||
EventFinish = 0x016A, // updated 4.1
|
EventFinish = 0x016A, // updated 4.1
|
||||||
|
@ -119,11 +114,11 @@ namespace Packets {
|
||||||
|
|
||||||
QuestFinish = 0x0180, // updated 4.1
|
QuestFinish = 0x0180, // updated 4.1
|
||||||
|
|
||||||
|
|
||||||
QuestTracker = 0x018D, // updated 4.1
|
QuestTracker = 0x018D, // updated 4.1
|
||||||
ActorSpawn = 0x0190, // todo: split into playerspawn/actorspawn and use opcode 0x110/0x111
|
ActorSpawn = 0x0190, // todo: split into playerspawn/actorspawn and use opcode 0x110/0x111
|
||||||
ActorFreeSpawn = 0x0191, // unchanged for sb
|
ActorFreeSpawn = 0x0191, // unchanged for sb
|
||||||
InitZone = 0x019A, // unchanged for sb
|
InitZone = 0x019A, // unchanged for sb
|
||||||
|
Mount = 0x019F,
|
||||||
WeatherChange = 0x01AF, // updated for sb
|
WeatherChange = 0x01AF, // updated for sb
|
||||||
PlayerTitleList = 0x01BD, // updated for 4.1
|
PlayerTitleList = 0x01BD, // updated for 4.1
|
||||||
Discovery = 0x01BE, // updated for 4.1
|
Discovery = 0x01BE, // updated for 4.1
|
||||||
|
|
|
@ -42,8 +42,8 @@ struct FFXIVIpcInit : FFXIVIpcBasePacket<Init>
|
||||||
*/
|
*/
|
||||||
struct FFXIVIpcChat : FFXIVIpcBasePacket<Chat>
|
struct FFXIVIpcChat : FFXIVIpcBasePacket<Chat>
|
||||||
{
|
{
|
||||||
/* 0000 */ Common::ChatType chatType;
|
/* 0000 */ uint8_t padding[14]; //Maybe this is SubCode, or some kind of talker ID...
|
||||||
uint8_t padding[16]; //Maybe this is SubCode, or some kind of talker ID...
|
Common::ChatType chatType;
|
||||||
char name[32];
|
char name[32];
|
||||||
char msg[1012];
|
char msg[1012];
|
||||||
};
|
};
|
||||||
|
@ -81,7 +81,7 @@ struct FFXIVIpcPlayTime : FFXIVIpcBasePacket<Playtime>
|
||||||
*/
|
*/
|
||||||
struct PlayerEntry {
|
struct PlayerEntry {
|
||||||
uint64_t contentId;
|
uint64_t contentId;
|
||||||
char bytes[12];
|
uint8_t bytes[12];
|
||||||
uint16_t zoneId;
|
uint16_t zoneId;
|
||||||
uint16_t zoneId1;
|
uint16_t zoneId1;
|
||||||
char bytes1[8];
|
char bytes1[8];
|
||||||
|
@ -604,7 +604,8 @@ struct FFXIVIpcActorSetPos : FFXIVIpcBasePacket<ActorSetPos>
|
||||||
struct FFXIVIpcActorCast : FFXIVIpcBasePacket<ActorCast>
|
struct FFXIVIpcActorCast : FFXIVIpcBasePacket<ActorCast>
|
||||||
{
|
{
|
||||||
uint16_t action_id;
|
uint16_t action_id;
|
||||||
uint16_t unknown;
|
Common::SkillType skillType;
|
||||||
|
uint8_t unknown;
|
||||||
uint32_t unknown_1; // Also action id
|
uint32_t unknown_1; // Also action id
|
||||||
float cast_time;
|
float cast_time;
|
||||||
uint32_t target_id;
|
uint32_t target_id;
|
||||||
|
@ -1303,6 +1304,15 @@ struct FFXIVIpcEquipDisplayFlags : FFXIVIpcBasePacket<EquipDisplayFlags>
|
||||||
uint8_t bitmask;
|
uint8_t bitmask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structural representation of the packet sent by the server
|
||||||
|
* to mount a player
|
||||||
|
*/
|
||||||
|
struct FFXIVIpcMount : FFXIVIpcBasePacket<Mount>
|
||||||
|
{
|
||||||
|
uint32_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} /* Server */
|
} /* Server */
|
||||||
} /* Packets */
|
} /* Packets */
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <boost/variant/detail/substitute.hpp>
|
||||||
|
|
||||||
std::string Core::Util::binaryToHexString( uint8_t* pBinData, uint16_t size )
|
std::string Core::Util::binaryToHexString( uint8_t* pBinData, uint16_t size )
|
||||||
{
|
{
|
||||||
|
|
||||||
std::string outStr;
|
std::string outStr;
|
||||||
|
|
||||||
for( uint32_t i = 0; i < size; i++ )
|
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<char>( by );
|
||||||
|
}
|
||||||
|
|
||||||
|
hexColumn += 3;
|
||||||
|
charColumn++;
|
||||||
|
}
|
||||||
|
|
||||||
|
outStr += line + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return outStr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t Core::Util::getTimeMs()
|
uint64_t Core::Util::getTimeMs()
|
||||||
{
|
{
|
||||||
std::chrono::milliseconds epoch = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch());
|
std::chrono::milliseconds epoch = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch());
|
||||||
|
|
|
@ -9,6 +9,8 @@ namespace Util {
|
||||||
|
|
||||||
std::string binaryToHexString( uint8_t* pBinData, uint16_t size );
|
std::string binaryToHexString( uint8_t* pBinData, uint16_t size );
|
||||||
|
|
||||||
|
std::string binaryToHexDump( uint8_t* pBinData, uint16_t size );
|
||||||
|
|
||||||
uint64_t getTimeMs();
|
uint64_t getTimeMs();
|
||||||
|
|
||||||
uint64_t getTimeSeconds();
|
uint64_t getTimeSeconds();
|
||||||
|
|
|
@ -20,11 +20,6 @@ set_target_properties(server_lobby PROPERTIES
|
||||||
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/"
|
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)
|
if (UNIX)
|
||||||
target_link_libraries(server_lobby Common xivdat pthread mysqlclient mysqlConnector dl z)
|
target_link_libraries(server_lobby Common xivdat pthread mysqlclient mysqlConnector dl z)
|
||||||
else()
|
else()
|
||||||
|
|
|
@ -152,7 +152,7 @@ void Core::Network::GameConnection::getCharList( FFXIVARR_PACKET_RAW& packet, ui
|
||||||
|
|
||||||
auto charList = g_restConnector.getCharList( ( char * )m_pSession->getSessionId() );
|
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++ )
|
for( uint8_t i = 0; i < 4; i++ )
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <src/servers/Server_Common/Network/Hive.h>
|
#include <src/servers/Server_Common/Network/Hive.h>
|
||||||
#include <src/servers/Server_Common/Network/Acceptor.h>
|
#include <src/servers/Server_Common/Network/Acceptor.h>
|
||||||
|
|
||||||
|
#include <src/servers/Server_Common/Version.h>
|
||||||
#include <src/servers/Server_Common/Logging/Logger.h>
|
#include <src/servers/Server_Common/Logging/Logger.h>
|
||||||
#include <src/servers/Server_Common/Config/XMLConfig.h>
|
#include <src/servers/Server_Common/Config/XMLConfig.h>
|
||||||
|
|
||||||
|
@ -58,7 +59,8 @@ namespace Core {
|
||||||
|
|
||||||
g_log.info( "===========================================================" );
|
g_log.info( "===========================================================" );
|
||||||
g_log.info( "Sapphire Server Project " );
|
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( "Compiled: " __DATE__ " " __TIME__ );
|
||||||
g_log.info( "===========================================================" );
|
g_log.info( "===========================================================" );
|
||||||
|
|
||||||
|
@ -89,7 +91,7 @@ namespace Core {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::vector<std::string> args( argv + 1, argv + argc );
|
std::vector<std::string> 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 arg( "" );
|
||||||
std::string val( "" );
|
std::string val( "" );
|
||||||
|
|
|
@ -266,7 +266,7 @@ namespace SimpleWeb {
|
||||||
if( content_length>num_additional_bytes ) {
|
if( content_length>num_additional_bytes ) {
|
||||||
auto timer = get_timeout_timer();
|
auto timer = get_timeout_timer();
|
||||||
boost::asio::async_read( *socket, response->content_buffer,
|
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*/ ) {
|
[this, timer]( const boost::system::error_code& ec, size_t /*bytes_transferred*/ ) {
|
||||||
if( timer )
|
if( timer )
|
||||||
timer->cancel();
|
timer->cancel();
|
||||||
|
@ -307,7 +307,7 @@ namespace SimpleWeb {
|
||||||
line.pop_back();
|
line.pop_back();
|
||||||
std::streamsize length = stol( line, 0, 16 );
|
std::streamsize length = stol( line, 0, 16 );
|
||||||
|
|
||||||
auto num_additional_bytes = static_cast<std::streamsize>( response->content_buffer.size() - bytes_transferred );
|
auto num_additional_bytes = response->content_buffer.size() - bytes_transferred;
|
||||||
|
|
||||||
auto post_process = [this, &response, &streambuf, length] {
|
auto post_process = [this, &response, &streambuf, length] {
|
||||||
std::ostream stream( &streambuf );
|
std::ostream stream( &streambuf );
|
||||||
|
@ -332,7 +332,7 @@ namespace SimpleWeb {
|
||||||
if( ( 2 + length )>num_additional_bytes ) {
|
if( ( 2 + length )>num_additional_bytes ) {
|
||||||
auto timer = get_timeout_timer();
|
auto timer = get_timeout_timer();
|
||||||
boost::asio::async_read( *socket, response->content_buffer,
|
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*/ ) {
|
[this, post_process, timer]( const boost::system::error_code& ec, size_t /*bytes_transferred*/ ) {
|
||||||
if( timer )
|
if( timer )
|
||||||
timer->cancel();
|
timer->cancel();
|
||||||
|
|
|
@ -19,11 +19,6 @@ set_target_properties(server_rest PROPERTIES
|
||||||
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/"
|
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)
|
if (UNIX)
|
||||||
target_link_libraries (server_rest Common xivdat pthread mysqlclient mysqlConnector dl z)
|
target_link_libraries (server_rest Common xivdat pthread mysqlclient mysqlConnector dl z)
|
||||||
else()
|
else()
|
||||||
|
|
|
@ -171,7 +171,7 @@ namespace Core {
|
||||||
|
|
||||||
uint16_t size = static_cast< uint16_t >( m_lookMap.size() );
|
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];
|
customize[i] = m_lookMap[i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ bool loadSettings( int32_t argc, char* argv[] )
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> args( argv + 1, argv + argc );
|
std::vector<std::string> 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 arg( "" );
|
||||||
std::string val( "" );
|
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.port = m_pConfig->getValue< uint16_t >( "Settings.General.Mysql.Port", 3306 );
|
||||||
params.username = m_pConfig->getValue< std::string >( "Settings.General.Mysql.Username", "root" );
|
params.username = m_pConfig->getValue< std::string >( "Settings.General.Mysql.Username", "root" );
|
||||||
|
|
||||||
server.config.port = std::stoul( m_pConfig->getValue<std::string>( "Settings.General.HttpPort", "80" ) );
|
server.config.port = static_cast< unsigned short >( std::stoul( m_pConfig->getValue<std::string>( "Settings.General.HttpPort", "80" ) ) );
|
||||||
|
|
||||||
if( !g_database.initialize( params ) )
|
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" );
|
auto path = boost::filesystem::canonical( web_root_path / "news.xml" );
|
||||||
//Check if path is within web_root_path
|
//Check if path is within web_root_path
|
||||||
if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) ||
|
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" );
|
throw invalid_argument( "path must be within root path" );
|
||||||
if( !( boost::filesystem::exists( path ) && boost::filesystem::is_regular_file( path ) ) )
|
if( !( boost::filesystem::exists( path ) && boost::filesystem::is_regular_file( path ) ) )
|
||||||
throw invalid_argument( "file does not exist" );
|
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" );
|
auto path = boost::filesystem::canonical( web_root_path / "headlines.xml" );
|
||||||
//Check if path is within web_root_path
|
//Check if path is within web_root_path
|
||||||
if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) ||
|
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" );
|
throw invalid_argument( "path must be within root path" );
|
||||||
if( !( boost::filesystem::exists( path ) && boost::filesystem::is_regular_file( path ) ) )
|
if( !( boost::filesystem::exists( path ) && boost::filesystem::is_regular_file( path ) ) )
|
||||||
throw invalid_argument( "file does not exist" );
|
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 );
|
auto path = boost::filesystem::canonical( web_root_path / request->path );
|
||||||
//Check if path is within web_root_path
|
//Check if path is within web_root_path
|
||||||
if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) ||
|
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" );
|
throw invalid_argument( "path must be within root path" );
|
||||||
if( boost::filesystem::is_directory( path ) )
|
if( boost::filesystem::is_directory( path ) )
|
||||||
path /= "index.html";
|
path /= "index.html";
|
||||||
|
@ -731,7 +731,7 @@ int main(int argc, char* argv[])
|
||||||
else
|
else
|
||||||
throw invalid_argument( "could not read file" );
|
throw invalid_argument( "could not read file" );
|
||||||
}
|
}
|
||||||
catch( const exception &e )
|
catch( const exception & )
|
||||||
{
|
{
|
||||||
string content = "Path not found: " + request->path;
|
string content = "Path not found: " + request->path;
|
||||||
*response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << content.length() << "\r\n\r\n" << content;
|
*response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << content.length() << "\r\n\r\n" << content;
|
||||||
|
|
|
@ -273,7 +273,7 @@ namespace SimpleWeb {
|
||||||
try {
|
try {
|
||||||
content_length=stoull(it->second);
|
content_length=stoull(it->second);
|
||||||
}
|
}
|
||||||
catch(const std::exception &e) {
|
catch( const std::exception & ) {
|
||||||
if(on_error)
|
if(on_error)
|
||||||
on_error(request, boost::system::error_code(boost::system::errc::protocol_error, boost::system::generic_category()));
|
on_error(request, boost::system::error_code(boost::system::errc::protocol_error, boost::system::generic_category()));
|
||||||
return;
|
return;
|
||||||
|
@ -282,7 +282,7 @@ namespace SimpleWeb {
|
||||||
//Set timeout on the following boost::asio::async-read or write function
|
//Set timeout on the following boost::asio::async-read or write function
|
||||||
auto timer=this->get_timeout_timer(socket, config.timeout_content);
|
auto timer=this->get_timeout_timer(socket, config.timeout_content);
|
||||||
boost::asio::async_read(*socket, request->streambuf,
|
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]
|
[this, socket, request, timer]
|
||||||
(const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
|
(const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
|
||||||
if(timer)
|
if(timer)
|
||||||
|
@ -388,7 +388,7 @@ namespace SimpleWeb {
|
||||||
try {
|
try {
|
||||||
http_version=stof(request->http_version);
|
http_version=stof(request->http_version);
|
||||||
}
|
}
|
||||||
catch(const std::exception &e){
|
catch( const std::exception & ){
|
||||||
if(on_error)
|
if(on_error)
|
||||||
on_error(request, boost::system::error_code(boost::system::errc::protocol_error, boost::system::generic_category()));
|
on_error(request, boost::system::error_code(boost::system::errc::protocol_error, boost::system::generic_category()));
|
||||||
return;
|
return;
|
||||||
|
@ -410,7 +410,7 @@ namespace SimpleWeb {
|
||||||
try {
|
try {
|
||||||
resource_function(response, request);
|
resource_function(response, request);
|
||||||
}
|
}
|
||||||
catch(const std::exception &e) {
|
catch( const std::exception & ) {
|
||||||
if(on_error)
|
if(on_error)
|
||||||
on_error(request, boost::system::error_code(boost::system::errc::operation_canceled, boost::system::generic_category()));
|
on_error(request, boost::system::error_code(boost::system::errc::operation_canceled, boost::system::generic_category()));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -53,7 +53,7 @@ void Core::Action::ActionCast::onStart()
|
||||||
GamePacketNew< FFXIVIpcActorCast, ServerZoneIpcType > castPacket( m_pSource->getId() );
|
GamePacketNew< FFXIVIpcActorCast, ServerZoneIpcType > castPacket( m_pSource->getId() );
|
||||||
|
|
||||||
castPacket.data().action_id = m_id;
|
castPacket.data().action_id = m_id;
|
||||||
castPacket.data().unknown = 1;
|
castPacket.data().skillType = Common::SkillType::Normal;
|
||||||
castPacket.data().unknown_1 = m_id;
|
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().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();
|
castPacket.data().target_id = m_pTarget->getId();
|
||||||
|
|
111
src/servers/Server_Zone/Action/ActionMount.cpp
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#include "ActionMount.h"
|
||||||
|
|
||||||
|
#include <src/servers/Server_Common/Common.h>
|
||||||
|
#include <src/servers/Server_Common/Util/Util.h>
|
||||||
|
#include <src/servers/Server_Common/Util/UtilMath.h>
|
||||||
|
#include <src/servers/Server_Common/Exd/ExdData.h>
|
||||||
|
#include <src/servers/Server_Common/Logging/Logger.h>
|
||||||
|
|
||||||
|
#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 );
|
||||||
|
|
||||||
|
}
|
28
src/servers/Server_Zone/Action/ActionMount.h
Normal file
|
@ -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
|
|
@ -685,7 +685,7 @@ void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint32_t actionId, u
|
||||||
|
|
||||||
case ActionEffectType::Damage:
|
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].effectType = ActionEffectType::Damage;
|
||||||
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage;
|
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage;
|
||||||
effectPacket.data().effects[0].unknown_3 = 7;
|
effectPacket.data().effects[0].unknown_3 = 7;
|
||||||
|
|
|
@ -451,7 +451,7 @@ void Core::Entity::BattleNpc::onDeath()
|
||||||
|
|
||||||
|
|
||||||
// todo: this is actually retarded, we need real rand()
|
// 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();
|
auto pPlayer = pHateEntry->m_pActor->getAsPlayer();
|
||||||
pPlayer->gainExp( exp );
|
pPlayer->gainExp( exp );
|
||||||
|
|
|
@ -38,7 +38,7 @@ float CalcBattle::calculateBaseStat( PlayerPtr pPlayer )
|
||||||
// SB Base Stat Formula (Aligned)
|
// SB Base Stat Formula (Aligned)
|
||||||
if ( level > 60 )
|
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)
|
// HW Base Stat Formula (Aligned)
|
||||||
else if ( level > 50 )
|
else if ( level > 50 )
|
||||||
|
@ -77,7 +77,7 @@ uint32_t CalcBattle::calculateMaxHp( PlayerPtr pPlayer )
|
||||||
// These values are not precise.
|
// These values are not precise.
|
||||||
|
|
||||||
if ( level >= 60 )
|
if ( level >= 60 )
|
||||||
approxBaseHp = 2600 + ( level - 60 ) * 100;
|
approxBaseHp = static_cast< float >( 2600 + ( level - 60 ) * 100 );
|
||||||
else if ( level >= 50 )
|
else if ( level >= 50 )
|
||||||
approxBaseHp = 1700 + ( ( level - 50 ) * ( 1700 * 1.04325f ) );
|
approxBaseHp = 1700 + ( ( level - 50 ) * ( 1700 * 1.04325f ) );
|
||||||
else
|
else
|
||||||
|
|
|
@ -347,7 +347,7 @@ void Core::Entity::Player::teleport( uint16_t aetheryteId, uint8_t type )
|
||||||
|
|
||||||
void Core::Entity::Player::forceZoneing( uint32_t zoneId )
|
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() );
|
//performZoning( zoneId, Common::ZoneingType::None, getPos() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1439,6 +1439,33 @@ uint8_t Core::Entity::Player::getEquipDisplayFlags() const
|
||||||
return m_equipDisplayFlags;
|
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 )
|
void Core::Entity::Player::autoAttack( ActorPtr pTarget )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -197,9 +197,9 @@ public:
|
||||||
// Inventory / Item / Currency
|
// Inventory / Item / Currency
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/*! add an item to the first free slot in one of the 4 main containers */
|
/*! 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 */
|
/*! 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 */
|
/*! equip an item to a specified slot */
|
||||||
void equipItem( Inventory::EquipSlot equipSlotId, ItemPtr pItem, bool sendModel );
|
void equipItem( Inventory::EquipSlot equipSlotId, ItemPtr pItem, bool sendModel );
|
||||||
/*! remove an item from an equipment slot */
|
/*! remove an item from an equipment slot */
|
||||||
|
@ -338,8 +338,14 @@ public:
|
||||||
void setTitle( uint16_t titleId );
|
void setTitle( uint16_t titleId );
|
||||||
/*! change gear param state */
|
/*! change gear param state */
|
||||||
void setEquipDisplayFlags( uint8_t state );
|
void setEquipDisplayFlags( uint8_t state );
|
||||||
/*! get gear param state and send update to inRangeSet */
|
/*! get gear param state */
|
||||||
uint8_t getEquipDisplayFlags() const;
|
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 calculateStats() override;
|
||||||
void sendStats();
|
void sendStats();
|
||||||
|
|
|
@ -189,10 +189,10 @@ void Core::Entity::Player::removeCrystal( uint8_t type, uint32_t amount )
|
||||||
queuePacket( invUpPacket );
|
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 )
|
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;
|
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 )
|
if( m_pInventory->addItem( containerId, -1, catalogId, quantity ) != -1 )
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -864,7 +864,6 @@ void Core::Entity::Player::updateQuest( uint16_t questId, uint8_t sequence )
|
||||||
{
|
{
|
||||||
if( hasQuest( questId ) )
|
if( hasQuest( questId ) )
|
||||||
{
|
{
|
||||||
|
|
||||||
uint8_t index = getQuestIndex( questId );
|
uint8_t index = getQuestIndex( questId );
|
||||||
auto pNewQuest = m_activeQuests[index];
|
auto pNewQuest = m_activeQuests[index];
|
||||||
GamePacketNew< FFXIVIpcQuestUpdate, ServerZoneIpcType > pe_qa( getId() );
|
GamePacketNew< FFXIVIpcQuestUpdate, ServerZoneIpcType > pe_qa( getId() );
|
||||||
|
@ -926,7 +925,7 @@ void Core::Entity::Player::sendQuestTracker()
|
||||||
if( m_questTracking[ii] >= 0 )
|
if( m_questTracking[ii] >= 0 )
|
||||||
{
|
{
|
||||||
trackerPacket.data().entry[ii].active = 1;
|
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 );
|
queuePacket( trackerPacket );
|
||||||
|
@ -1030,7 +1029,7 @@ bool Core::Entity::Player::giveQuestRewards( uint32_t questId, uint32_t optional
|
||||||
|
|
||||||
exp = questInfo->reward_exp_factor;
|
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;
|
uint16_t optionalItemCount = questInfo->reward_item_optional.size() > 0 ? 1 : 0;
|
||||||
|
|
||||||
uint32_t gilReward = questInfo->reward_gil;
|
uint32_t gilReward = questInfo->reward_gil;
|
||||||
|
|
|
@ -35,11 +35,6 @@ set_target_properties(server_zone PROPERTIES
|
||||||
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../bin/"
|
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)
|
if (UNIX)
|
||||||
target_link_libraries ( server_zone Common xivdat pthread mysqlclient mysqlConnector dl z )
|
target_link_libraries ( server_zone Common xivdat pthread mysqlclient mysqlConnector dl z )
|
||||||
else()
|
else()
|
||||||
|
|
|
@ -44,12 +44,13 @@ Core::DebugCommandHandler::DebugCommandHandler()
|
||||||
registerCommand( "set", &DebugCommandHandler::set, "Loads and injects a premade Packet.", 1 );
|
registerCommand( "set", &DebugCommandHandler::set, "Loads and injects a premade Packet.", 1 );
|
||||||
registerCommand( "get", &DebugCommandHandler::get, "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( "add", &DebugCommandHandler::add, "Loads and injects a premade Packet.", 1 );
|
||||||
registerCommand( "inject", &DebugCommandHandler::injectPacket, "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( "injectc", &DebugCommandHandler::injectChatPacket, "Loads and injects a premade chat packet.", 1 );
|
||||||
registerCommand( "script_reload", &DebugCommandHandler::scriptReload, "Loads and injects a premade Packet.", 1 );
|
registerCommand( "script_reload", &DebugCommandHandler::scriptReload, "Reload all server scripts", 1 );
|
||||||
registerCommand( "nudge", &DebugCommandHandler::nudge, "Nudges you forward/up/down", 1 );
|
registerCommand( "nudge", &DebugCommandHandler::nudge, "Nudges you forward/up/down", 1 );
|
||||||
registerCommand( "info", &DebugCommandHandler::serverInfo, "Send server info", 0 );
|
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
|
// clear all loaded commands
|
||||||
|
@ -121,6 +122,18 @@ void Core::DebugCommandHandler::scriptReload( char * data, Core::Entity::PlayerP
|
||||||
pPlayer->sendDebug( "Scripts reloaded." );
|
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<Core::DebugCommand> command )
|
void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlayer, boost::shared_ptr<Core::DebugCommand> command )
|
||||||
{
|
{
|
||||||
std::string subCommand = "";
|
std::string subCommand = "";
|
||||||
|
@ -258,6 +271,14 @@ void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlaye
|
||||||
pPlayer->sendModel();
|
pPlayer->sendModel();
|
||||||
pPlayer->sendDebug( "Model updated" );
|
pPlayer->sendDebug( "Model updated" );
|
||||||
}
|
}
|
||||||
|
else if ( subCommand == "mount" )
|
||||||
|
{
|
||||||
|
int32_t id;
|
||||||
|
sscanf( params.c_str(), "%d", &id );
|
||||||
|
|
||||||
|
pPlayer->dismount();
|
||||||
|
pPlayer->mount( id );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pPlayer->sendUrgent( subCommand + " is not a valid SET command." );
|
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( "Compiled: " __DATE__ " " __TIME__ );
|
||||||
pPlayer->sendDebug( "Sessions: " + std::to_string( g_serverZone.getSessionCount() ) );
|
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( );
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,9 @@ public:
|
||||||
// execute command if registered
|
// execute command if registered
|
||||||
void execCommand( char * data, Entity::PlayerPtr pPlayer );
|
void execCommand( char * data, Entity::PlayerPtr pPlayer );
|
||||||
|
|
||||||
|
// help command
|
||||||
|
void help( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
|
|
||||||
// command handler callbacks
|
// command handler callbacks
|
||||||
void set( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
void set( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
void get( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
void get( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
|
@ -39,6 +42,9 @@ public:
|
||||||
void nudge( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
void nudge( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
void serverInfo( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
void serverInfo( char * data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
|
|
||||||
|
void unlockCharacter( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
|
void targetInfo( char* data, Entity::PlayerPtr pPlayer, boost::shared_ptr<DebugCommand> command );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ namespace Core
|
||||||
TYPE_FORWARD( Action );
|
TYPE_FORWARD( Action );
|
||||||
TYPE_FORWARD( ActionTeleport );
|
TYPE_FORWARD( ActionTeleport );
|
||||||
TYPE_FORWARD( ActionCast );
|
TYPE_FORWARD( ActionCast );
|
||||||
|
TYPE_FORWARD( ActionMount );
|
||||||
TYPE_FORWARD( EventAction );
|
TYPE_FORWARD( EventAction );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ Core::Inventory::InvSlotPairVec Core::Inventory::getSlotsOfItemsInInventory( uin
|
||||||
for( auto item : inv->getItemMap() )
|
for( auto item : inv->getItemMap() )
|
||||||
{
|
{
|
||||||
if( item.second && item.second->getId() == catalogId )
|
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;
|
return outVec;
|
||||||
|
@ -118,7 +118,7 @@ Core::Inventory::InvSlotPair Core::Inventory::getFreeBagSlot()
|
||||||
{
|
{
|
||||||
for( auto i : { Bag0, Bag1, Bag2, Bag3 } )
|
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 )
|
if( freeSlot != -1 )
|
||||||
return std::make_pair( i, freeSlot );
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t rSlotId = -1;
|
int8_t rSlotId = -1;
|
||||||
|
|
||||||
//if( itemInfo->stack_size > 1 )
|
//if( itemInfo->stack_size > 1 )
|
||||||
//{
|
//{
|
||||||
|
|
|
@ -29,7 +29,7 @@ bool Core::LinkshellMgr::loadLinkshells()
|
||||||
|
|
||||||
do
|
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 >();
|
uint32_t masterId = field[1].get< uint32_t >();
|
||||||
std::string name = field[3].getString();
|
std::string name = field[3].getString();
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ typedef boost::shared_ptr< Linkshell > LinkshellPtr;
|
||||||
class LinkshellMgr
|
class LinkshellMgr
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::map< uint32_t, LinkshellPtr > m_linkshellIdMap;
|
std::map< uint64_t, LinkshellPtr > m_linkshellIdMap;
|
||||||
std::map< std::string, LinkshellPtr > m_linkshellNameMap;
|
std::map< std::string, LinkshellPtr > m_linkshellNameMap;
|
||||||
|
|
||||||
LinkshellPtr getLinkshellByName( const std::string& name );
|
LinkshellPtr getLinkshellByName( const std::string& name );
|
||||||
|
|
|
@ -206,7 +206,7 @@ void Core::Network::GameConnection::handleZonePacket( const Packets::GamePacket&
|
||||||
g_log.debug( sessionStr + " Undefined Zone IPC : Unknown ( " +
|
g_log.debug( sessionStr + " Undefined Zone IPC : Unknown ( " +
|
||||||
boost::str( boost::format( "%|04X|" ) %
|
boost::str( boost::format( "%|04X|" ) %
|
||||||
static_cast< uint32_t >( pPacket.getSubType() & 0xFFFF ) ) + " )" );
|
static_cast< uint32_t >( pPacket.getSubType() & 0xFFFF ) ) + " )" );
|
||||||
g_log.debug( pPacket.toString() );
|
g_log.debug( "\n" + pPacket.toString() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,11 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in
|
||||||
pPlayer->changeTarget( targetId );
|
pPlayer->changeTarget( targetId );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 0x65:
|
||||||
|
{
|
||||||
|
pPlayer->dismount();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 0x68: // Remove status (clicking it off)
|
case 0x68: // Remove status (clicking it off)
|
||||||
{
|
{
|
||||||
// todo: check if status can be removed by client from exd
|
// 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
|
case 0x12E: // Set player title
|
||||||
{
|
{
|
||||||
pPlayer->setTitle( param1 );
|
pPlayer->setTitle( static_cast< uint16_t >( param1 ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x12F: // Get title list
|
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 );
|
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
|
// 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 ) +
|
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;
|
pow( fromAetheryte->map_coord_y - targetAetheryte->map_coord_y, 2 ) ) / 2 ) + 100 );
|
||||||
|
|
||||||
// cap at 999 gil
|
// cap at 999 gil
|
||||||
cost = cost > 999 ? 999 : cost;
|
cost = cost > 999 ? 999 : cost;
|
||||||
|
|
|
@ -141,7 +141,7 @@ void Core::Network::GameConnection::eventHandler( const Packets::GamePacket& inP
|
||||||
|
|
||||||
GamePacketNew< FFXIVIpcEventLinkshell, ServerZoneIpcType > linkshellEvent( pPlayer->getId() );
|
GamePacketNew< FFXIVIpcEventLinkshell, ServerZoneIpcType > linkshellEvent( pPlayer->getId() );
|
||||||
linkshellEvent.data().eventId = eventId;
|
linkshellEvent.data().eventId = eventId;
|
||||||
linkshellEvent.data().scene = subEvent;
|
linkshellEvent.data().scene = static_cast< uint8_t >(subEvent);
|
||||||
linkshellEvent.data().param3 = 1;
|
linkshellEvent.data().param3 = 1;
|
||||||
linkshellEvent.data().unknown1 = 0x15a;
|
linkshellEvent.data().unknown1 = 0x15a;
|
||||||
pPlayer->queuePacket( linkshellEvent );
|
pPlayer->queuePacket( linkshellEvent );
|
||||||
|
|
|
@ -282,13 +282,16 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
|
||||||
}
|
}
|
||||||
case GmCommand::Teri:
|
case GmCommand::Teri:
|
||||||
{
|
{
|
||||||
if( param1 < 128 )
|
auto zoneInfo = g_zoneMgr.getZone( param1 );
|
||||||
pPlayer->sendUrgent( "Zone ID out of range." );
|
if ( !zoneInfo )
|
||||||
|
{
|
||||||
|
pPlayer->sendUrgent( "Invalid zone " + std::to_string( param1 ) );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
targetPlayer->setPosition( targetPlayer->getPos() );
|
targetPlayer->setPosition( targetPlayer->getPos() );
|
||||||
targetPlayer->performZoning( param1, targetPlayer->getPos(), 0 );
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,10 @@
|
||||||
#include "src/servers/Server_Zone/Forwards.h"
|
#include "src/servers/Server_Zone/Forwards.h"
|
||||||
|
|
||||||
#include "src/servers/Server_Zone/Action/Action.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/ActionCast.h"
|
||||||
|
#include "src/servers/Server_Zone/Action/ActionMount.h"
|
||||||
#include "src/servers/Server_Zone/Script/ScriptManager.h"
|
#include "src/servers/Server_Zone/Script/ScriptManager.h"
|
||||||
|
#include "Server_Zone/Network/PacketWrappers/MoveActorPacket.h"
|
||||||
|
|
||||||
|
|
||||||
extern Core::Scripting::ScriptManager g_scriptMgr;
|
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,
|
void Core::Network::GameConnection::skillHandler( const Packets::GamePacket& inPacket,
|
||||||
Entity::PlayerPtr pPlayer )
|
Entity::PlayerPtr pPlayer )
|
||||||
{
|
{
|
||||||
|
uint8_t type = inPacket.getValAt< uint32_t >( 0x21 );
|
||||||
|
|
||||||
uint32_t action = inPacket.getValAt< uint32_t >( 0x24 );
|
uint32_t action = inPacket.getValAt< uint32_t >( 0x24 );
|
||||||
uint32_t useCount = inPacket.getValAt< uint32_t >( 0x28 );
|
uint32_t useCount = inPacket.getValAt< uint32_t >( 0x28 );
|
||||||
|
|
||||||
uint64_t targetId = inPacket.getValAt< uint64_t >( 0x30 );
|
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
|
if( action < 1000000 ) // normal action
|
||||||
{
|
{
|
||||||
std::string actionIdStr = boost::str( boost::format( "%|04X|" ) % 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -64,6 +64,9 @@ private:
|
||||||
|
|
||||||
memcpy( m_data.orchestrionMask, player->getOrchestrionBitmask(), sizeof( m_data.orchestrionMask ) );
|
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.unlockBitmask, player->getUnlockBitmask(), sizeof( m_data.unlockBitmask ) );
|
||||||
|
|
||||||
memcpy( m_data.discovery, player->getDiscoveryBitmask(), sizeof( m_data.discovery ) );
|
memcpy( m_data.discovery, player->getDiscoveryBitmask(), sizeof( m_data.discovery ) );
|
||||||
|
|
|
@ -111,6 +111,8 @@ namespace Server {
|
||||||
m_data.displayFlags |= Entity::Actor::DisplayFlags::Visor;
|
m_data.displayFlags |= Entity::Actor::DisplayFlags::Visor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_data.currentMount = pPlayer->getCurrentMount();
|
||||||
|
|
||||||
m_data.targetId = pPlayer->getTargetId();
|
m_data.targetId = pPlayer->getTargetId();
|
||||||
//m_data.type = 1;
|
//m_data.type = 1;
|
||||||
//m_data.unknown_33 = 4;
|
//m_data.unknown_33 = 4;
|
||||||
|
|
|
@ -91,7 +91,7 @@ bool Core::Scripting::ScriptManager::onTalk( Core::Entity::PlayerPtr pPlayer, ui
|
||||||
std::string objName = Event::getEventName( eventId );
|
std::string objName = Event::getEventName( eventId );
|
||||||
|
|
||||||
pPlayer->sendDebug("Actor: " +
|
pPlayer->sendDebug("Actor: " +
|
||||||
std::to_string( actorId ) +
|
std::to_string( actorId ) + " -> " + std::to_string( Core::Event::mapEventActorToRealActor( static_cast< uint32_t >( actorId ) ) ) +
|
||||||
" \neventId: " +
|
" \neventId: " +
|
||||||
std::to_string( eventId ) +
|
std::to_string( eventId ) +
|
||||||
" (0x" + boost::str( boost::format( "%|08X|" )
|
" (0x" + boost::str( boost::format( "%|08X|" )
|
||||||
|
@ -114,18 +114,18 @@ bool Core::Scripting::ScriptManager::onTalk( Core::Entity::PlayerPtr pPlayer, ui
|
||||||
}
|
}
|
||||||
catch( std::exception& e )
|
catch( std::exception& e )
|
||||||
{
|
{
|
||||||
|
pPlayer->sendDebug( e.what( ) );
|
||||||
|
|
||||||
if( eventType == Common::EventType::Quest )
|
if( eventType == Common::EventType::Quest )
|
||||||
{
|
{
|
||||||
auto questInfo = g_exdData.getQuestInfo( eventId );
|
auto questInfo = g_exdData.getQuestInfo( eventId );
|
||||||
if( questInfo )
|
if( questInfo )
|
||||||
{
|
{
|
||||||
pPlayer->sendDebug( "Quest not implemented: " + questInfo->name + "\n" + e.what() );
|
pPlayer->sendUrgent( "Quest not implemented: " + questInfo->name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pPlayer->sendDebug( e.what() );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -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::returnToHomepoint ), "returnToHomepoint" );
|
||||||
m_pChaiHandler->add( chaiscript::fun( &Entity::Player::teleport ), "teleport" );
|
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::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::getCurrency ), "getCurrency" );
|
||||||
m_pChaiHandler->add( chaiscript::fun( &Entity::Player::addCurrency ), "addCurrency" );
|
m_pChaiHandler->add( chaiscript::fun( &Entity::Player::addCurrency ), "addCurrency" );
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "ServerZone.h"
|
#include "ServerZone.h"
|
||||||
|
|
||||||
|
#include <src/servers/Server_Common/Version.h>
|
||||||
#include <src/servers/Server_Common/Logging/Logger.h>
|
#include <src/servers/Server_Common/Logging/Logger.h>
|
||||||
#include <src/servers/Server_Common/Config/XMLConfig.h>
|
#include <src/servers/Server_Common/Config/XMLConfig.h>
|
||||||
#include <src/servers/Server_Common/Database/Database.h>
|
#include <src/servers/Server_Common/Database/Database.h>
|
||||||
|
@ -375,7 +376,8 @@ void Core::ServerZone::printBanner() const
|
||||||
{
|
{
|
||||||
g_log.info("===========================================================" );
|
g_log.info("===========================================================" );
|
||||||
g_log.info( "Sapphire Server Project " );
|
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( "Compiled: " __DATE__ " " __TIME__ );
|
||||||
g_log.info( "===========================================================" );
|
g_log.info( "===========================================================" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,9 @@ if (UNIX)
|
||||||
target_link_libraries (exd_common_gen Common xivdat pthread mysqlclient dl z)
|
target_link_libraries (exd_common_gen Common xivdat pthread mysqlclient dl z)
|
||||||
else()
|
else()
|
||||||
target_link_libraries (exd_common_gen Common xivdat libmysql zlib1)
|
target_link_libraries (exd_common_gen Common xivdat libmysql zlib1)
|
||||||
|
|
||||||
|
# ignore unchecked iterators warnings from msvc
|
||||||
|
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(exd_common_gen ${Boost_LIBRARIES} ${Boost_LIBRARIES})
|
target_link_libraries(exd_common_gen ${Boost_LIBRARIES} ${Boost_LIBRARIES})
|
||||||
|
|
|
@ -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("../")
|
include_directories("../")
|
||||||
|
|
||||||
file(GLOB SERVER_PUBLIC_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*")
|
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})
|
#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "../bin/")
|
||||||
link_directories(${SERVER_COMMON_DIR})
|
add_executable(pcb_reader2 ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES})
|
||||||
#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ".")
|
|
||||||
add_executable(pcb_parser2 ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES})
|
|
||||||
|
|
||||||
target_link_libraries (pcb_parser2 server_common.a pthread mysqlclient dl z)
|
set_target_properties(pcb_reader2 PROPERTIES
|
||||||
target_link_libraries(pcb_parser2 ${Boost_LIBRARIES} ${Boost_LIBRARIES})
|
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})
|
||||||
|
|
||||||
|
|
280
src/tools/pcb_reader/lgb.h
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
#ifndef _LGB_H
|
||||||
|
#define _LGB_H
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#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<LGB_BGPARTS_HEADER*>( 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<LGB_GIMMICK_HEADER*>( 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<std::shared_ptr<LGB_MODEL_ENTRY>> entries;
|
||||||
|
|
||||||
|
LGB_GROUP( char* buf, LGB_FILE* parentStruct, uint32_t offset )
|
||||||
|
{
|
||||||
|
parent = parentStruct;
|
||||||
|
header = *reinterpret_cast<LGB_GROUP_HEADER*>( 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<int32_t*>( buf + ( entriesOffset + i * 4 ) );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto type = *reinterpret_cast<LgbEntryType*>( buf + entryOffset );
|
||||||
|
if( type == LgbEntryType::BgParts )
|
||||||
|
{
|
||||||
|
entries.push_back( std::make_shared<LGB_BGPARTS_ENTRY>( buf, entryOffset ) );
|
||||||
|
}
|
||||||
|
else if( type == LgbEntryType::Gimmick )
|
||||||
|
{
|
||||||
|
entries.push_back( std::make_shared<LGB_GIMMICK_ENTRY>( 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<LGB_GROUP> groups;
|
||||||
|
|
||||||
|
LGB_FILE( char* buf )
|
||||||
|
{
|
||||||
|
header = *reinterpret_cast<LGB_FILE_HEADER*>( 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<int32_t*>( buf + ( baseOffset + i * 4 ) );
|
||||||
|
const auto group = LGB_GROUP( buf, this, groupOffset );
|
||||||
|
groups.push_back( group );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
#include <experimental/filesystem>
|
||||||
|
std::map<std::string, LGB_FILE> getLgbFiles( const std::string& dir )
|
||||||
|
{
|
||||||
|
namespace fs = std::experimental::filesystem;
|
||||||
|
std::map<std::string, LGB_FILE> 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<char> 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
|
|
@ -1,10 +1,28 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <string.h>
|
#include <string>
|
||||||
|
|
||||||
#include "pcb.h"
|
#include "pcb.h"
|
||||||
|
#include "lgb.h"
|
||||||
|
#include "sgb.h"
|
||||||
|
|
||||||
|
#include <GameData.h>
|
||||||
|
#include <File.h>
|
||||||
|
#include <DatCat.h>
|
||||||
|
#include <ExdData.h>
|
||||||
|
#include <ExdCat.h>
|
||||||
|
#include <Exd.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
struct face
|
||||||
|
{
|
||||||
|
int32_t f1, f2, f3;
|
||||||
|
};
|
||||||
|
|
||||||
int parseBlockEntry( char* data, std::vector<PCB_BLOCK_ENTRY>& entries, int gOff )
|
int parseBlockEntry( char* data, std::vector<PCB_BLOCK_ENTRY>& entries, int gOff )
|
||||||
{
|
{
|
||||||
|
@ -14,7 +32,7 @@ int parseBlockEntry( char* data, std::vector<PCB_BLOCK_ENTRY>& entries, int gOff
|
||||||
{
|
{
|
||||||
PCB_BLOCK_ENTRY block_entry;
|
PCB_BLOCK_ENTRY block_entry;
|
||||||
memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) );
|
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 );
|
//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<PCB_BLOCK_ENTRY>& entries, int gOff
|
||||||
{
|
{
|
||||||
parseBlockEntry( data + offset + 0x30, entries, gOff + offset );
|
parseBlockEntry( data + offset + 0x30, entries, gOff + offset );
|
||||||
offset += block_entry.header.group_size;
|
offset += block_entry.header.group_size;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf( "\tnum_v16: %i, num_indices: %i, num_vertices: %i\n\n",
|
/* 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 );
|
block_entry.header.num_v16, block_entry.header.num_indices, block_entry.header.num_vertices );*/
|
||||||
int doffset = sizeof( block_entry.header ) + offset;
|
int doffset = sizeof( block_entry.header ) + offset;
|
||||||
uint16_t block_size = sizeof( block_entry.header ) +
|
uint16_t block_size = sizeof( block_entry.header ) +
|
||||||
block_entry.header.num_vertices * 3 * 4 +
|
block_entry.header.num_vertices * 3 * 4 +
|
||||||
|
@ -52,207 +69,365 @@ int parseBlockEntry( char* data, std::vector<PCB_BLOCK_ENTRY>& entries, int gOff
|
||||||
if( block_entry.header.num_indices != 0 )
|
if( block_entry.header.num_indices != 0 )
|
||||||
{
|
{
|
||||||
block_entry.data.indices.resize( block_entry.header.num_indices );
|
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 );
|
memcpy( &block_entry.data.indices[0], data + doffset, size_indexbuffer );
|
||||||
doffset += size_indexbuffer;
|
doffset += size_indexbuffer;
|
||||||
}
|
}
|
||||||
entries.push_back( block_entry );
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
std::string zoneNameToPath( const std::string& name )
|
||||||
{
|
{
|
||||||
char *data;
|
char teri = name[0];
|
||||||
|
char region = name[1];
|
||||||
uint32_t offset = 0;
|
char type = name[2];
|
||||||
//r1f1_b1_dor00.pcb
|
char zone = name[3];
|
||||||
|
static std::map<char, std::string> teriMap
|
||||||
//std::string filename( "f1h0_s_rof0003.pcb" );
|
|
||||||
std::string filename( "tr0924.pcb" );
|
|
||||||
FILE *fp = nullptr;
|
|
||||||
fp = fopen( filename.c_str(), "rb" );
|
|
||||||
if( fp == nullptr )
|
|
||||||
{
|
{
|
||||||
return 0;
|
{ 'r', "roc" },
|
||||||
}
|
{ 'w', "wil" },
|
||||||
|
{ 'l', "lak" },
|
||||||
|
{ 'o', "ocn" },
|
||||||
|
{ 'f', "fst" },
|
||||||
|
{ 'a', "air" },
|
||||||
|
{ 's', "sea" },
|
||||||
|
{ 'z', "zon" }
|
||||||
|
};
|
||||||
|
|
||||||
fseek( fp, 0, SEEK_END );
|
static std::map<char, std::string> typeMap
|
||||||
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<PCB_BLOCK_ENTRY> entries;
|
|
||||||
|
|
||||||
bool isgroup = true;
|
|
||||||
while( isgroup )
|
|
||||||
{
|
{
|
||||||
PCB_BLOCK_ENTRY block_entry;
|
{ 'f', "fld" },
|
||||||
memcpy( &block_entry.header, data + offset, sizeof( block_entry.header ) );
|
{ 't', "twn" },
|
||||||
isgroup = block_entry.header.type == 0x30 ? true : false;
|
{ '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 );
|
int main( int argc, char* argv[] )
|
||||||
|
{
|
||||||
if( isgroup )
|
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<uint8_t> data_block( block_entry.header.group_size );
|
zoneName = argv[2];
|
||||||
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;
|
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<std::string> 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
|
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<std::string, PCB_FILE> pcbFiles;
|
||||||
|
std::map<std::string, SGB_FILE> sgbFiles;
|
||||||
|
std::map<std::string, uint32_t> 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<LGB_GIMMICK_ENTRY*>( pEntry.get() );
|
||||||
|
auto pBgParts = dynamic_cast<LGB_BGPARTS_ENTRY*>( 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<SGB_MODEL_ENTRY*>( 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::seconds>( std::chrono::system_clock::now() - startTime ).count() << " seconds\n";
|
||||||
}
|
}
|
||||||
|
catch( std::exception& e )
|
||||||
for( uint16_t i = 0; i <= pcb_file.header.num_entries; i++ )
|
|
||||||
{
|
{
|
||||||
PCB_BLOCK_ENTRY block_entry;
|
std::cout << e.what() << std::endl;
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
100
src/tools/pcb_reader/matrix4.h
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
#ifndef _MATRIX4_H
|
||||||
|
#define _MATRIX4_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
// 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
|
|
@ -1,3 +1,6 @@
|
||||||
|
#ifndef _PCB_H
|
||||||
|
#define _PCB_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -6,7 +9,7 @@ struct PCB_HEADER
|
||||||
uint32_t unknown_1;
|
uint32_t unknown_1;
|
||||||
uint32_t unknown_2;
|
uint32_t unknown_2;
|
||||||
uint32_t num_entries; // count starts at 0
|
uint32_t num_entries; // count starts at 0
|
||||||
uint32_t total_indices;
|
uint32_t total_indices;
|
||||||
uint64_t padding;
|
uint64_t padding;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,13 +18,13 @@ struct PCB_BLOCK_HEADER
|
||||||
uint32_t type; // 0 for entry, 0x30 for group
|
uint32_t type; // 0 for entry, 0x30 for group
|
||||||
uint32_t group_size; // when group size in bytes for the group block
|
uint32_t group_size; // when group size in bytes for the group block
|
||||||
// bounding box
|
// bounding box
|
||||||
float x;
|
float x;
|
||||||
float y;
|
float y;
|
||||||
float z;
|
float z;
|
||||||
float x1;
|
float x1;
|
||||||
float y1;
|
float y1;
|
||||||
float z1;
|
float z1;
|
||||||
// number of vertices packed into 16 bit
|
// number of vertices packed into 16 bit
|
||||||
uint16_t num_v16;
|
uint16_t num_v16;
|
||||||
// number of indices
|
// number of indices
|
||||||
uint16_t num_indices;
|
uint16_t num_indices;
|
||||||
|
@ -40,6 +43,7 @@ struct PCB_INDEXDATA
|
||||||
{
|
{
|
||||||
uint8_t index[3];
|
uint8_t index[3];
|
||||||
uint8_t unknown[3];
|
uint8_t unknown[3];
|
||||||
|
uint8_t unknown1[6];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PCB_VERTEXDATAI16
|
struct PCB_VERTEXDATAI16
|
||||||
|
@ -67,3 +71,22 @@ struct PCB_FILE
|
||||||
PCB_HEADER header;
|
PCB_HEADER header;
|
||||||
std::vector< PCB_BLOCK_ENTRY > entries;
|
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<PCB_LIST_ENTRY> entries;
|
||||||
|
};
|
||||||
|
#endif
|
202
src/tools/pcb_reader/sgb.h
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
#ifndef _SGB_H
|
||||||
|
#define _SGB_H
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#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<SGB_MODEL_HEADER*>( 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<std::shared_ptr<SGB_GROUP_ENTRY>> entries;
|
||||||
|
|
||||||
|
SGB_GROUP( char* buf, SGB_FILE* file, uint32_t fileSize, uint32_t offset )
|
||||||
|
{
|
||||||
|
parent = file;
|
||||||
|
header = *reinterpret_cast<SGB_GROUP_HEADER*>( 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<uint32_t*>( 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<uint32_t*>( buf + entryOffset );
|
||||||
|
if( type == SgbGroupEntryType::Model )
|
||||||
|
{
|
||||||
|
entries.push_back( std::make_shared<SGB_MODEL_ENTRY>( 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<SGB_GROUP> entries;
|
||||||
|
|
||||||
|
SGB_FILE()
|
||||||
|
{
|
||||||
|
memset( &header, 0, sizeof( header ) );
|
||||||
|
}
|
||||||
|
SGB_FILE( char* buf )
|
||||||
|
{
|
||||||
|
constexpr int baseOffset = 0x14;
|
||||||
|
header = *reinterpret_cast<SGB_HEADER*>( 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
|
31
src/tools/pcb_reader/vec3.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef _VEC3_H
|
||||||
|
#define _VEC3_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#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
|
|
@ -91,7 +91,7 @@ void createScript( boost::shared_ptr< Core::Data::QuestInfo > pQuestData, std::s
|
||||||
if( pQuestData->reward_item.size() > 0 )
|
if( pQuestData->reward_item.size() > 0 )
|
||||||
{
|
{
|
||||||
rewards += " this.RewardItem = [";
|
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 ) );
|
rewards += std::to_string( pQuestData->reward_item.at( ca ) );
|
||||||
if( ca != pQuestData->reward_item.size() - 1 )
|
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 )
|
if( pQuestData->reward_item.size() > 0 )
|
||||||
{
|
{
|
||||||
rewards += " this.RewardItemCount = [";
|
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 ) );
|
rewards += std::to_string( pQuestData->reward_item_count.at( ca ) );
|
||||||
if( ca != pQuestData->reward_item_count.size() - 1 )
|
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 )
|
if( pQuestData->reward_item_optional.size() > 0 )
|
||||||
{
|
{
|
||||||
rewards += " this.RewardItemOptional = [";
|
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 ) );
|
rewards += std::to_string( pQuestData->reward_item_optional.at( ca ) );
|
||||||
if( ca != pQuestData->reward_item_optional.size() - 1 )
|
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 )
|
if( pQuestData->reward_item_optional_count.size() > 0 )
|
||||||
{
|
{
|
||||||
rewards += " this.RewardItemOptionalCount = [";
|
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 ) );
|
rewards += std::to_string( pQuestData->reward_item_optional_count.at( ca ) );
|
||||||
if( ca != pQuestData->reward_item_optional_count.size() - 1 )
|
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::vector< std::string > script_entities;
|
||||||
std::string sentities = " // Entities found in the script data of the quest\n";
|
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 ) )
|
if( ( pQuestData->script_entity.at( ca ).find( "HOWTO" ) != std::string::npos ) || ( pQuestData->script_entity.at( ca ).find( "HOW_TO" ) != std::string::npos ) )
|
||||||
continue;
|
continue;
|
||||||
|
|