1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-28 07:07:45 +00:00

Merge remote-tracking branch 'origin/develop'

This commit is contained in:
Mordred 2019-01-13 17:45:32 +01:00
commit b41ac00875
64 changed files with 1553 additions and 1240 deletions

View file

@ -11,6 +11,7 @@ else()
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" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4834" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4834" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17" )
set( CMAKE_CXX_STANDARD 17 ) set( CMAKE_CXX_STANDARD 17 )
set( CMAKE_CXX_STANDARD_REQUIRED ON ) set( CMAKE_CXX_STANDARD_REQUIRED ON )

3
config/api.ini.default Normal file
View file

@ -0,0 +1,3 @@
[Network]
ListenIp = 0.0.0.0
ListenPort = 80

View file

@ -1,62 +0,0 @@
[Database]
Host = 127.0.0.1
Port = 3306
Database = sapphire
Username = sapphire
Password =
SyncThreads = 2
AsyncThreads = 2
[GlobalParameters]
ServerSecret = default
DataPath = C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack
[GlobalNetwork]
; Values definining how Users and other servers will access - these have to be set to your public IP when running a public server
ZoneHost = 127.0.0.1
ZonePort = 54992
LobbyHost = 127.0.0.1
LobbyPort = 54994
RestHost = 127.0.0.1
RestPort = 80
[Lobby]
WorldID = 67
AllowNoSessionConnect = false
WorldName = Sapphire
[LobbyNetwork]
ListenIp = 0.0.0.0
ListenPort = 54994
[CharacterCreation]
DefaultGMRank = 255
[RestNetwork]
ListenIp = 0.0.0.0
ListenPort = 80
[Scripts]
; where compiled script modules are located
Path = ./compiledscripts/
; relative to Path, where we copy and load modules from
CachePath = ./cache/
; whether we should detect changes to script modules and reload them
HotSwap = true
[Network]
DisconnectTimeout = 20
[ZoneNetwork]
ListenIp = 0.0.0.0
ListenPort = 54992
[General]
; Sent on login - each line must be shorter than 307 characters, split lines with ';'
MotD = Welcome to Sapphire!;This is a very good server;You can change these messages by editing General.MotD in config/config.ini
[Housing]
; Set the default estate name. %i will be replaced with the plot number
DefaultEstateName = Estate #%i

25
config/global.ini.default Normal file
View file

@ -0,0 +1,25 @@
[Database]
Host = 127.0.0.1
Port = 3306
Database = sapphire
Username = sapphire
Password =
SyncThreads = 2
AsyncThreads = 2
[General]
ServerSecret = default
DataPath = C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack
WorldID = 67
DefaultGMRank = 255
[Network]
; Values definining how Users and other servers will access - these have to be set to your public IP when running a public server
ZoneHost = 127.0.0.1
ZonePort = 54992
LobbyHost = 127.0.0.1
LobbyPort = 54994
RestHost = 127.0.0.1
RestPort = 80

7
config/lobby.ini.default Normal file
View file

@ -0,0 +1,7 @@
[Lobby]
AllowNoSessionConnect = false
WorldName = Sapphire
[Network]
ListenIp = 0.0.0.0
ListenPort = 54994

20
config/world.ini.default Normal file
View file

@ -0,0 +1,20 @@
[Scripts]
; where compiled script modules are located
Path = ./compiledscripts/
; relative to Path, where we copy and load modules from
CachePath = ./cache/
; whether we should detect changes to script modules and reload them
HotSwap = true
[Network]
ListenIp = 0.0.0.0
ListenPort = 54992
DisconnectTimeout = 20
[General]
; Sent on login - each line must be shorter than 307 characters, split lines with ';'
MotD = Welcome to Sapphire!;This is a very good server;You can change these messages by editing General.MotD in config/config.ini
[Housing]
; Set the default estate name. {0} will be replaced with the plot number
DefaultEstateName = Estate ${0}

File diff suppressed because one or more lines are too long

View file

@ -34,7 +34,7 @@ CREATE TABLE `spawnpoint` (
`y` float NOT NULL, `y` float NOT NULL,
`z` float NOT NULL, `z` float NOT NULL,
`r` float NOT NULL, `r` float NOT NULL,
`gimmickId` int(11) NOT NULL, `gimmickId` int(11) DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `spawngroupidx` (`spawnGroupId`) KEY `spawngroupidx` (`spawnGroupId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
@ -576,10 +576,10 @@ CREATE TABLE `zonepositions` (
CREATE TABLE `landplaceditems` ( CREATE TABLE `landplaceditems` (
`ItemId` INT(20) UNSIGNED NOT NULL, `ItemId` INT(20) UNSIGNED NOT NULL,
`PosX` INT(10) NOT NULL, `PosX` FLOAT NOT NULL,
`PosY` INT(10) NOT NULL, `PosY` FLOAT NOT NULL,
`PosZ` INT(10) NOT NULL, `PosZ` FLOAT NOT NULL,
`Rotation` INT(10) NOT NULL, `Rotation` FLOAT NOT NULL,
PRIMARY KEY (`ItemId`) PRIMARY KEY (`ItemId`)
) )
COLLATE='latin1_swedish_ci' ENGINE=InnoDB; COLLATE='latin1_swedish_ci' ENGINE=InnoDB;

View file

@ -49,18 +49,42 @@ void default_resource_send( const HttpServer& server, const shared_ptr< HttpServ
const shared_ptr< ifstream >& ifs ); const shared_ptr< ifstream >& ifs );
auto m_pConfig = std::make_shared< Sapphire::ConfigMgr >();
HttpServer server; HttpServer server;
std::string configPath( "config.ini" ); std::string configPath( "api.ini" );
Sapphire::Common::Config::ApiConfig m_config;
void reloadConfig() void reloadConfig()
{ {
m_pConfig = std::make_shared< Sapphire::ConfigMgr >(); auto pConfig = std::make_shared< Sapphire::ConfigMgr >();
if( !m_pConfig->loadConfig( configPath ) ) Logger::info( "Loading config " + configPath );
bool failedLoad = false;
// load global cfg first
if( !pConfig->loadGlobalConfig( m_config.global ) )
{
Logger::fatal( "Error loading config global.ini" );
failedLoad = true;
}
if( !pConfig->loadConfig( configPath ) )
{
Logger::fatal( "Error loading config {0}", configPath );
failedLoad = true;
}
if( failedLoad )
{
Logger::fatal( "If this is the first time starting the server, we've copied the default configs for your editing pleasure." );
throw "Error loading config"; throw "Error loading config";
} }
// setup api config
m_config.network.listenPort = pConfig->getValue< uint16_t >( "Network", "ListenPort", 80 );
m_config.network.listenIP = pConfig->getValue< std::string >( "Network", "ListenIp", "0.0.0.0" );
}
void print_request_info( shared_ptr< HttpServer::Request > request ) void print_request_info( shared_ptr< HttpServer::Request > request )
{ {
Logger::info( "Request from {0} ({1})", request->remote_endpoint_address, request->path ); Logger::info( "Request from {0} ({1})", request->remote_endpoint_address, request->path );
@ -68,14 +92,7 @@ void print_request_info( shared_ptr< HttpServer::Request > request )
bool loadSettings( int32_t argc, char* argv[] ) bool loadSettings( int32_t argc, char* argv[] )
{ {
Logger::info( "Loading config " + configPath ); reloadConfig();
if( !m_pConfig->loadConfig( configPath ) )
{
Logger::fatal( "Error loading config {0}", configPath );
Logger::fatal( "If this is the first time starting the server, we've copied the default one for your editing pleasure." );
return false;
}
std::vector< std::string > args( argv + 1, argv + argc ); std::vector< std::string > args( argv + 1, argv + argc );
for( size_t i = 0; i + 1 < args.size(); i += 2 ) for( size_t i = 0; i + 1 < args.size(); i += 2 )
@ -91,46 +108,7 @@ bool loadSettings( int32_t argc, char* argv[] )
// trim '-' from start of arg // trim '-' from start of arg
arg = arg.erase( 0, arg.find_first_not_of( '-' ) ); arg = arg.erase( 0, arg.find_first_not_of( '-' ) );
if( arg == "ip" )
{
m_pConfig->setValue< std::string >( "RestNetwork.ListenIp", val );
}
else if( arg == "p" || arg == "port" )
{
m_pConfig->setValue< std::string >( "RestNetwork.ListenPort", val );
}
else if( arg == "exdpath" || arg == "datapath" )
{
m_pConfig->setValue< std::string >( "GlobalParameters.DataPath", val );
}
else if( arg == "h" || arg == "dbhost" )
{
m_pConfig->setValue< std::string >( "Database.Host", val );
}
else if( arg == "dbport" )
{
m_pConfig->setValue< std::string >( "Database.Port", val );
}
else if( arg == "u" || arg == "user" || arg == "dbuser" )
{
m_pConfig->setValue< std::string >( "Database.Username", val );
}
else if( arg == "pass" || arg == "dbpass" )
{
m_pConfig->setValue< std::string >( "Database.Password", val );
}
else if( arg == "d" || arg == "db" || arg == "database" )
{
m_pConfig->setValue< std::string >( "Database.Database", val );
}
else if( arg == "lobbyip" || arg == "lobbyhost" )
{
m_pConfig->setValue< std::string >( "GlobalNetwork.LobbyHost", val );
}
else if( arg == "lobbyport" )
{
m_pConfig->setValue< std::string >( "GlobalNetwork.LobbyPort", val );
}
} }
catch( ... ) catch( ... )
{ {
@ -140,34 +118,24 @@ bool loadSettings( int32_t argc, char* argv[] )
} }
Logger::info( "Setting up generated EXD data" ); Logger::info( "Setting up generated EXD data" );
auto dataPath = m_pConfig->getValue< std::string >( "GlobalParameters", "DataPath", "" ); auto dataPath = m_config.global.general.dataPath;
if( !g_exdDataGen.init( dataPath ) ) if( !g_exdDataGen.init( dataPath ) )
{ {
Logger::fatal( "Error setting up generated EXD data. Make sure that DataPath is set correctly in config.ini" ); Logger::fatal( "Error setting up generated EXD data. Make sure that DataPath is set correctly in global.ini" );
Logger::fatal( "DataPath: {0}", dataPath ); Logger::fatal( "DataPath: {0}", dataPath );
return false; return false;
} }
Sapphire::Db::DbLoader loader; Sapphire::Db::DbLoader loader;
Sapphire::Db::ConnectionInfo info; loader.addDb( g_charaDb, m_config.global.database );
info.password = m_pConfig->getValue< std::string >( "Database", "Password", "" );
info.host = m_pConfig->getValue< std::string >( "Database", "Host", "127.0.0.1" );
info.database = m_pConfig->getValue< std::string >( "Database", "Database", "sapphire" );
info.port = m_pConfig->getValue< uint16_t >( "Database", "Port", 3306 );
info.user = m_pConfig->getValue< std::string >( "Database", "Username", "root" );
info.syncThreads = m_pConfig->getValue< uint8_t >( "Database", "SyncThreads", 2 );
info.asyncThreads = m_pConfig->getValue< uint8_t >( "Database", "AsyncThreads", 2 );
loader.addDb( g_charaDb, info );
if( !loader.initDbs() ) if( !loader.initDbs() )
return false; return false;
server.config.port = static_cast< uint16_t >( std::stoul( server.config.port = m_config.network.listenPort;
m_pConfig->getValue< std::string >( "RestNetwork", "ListenPort", "80" ) ) ); server.config.address = m_config.network.listenIP;
server.config.address = m_pConfig->getValue< std::string >( "RestNetwork", "ListenIp", "0.0.0.0" );
Logger::info( "Database: Connected to {0}:{1}", info.host, info.port ); Logger::info( "Database: Connected to {0}:{1}", m_config.global.database.host, m_config.global.database.port );
return true; return true;
} }
@ -267,9 +235,9 @@ void createAccount( shared_ptr< HttpServer::Response > response, shared_ptr< Htt
// todo: construct proper json object here // todo: construct proper json object here
std::string json_string = "{\"sId\":\"" + sId + std::string json_string = "{\"sId\":\"" + sId +
"\", \"lobbyHost\":\"" + "\", \"lobbyHost\":\"" +
m_pConfig->getValue< std::string >( "GlobalNetwork", "LobbyHost" ) + m_config.global.network.lobbyHost +
"\", \"frontierHost\":\"" + "\", \"frontierHost\":\"" +
m_pConfig->getValue< std::string >( "GlobalNetwork", "RestHost" ) + "\"}"; m_config.global.network.restHost + "\"}";
*response << buildHttpResponse( 200, json_string, JSON ); *response << buildHttpResponse( 200, json_string, JSON );
} }
else else
@ -300,9 +268,9 @@ void login( shared_ptr< HttpServer::Response > response, shared_ptr< HttpServer:
// todo: build proper json object and stringify it // todo: build proper json object and stringify it
std::string json_string = "{\"sId\":\"" + sId + std::string json_string = "{\"sId\":\"" + sId +
"\", \"lobbyHost\":\"" + "\", \"lobbyHost\":\"" +
m_pConfig->getValue< std::string >( "GlobalNetwork", "LobbyHost" ) + m_config.global.network.lobbyHost +
"\", \"frontierHost\":\"" + "\", \"frontierHost\":\"" +
m_pConfig->getValue< std::string >( "GlobalNetwork", "RestHost" ) + "\"}"; m_config.global.network.restHost + "\"}";
*response << buildHttpResponse( 200, json_string, JSON ); *response << buildHttpResponse( 200, json_string, JSON );
} }
else else
@ -332,7 +300,7 @@ void deleteCharacter( shared_ptr< HttpServer::Response > response, shared_ptr< H
int32_t accountId = g_sapphireAPI.checkSession( sId ); int32_t accountId = g_sapphireAPI.checkSession( sId );
if( m_pConfig->getValue< std::string >( "GlobalParameters", "ServerSecret" ) != secret ) if( m_config.global.general.serverSecret != secret )
{ {
std::string json_string = "{\"result\":\"invalid_secret\"}"; std::string json_string = "{\"result\":\"invalid_secret\"}";
*response << buildHttpResponse( 403, json_string, JSON ); *response << buildHttpResponse( 403, json_string, JSON );
@ -372,15 +340,15 @@ void createCharacter( shared_ptr< HttpServer::Response > response, shared_ptr< H
if( result != -1 ) if( result != -1 )
{ {
if( m_pConfig->getValue< std::string >( "GlobalParameters", "ServerSecret" ) != secret ) if( m_config.global.general.serverSecret != secret )
{ {
std::string json_string = "{\"result\":\"invalid_secret\"}"; std::string json_string = "{\"result\":\"invalid_secret\"}";
*response << buildHttpResponse( 403, json_string, JSON ); *response << buildHttpResponse( 403, json_string, JSON );
} }
else else
{ {
int32_t charId = g_sapphireAPI.createCharacter( result, name, finalJson, m_pConfig->getValue< uint8_t >( int32_t charId = g_sapphireAPI.createCharacter( result, name, finalJson,
"CharacterCreation", "DefaultGMRank", 255 ) ); m_config.global.general.defaultGMRank );
std::string json_string = "{\"result\":\"" + std::to_string( charId ) + "\"}"; std::string json_string = "{\"result\":\"" + std::to_string( charId ) + "\"}";
*response << buildHttpResponse( 200, json_string, JSON ); *response << buildHttpResponse( 200, json_string, JSON );
@ -413,7 +381,7 @@ void insertSession( shared_ptr< HttpServer::Response > response, shared_ptr< Htt
std::string secret = json["secret"]; std::string secret = json["secret"];
// reloadConfig(); // reloadConfig();
if( m_pConfig->getValue< std::string >( "GlobalParameters", "ServerSecret" ) != secret ) if( m_config.global.general.serverSecret != secret )
{ {
std::string json_string = "{\"result\":\"invalid_secret\"}"; std::string json_string = "{\"result\":\"invalid_secret\"}";
*response << buildHttpResponse( 403, json_string, JSON ); *response << buildHttpResponse( 403, json_string, JSON );
@ -445,7 +413,7 @@ void checkNameTaken( shared_ptr< HttpServer::Response > response, shared_ptr< Ht
// reloadConfig(); // reloadConfig();
if( m_pConfig->getValue< std::string >( "GlobalParameters", "ServerSecret" ) != secret ) if( m_config.global.general.serverSecret != secret )
{ {
std::string json_string = "{\"result\":\"invalid_secret\"}"; std::string json_string = "{\"result\":\"invalid_secret\"}";
*response << buildHttpResponse( 403, json_string, JSON ); *response << buildHttpResponse( 403, json_string, JSON );
@ -482,7 +450,7 @@ void checkSession( shared_ptr< HttpServer::Response > response, shared_ptr< Http
if( result != -1 ) if( result != -1 )
{ {
if( m_pConfig->getValue< std::string >( "GlobalParameters", "ServerSecret" ) != secret ) if( m_config.global.general.serverSecret != secret )
{ {
std::string json_string = "{\"result\":\"invalid_secret\"}"; std::string json_string = "{\"result\":\"invalid_secret\"}";
*response << buildHttpResponse( 403, json_string, JSON ); *response << buildHttpResponse( 403, json_string, JSON );
@ -521,7 +489,7 @@ void getNextCharId( shared_ptr< HttpServer::Response > response, shared_ptr< Htt
// reloadConfig(); // reloadConfig();
if( m_pConfig->getValue< std::string >( "GlobalParameters", "ServerSecret" ) != secret ) if( m_config.global.general.serverSecret != secret )
{ {
std::string json_string = "{\"result\":\"invalid_secret\"}"; std::string json_string = "{\"result\":\"invalid_secret\"}";
*response << buildHttpResponse( 403, json_string, JSON ); *response << buildHttpResponse( 403, json_string, JSON );
@ -552,7 +520,7 @@ void getNextContentId( shared_ptr< HttpServer::Response > response, shared_ptr<
// reloadConfig(); // reloadConfig();
if( m_pConfig->getValue< std::string >( "GlobalParameters", "ServerSecret" ) != secret ) if( m_config.global.general.serverSecret != secret )
{ {
std::string json_string = "{\"result\":\"invalid_secret\"}"; std::string json_string = "{\"result\":\"invalid_secret\"}";
*response << buildHttpResponse( 403, json_string, JSON ); *response << buildHttpResponse( 403, json_string, JSON );
@ -587,7 +555,7 @@ void getCharacterList( shared_ptr< HttpServer::Response > response, shared_ptr<
if( result != -1 ) if( result != -1 )
{ {
if( m_pConfig->getValue< std::string >( "GlobalParameters", "ServerSecret" ) != secret ) if( m_config.global.general.serverSecret != secret )
{ {
std::string json_string = "{\"result\":\"invalid_secret\"}"; std::string json_string = "{\"result\":\"invalid_secret\"}";
*response << buildHttpResponse( 403, json_string, JSON ); *response << buildHttpResponse( 403, json_string, JSON );
@ -767,8 +735,7 @@ int main( int argc, char* argv[] )
server.start(); server.start();
} ); } );
Logger::info( "API server running on {0}:{1}", m_pConfig->getValue< std::string >( "RestNetwork", "ListenIp", "0.0.0.0" ), Logger::info( "API server running on {0}:{1}", m_config.network.listenIP, m_config.network.listenPort );
m_pConfig->getValue< std::string >( "RestNetwork", "ListenPort", "80" ) );
//Wait for server to start so that the client can connect //Wait for server to start so that the client can connect
this_thread::sleep_for( chrono::seconds( 1 ) ); this_thread::sleep_for( chrono::seconds( 1 ) );

View file

@ -855,8 +855,9 @@ namespace Sapphire::Common
struct HousingObject struct HousingObject
{ {
uint32_t itemId; uint32_t itemId;
uint16_t itemRotation; uint32_t padding; // was itemrotation + unknown/pad, looks unused now
Common::FFXIVARR_POSITION3_U16 pos; float rotation;
Common::FFXIVARR_POSITION3 pos;
}; };
enum HouseSize : uint8_t enum HouseSize : uint8_t
@ -880,21 +881,6 @@ namespace Sapphire::Common
heart = 0x06 heart = 0x06
}; };
enum HousingAppeal : uint8_t
{
NoAppeal = 0,
Emporium = 1,
Botique = 2,
DesignerHome = 3,
MessageBook = 4,
Tavern = 5,
Eatery = 6,
ImmersiveExperience = 7,
Aquarium = 9,
Sanctum = 10,
Venue = 11,
};
enum WardlandFlags : uint8_t enum WardlandFlags : uint8_t
{ {
IsEstateOwned = 1, IsEstateOwned = 1,

View file

@ -11,9 +11,9 @@ namespace Common {
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//ActionCategory.exd //ActionCategory.exd
enum class ActionCategory : enum class ActionCategory : uint8_t
uint8_t
{ {
None = 0,
Autoattack = 1, Autoattack = 1,
Spell = 2, Spell = 2,
Weaponskill = 3, Weaponskill = 3,
@ -33,8 +33,7 @@ enum class ActionCategory :
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//BeastReputationRank.exd //BeastReputationRank.exd
enum class BeastReputationRank : enum class BeastReputationRank : uint8_t
uint8_t
{ {
None = 0, None = 0,
Neutral = 1, Neutral = 1,
@ -49,15 +48,13 @@ enum class BeastReputationRank :
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//BeastTribe.exd //BeastTribe.exd
enum class BeastTribe : enum class BeastTribe : uint8_t
uint8_t
{ {
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//ClassJob.exd //ClassJob.exd
enum class ClassJob : enum class ClassJob : uint8_t
uint8_t
{ {
Adventurer = 0, Adventurer = 0,
Gladiator = 1, Gladiator = 1,
@ -95,13 +92,14 @@ enum class ClassJob :
Astrologian = 33, Astrologian = 33,
Samurai = 34, Samurai = 34,
Redmage = 35, Redmage = 35,
Bluemage = 36,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//ContentType.exd //ContentType.exd
enum class ContentType : enum class ContentType : uint8_t
uint8_t
{ {
None = 0,
DutyRoulette = 1, DutyRoulette = 1,
Dungeons = 2, Dungeons = 2,
Guildhests = 3, Guildhests = 3,
@ -121,36 +119,42 @@ enum class ContentType :
DisciplesoftheHand = 17, DisciplesoftheHand = 17,
RetainerVentures = 18, RetainerVentures = 18,
GoldSaucer = 19, GoldSaucer = 19,
one = 20,
DeepDungeons = 21, DeepDungeons = 21,
two = 22,
three = 23,
WondrousTails = 24, WondrousTails = 24,
CustomDeliveries = 25, CustomDeliveries = 25,
Eureka = 26,
four = 27,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//EmoteCategory.exd //EmoteCategory.exd
enum class EmoteCategory : enum class EmoteCategory : uint8_t
uint8_t
{ {
None = 0,
General = 1, General = 1,
Persistent = 2, Special = 2,
Expressions = 3, Expressions = 3,
one = 4,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//ExVersion.exd //ExVersion.exd
enum class ExVersion : enum class ExVersion : uint8_t
uint8_t
{ {
ARealmReborn = 0, ARealmReborn = 0,
Heavensward = 1, Heavensward = 1,
Stormblood = 2, Stormblood = 2,
three = 3,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//GrandCompany.exd //GrandCompany.exd
enum GrandCompany : uint8_t enum class GrandCompany : uint8_t
{ {
NoGc = 0, None = 0,
Maelstrom = 1, Maelstrom = 1,
OrderoftheTwinAdder = 2, OrderoftheTwinAdder = 2,
ImmortalFlames = 3, ImmortalFlames = 3,
@ -160,6 +164,7 @@ enum GrandCompany : uint8_t
//GuardianDeity.exd //GuardianDeity.exd
enum class GuardianDeity : uint8_t enum class GuardianDeity : uint8_t
{ {
None = 0,
HalonetheFury = 1, HalonetheFury = 1,
MenphinatheLover = 2, MenphinatheLover = 2,
ThaliaktheScholar = 3, ThaliaktheScholar = 3,
@ -176,9 +181,9 @@ enum class GuardianDeity : uint8_t
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//ItemUICategory.exd //ItemUICategory.exd
enum class ItemUICategory : enum class ItemUICategory : uint8_t
uint8_t
{ {
None = 0,
PugilistsArm = 1, PugilistsArm = 1,
GladiatorsArm = 2, GladiatorsArm = 2,
MaraudersArm = 3, MaraudersArm = 3,
@ -279,13 +284,18 @@ enum class ItemUICategory :
ScholarsArm = 98, ScholarsArm = 98,
FishersSecondaryTool = 99, FishersSecondaryTool = 99,
Currency = 100, Currency = 100,
SubmersibleHull = 101,
SubmersibleStern = 102,
SubmersibleBow = 103,
SubmersibleBridge = 104,
BlueMagesArm = 105,
}; };
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//ItemSearchCategory.exd //ItemSearchCategory.exd
enum class ItemSearchCategory : enum class ItemSearchCategory : uint8_t
uint8_t
{ {
None = 0,
PrimaryArms = 1, PrimaryArms = 1,
PrimaryTools = 2, PrimaryTools = 2,
PrimaryTools1 = 3, PrimaryTools1 = 3,
@ -364,7 +374,7 @@ enum class ItemSearchCategory :
DarkKnightsArms = 76, DarkKnightsArms = 76,
MachinistsArms = 77, MachinistsArms = 77,
AstrologiansArms = 78, AstrologiansArms = 78,
AirshipComponents = 79, Airship_SubmersibleComponents = 79,
OrchestrionComponents = 80, OrchestrionComponents = 80,
GardeningItems = 81, GardeningItems = 81,
Paintings = 82, Paintings = 82,
@ -375,8 +385,7 @@ enum class ItemSearchCategory :
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//OnlineStatus.exd //OnlineStatus.exd
enum class OnlineStatus : enum class OnlineStatus : uint8_t
uint8_t
{ {
Producer = 1, Producer = 1,
GameMaster = 2, GameMaster = 2,
@ -429,9 +438,9 @@ enum class OnlineStatus :
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//Race.exd //Race.exd
enum class Race : enum class Race : uint8_t
uint8_t
{ {
None = 0,
Hyur = 1, Hyur = 1,
Elezen = 2, Elezen = 2,
Lalafell = 3, Lalafell = 3,
@ -442,9 +451,9 @@ enum class Race :
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//Tribe.exd //Tribe.exd
enum class Tribe : enum class Tribe : uint8_t
uint8_t
{ {
None = 0,
Midlander = 1, Midlander = 1,
Highlander = 2, Highlander = 2,
Wildwood = 3, Wildwood = 3,
@ -461,8 +470,7 @@ enum class Tribe :
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//Town.exd //Town.exd
enum class Town : enum class Town : uint8_t
uint8_t
{ {
Nowheresville = 0, Nowheresville = 0,
LimsaLominsa = 1, LimsaLominsa = 1,
@ -474,8 +482,7 @@ enum class Town :
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//Weather.exd //Weather.exd
enum class Weather : enum class Weather : uint8_t
uint8_t
{ {
None = 0, None = 0,
ClearSkies = 1, ClearSkies = 1,
@ -543,8 +550,8 @@ enum class Weather :
FairSkies7 = 63, FairSkies7 = 63,
Rain2 = 64, Rain2 = 64,
FairSkies8 = 65, FairSkies8 = 65,
Dragonstorm = 66, Dragonstorms = 66,
Dragonstorm1 = 67, Dragonstorms1 = 67,
Subterrain = 68, Subterrain = 68,
Concordance = 69, Concordance = 69,
Concordance1 = 70, Concordance1 = 70,
@ -557,17 +564,65 @@ enum class Weather :
DimensionalDisruption = 77, DimensionalDisruption = 77,
DimensionalDisruption1 = 78, DimensionalDisruption1 = 78,
DimensionalDisruption2 = 79, DimensionalDisruption2 = 79,
Revelstorm = 80, Revelstorms = 80,
Revelstorm1 = 81, Revelstorms1 = 81,
EternalBliss = 82, EternalBliss = 82,
EternalBliss1 = 83, EternalBliss1 = 83,
Wyrmstorm = 84, Wyrmstorms = 84,
Wyrmstorm1 = 85, Wyrmstorms1 = 85,
Revelstorm2 = 86, Revelstorms2 = 86,
Quicklevin = 87, Quicklevin = 87,
Thunder3 = 88, Thunder3 = 88,
DimensionalDisruption3 = 89, DimensionalDisruption3 = 89,
FairSkies9 = 90, FairSkies9 = 90,
ClearSkies1 = 91,
WhiteCyclones = 92,
WhiteCyclones1 = 93,
WhiteCyclones2 = 94,
Ultimania = 95,
WhiteCyclones3 = 96,
Moonlight = 97,
Moonlight1 = 98,
Moonlight2 = 99,
Moonlight3 = 100,
FairSkies10 = 101,
Scarlet = 102,
Scarlet1 = 103,
Scarlet2 = 104,
FairSkies11 = 105,
FairSkies12 = 106,
FairSkies13 = 107,
FairSkies14 = 108,
Flames = 109,
Tsunamis = 110,
Cyclones = 111,
Geostorms = 112,
TrueBlue = 113,
TrueBlue1 = 114,
TrueBlue2 = 115,
TrueBlue3 = 117,
};
///////////////////////////////////////////////////////////
//HousingAppeal.exd
enum class HousingAppeal : uint8_t
{
None = 0,
Emporium = 1,
Boutique = 2,
DesignerHome = 3,
MessageBook = 4,
Tavern = 5,
Eatery = 6,
ImmersiveExperience = 7,
Cafe = 8,
Aquarium = 9,
Sanctum = 10,
Venue = 11,
Florist = 12,
Library = 14,
PhotoStudio = 15,
HauntedHouse = 16,
}; };
} }
} }

View file

@ -0,0 +1,88 @@
#ifndef SAPPHIRE_CONFIGDEF_H
#define SAPPHIRE_CONFIGDEF_H
#include <Database/DbCommon.h>
namespace Sapphire::Common::Config
{
struct GlobalConfig
{
Sapphire::Db::ConnectionInfo database;
struct General
{
std::string serverSecret;
std::string dataPath;
uint16_t worldID;
uint8_t defaultGMRank;
} general;
struct Network
{
std::string zoneHost;
uint16_t zonePort;
std::string lobbyHost;
uint16_t lobbyPort;
std::string restHost;
uint16_t restPort;
} network;
};
struct WorldConfig
{
GlobalConfig global;
struct Network
{
std::string listenIp;
uint16_t listenPort;
uint16_t disconnectTimeout;
} network;
struct Housing
{
std::string defaultEstateName;
} housing;
struct Scripts
{
std::string path;
std::string cachePath;
bool hotSwap;
} scripts;
std::string motd;
};
struct LobbyConfig
{
GlobalConfig global;
struct Network
{
std::string listenIp;
uint16_t listenPort;
} network;
bool allowNoSessionConnect;
std::string worldName;
};
struct ApiConfig
{
GlobalConfig global;
struct Network
{
std::string listenIP;
uint16_t listenPort;
} network;
};
}
#endif //SAPPHIRE_CONFIGDEF_H

View file

@ -29,6 +29,46 @@ bool Sapphire::ConfigMgr::loadConfig( const std::string& configName )
return true; return true;
} }
bool Sapphire::ConfigMgr::loadGlobalConfig( Common::Config::GlobalConfig& config, const std::string& configName )
{
auto configFile = fs::path( fs::path( m_configFolderRoot ) / configName );
if( !fs::exists( configFile ) )
{
copyDefaultConfig( configName );
return false;
}
m_pInih = std::make_unique< INIReader >( configFile.string() );
if( m_pInih->ParseError() < 0 )
return false;
// database
config.database.host = getValue< std::string >( "Database", "Host", "127.0.0.1" );
config.database.port = getValue< uint16_t >( "Database", "Port", 3306 );
config.database.database = getValue< std::string >( "Database", "Database", "sapphire" );
config.database.user = getValue< std::string >( "Database", "Username", "sapphire" );
config.database.password = getValue< std::string >( "Database", "Password", "" );
config.database.syncThreads = getValue< uint8_t >( "Database", "SyncThreads", 2 );
config.database.asyncThreads = getValue< uint8_t >( "Database", "AsyncThreads", 2 );
// params
config.general.dataPath = getValue< std::string >( "General", "DataPath", "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack" );
config.general.serverSecret = getValue< std::string >( "General", "ServerSecret", "default" );
config.general.worldID = getValue< uint16_t >( "General", "WorldID", 67 );
config.general.defaultGMRank = getValue< uint8_t >( "General", "DefaultGMRank", 255 );
// network
config.network.zoneHost = getValue< std::string >( "Network", "ZoneHost", "127.0.0.1" );
config.network.zonePort = getValue< uint16_t >( "Network", "ZonePort", 54992 );
config.network.lobbyHost = getValue< std::string >( "Network", "LobbyHost", "127.0.0.1" );
config.network.lobbyPort = getValue< uint16_t >( "Network", "LobbyPort", 54994 );
config.network.restHost = getValue< std::string >( "Network", "RestHost", "127.0.0.1" );
config.network.restPort = getValue< uint16_t >( "Network", "RestPort", 80 );
return true;
}
bool Sapphire::ConfigMgr::copyDefaultConfig( const std::string& configName ) bool Sapphire::ConfigMgr::copyDefaultConfig( const std::string& configName )
{ {
fs::path configPath( m_configFolderRoot ); fs::path configPath( m_configFolderRoot );

View file

@ -6,6 +6,7 @@
#include <inih/INIReader.h> #include <inih/INIReader.h>
#include <string> #include <string>
#include <stdint.h> #include <stdint.h>
#include "ConfigDef.h"
namespace Sapphire namespace Sapphire
{ {
@ -13,10 +14,10 @@ namespace Sapphire
{ {
public: public:
ConfigMgr() = default; ConfigMgr() = default;
~ConfigMgr() = default; ~ConfigMgr() = default;
bool loadConfig( const std::string& configName ); bool loadConfig( const std::string& configName );
bool loadGlobalConfig( Common::Config::GlobalConfig& config, const std::string& configName = "global.ini" );
template< class T > struct always_false : std::false_type {}; template< class T > struct always_false : std::false_type {};

View file

@ -0,0 +1,18 @@
#ifndef SAPPHIRE_DBCOMMON_H
#define SAPPHIRE_DBCOMMON_H
namespace Sapphire::Db
{
struct ConnectionInfo
{
std::string user;
std::string password;
std::string database;
std::string host;
uint16_t port;
uint8_t syncThreads;
uint8_t asyncThreads;
};
}
#endif //SAPPHIRE_DBCOMMON_H

View file

@ -7,6 +7,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "Util/LockedWaitQueue.h" #include "Util/LockedWaitQueue.h"
#include "DbCommon.h"
namespace Mysql namespace Mysql
{ {
@ -31,17 +32,6 @@ namespace Sapphire::Db
CONNECTION_BOTH = CONNECTION_ASYNC | CONNECTION_SYNC CONNECTION_BOTH = CONNECTION_ASYNC | CONNECTION_SYNC
}; };
struct ConnectionInfo
{
std::string user;
std::string password;
std::string database;
std::string host;
uint16_t port;
uint8_t syncThreads;
uint8_t asyncThreads;
};
using PreparedStatementMap = std::map< uint32_t, std::pair< std::string, ConnectionFlags > >; using PreparedStatementMap = std::map< uint32_t, std::pair< std::string, ConnectionFlags > >;
class DbConnection : class DbConnection :

View file

@ -1034,14 +1034,14 @@ Sapphire::Data::ClassJob::ClassJob( uint32_t row_id, Sapphire::Data::ExdDataGene
classJobParent = exdData->getField< uint8_t >( row, 26 ); classJobParent = exdData->getField< uint8_t >( row, 26 );
nameEnglish = exdData->getField< std::string >( row, 27 ); nameEnglish = exdData->getField< std::string >( row, 27 );
itemStartingWeapon = exdData->getField< int32_t >( row, 28 ); itemStartingWeapon = exdData->getField< int32_t >( row, 28 );
limitBreak1 = exdData->getField< uint16_t >( row, 33 ); limitBreak1 = exdData->getField< uint16_t >( row, 34 );
limitBreak2 = exdData->getField< uint16_t >( row, 34 ); limitBreak2 = exdData->getField< uint16_t >( row, 35 );
limitBreak3 = exdData->getField< uint16_t >( row, 35 ); limitBreak3 = exdData->getField< uint16_t >( row, 36 );
itemSoulCrystal = exdData->getField< uint32_t >( row, 37 ); itemSoulCrystal = exdData->getField< uint32_t >( row, 38 );
unlockQuest = exdData->getField< uint32_t >( row, 38 ); unlockQuest = exdData->getField< uint32_t >( row, 39 );
relicQuest = exdData->getField< uint32_t >( row, 39 ); relicQuest = exdData->getField< uint32_t >( row, 40 );
prerequisite = exdData->getField< uint32_t >( row, 40 ); prerequisite = exdData->getField< uint32_t >( row, 41 );
startingLevel = exdData->getField< uint8_t >( row, 41 ); startingLevel = exdData->getField< uint8_t >( row, 42 );
} }
Sapphire::Data::ClassJobCategory::ClassJobCategory( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData ) Sapphire::Data::ClassJobCategory::ClassJobCategory( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData )
@ -1273,10 +1273,10 @@ Sapphire::Data::ContentFinderCondition::ContentFinderCondition( uint32_t row_id,
allowReplacement = exdData->getField< bool >( row, 20 ); allowReplacement = exdData->getField< bool >( row, 20 );
highEndDuty = exdData->getField< bool >( row, 26 ); highEndDuty = exdData->getField< bool >( row, 26 );
dutyRecorderAllowed = exdData->getField< bool >( row, 30 ); dutyRecorderAllowed = exdData->getField< bool >( row, 30 );
name = exdData->getField< std::string >( row, 32 ); name = exdData->getField< std::string >( row, 34 );
contentType = exdData->getField< uint8_t >( row, 33 ); contentType = exdData->getField< uint8_t >( row, 35 );
transient = exdData->getField< uint8_t >( row, 34 ); transient = exdData->getField< uint8_t >( row, 36 );
image = exdData->getField< uint32_t >( row, 37 ); image = exdData->getField< uint32_t >( row, 39 );
} }
Sapphire::Data::ContentFinderConditionTransient::ContentFinderConditionTransient( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData ) Sapphire::Data::ContentFinderConditionTransient::ContentFinderConditionTransient( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData )
@ -3164,7 +3164,7 @@ Sapphire::Data::InstanceContent::InstanceContent( uint32_t row_id, Sapphire::Dat
instanceClearExp = exdData->getField< uint32_t >( row, 46 ); instanceClearExp = exdData->getField< uint32_t >( row, 46 );
instanceContentBuff = exdData->getField< int32_t >( row, 51 ); instanceContentBuff = exdData->getField< int32_t >( row, 51 );
reqInstance = exdData->getField< uint32_t >( row, 52 ); reqInstance = exdData->getField< uint32_t >( row, 52 );
partyCondition = exdData->getField< uint8_t >( row, 55 ); partyCondition = exdData->getField< uint8_t >( row, 54 );
} }
Sapphire::Data::InstanceContentBuff::InstanceContentBuff( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData ) Sapphire::Data::InstanceContentBuff::InstanceContentBuff( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData )
@ -3240,7 +3240,7 @@ Sapphire::Data::Item::Item( uint32_t row_id, Sapphire::Data::ExdDataGenerated* e
materiaSlotCount = exdData->getField< uint8_t >( row, 84 ); materiaSlotCount = exdData->getField< uint8_t >( row, 84 );
isAdvancedMeldingPermitted = exdData->getField< bool >( row, 85 ); isAdvancedMeldingPermitted = exdData->getField< bool >( row, 85 );
isPvP = exdData->getField< bool >( row, 86 ); isPvP = exdData->getField< bool >( row, 86 );
isGlamourous = exdData->getField< bool >( row, 87 ); isGlamourous = exdData->getField< bool >( row, 88 );
} }
Sapphire::Data::ItemAction::ItemAction( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData ) Sapphire::Data::ItemAction::ItemAction( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData )
@ -4065,8 +4065,8 @@ Sapphire::Data::PublicContent::PublicContent( uint32_t row_id, Sapphire::Data::E
name = exdData->getField< std::string >( row, 3 ); name = exdData->getField< std::string >( row, 3 );
textDataStart = exdData->getField< uint32_t >( row, 4 ); textDataStart = exdData->getField< uint32_t >( row, 4 );
textDataEnd = exdData->getField< uint32_t >( row, 5 ); textDataEnd = exdData->getField< uint32_t >( row, 5 );
contentFinderCondition = exdData->getField< uint16_t >( row, 7 ); contentFinderCondition = exdData->getField< uint16_t >( row, 8 );
additionalData = exdData->getField< uint16_t >( row, 8 ); additionalData = exdData->getField< uint16_t >( row, 9 );
} }
Sapphire::Data::PublicContentCutscene::PublicContentCutscene( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData ) Sapphire::Data::PublicContentCutscene::PublicContentCutscene( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData )

View file

@ -13,25 +13,20 @@ namespace Server {
* Structural representation of the packet sent by the server as response * Structural representation of the packet sent by the server as response
* to a tell request * to a tell request
*/ */
struct FFXIVIpcTell : struct FFXIVIpcTell : FFXIVIpcBasePacket< Tell >
FFXIVIpcBasePacket< Tell >
{ {
uint32_t u1; uint64_t contentId;
uint16_t u2a; uint16_t worldId;
uint16_t u2b;
uint8_t preName; uint8_t preName;
uint8_t u3a;
uint8_t u3b; //Setting this to 1 seems to mark the tell as a GM tell (More research needed)
char receipientName[32]; char receipientName[32];
char msg[1031]; char msg[1029];
}; };
/** /**
* Structural representation of the packet sent by the server as response * Structural representation of the packet sent by the server as response
* to a failed tell because of unavailable target player * to a failed tell because of unavailable target player
*/ */
struct FFXIVIpcTellErrNotFound : struct FFXIVIpcTellErrNotFound : FFXIVIpcBasePacket< TellErrNotFound >
FFXIVIpcBasePacket< TellErrNotFound >
{ {
char receipientName[32]; char receipientName[32];
}; };

View file

@ -60,8 +60,8 @@ namespace Sapphire::Network::Packets
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
ChatBanned = 0x006B, ChatBanned = 0x006B,
Playtime = 0x006C, // updated 4.4 Playtime = 0x006C, // updated 4.5
Logout = 0x0077, // updated 4.4 Logout = 0x0077, // updated 4.5
CFNotify = 0x0078, CFNotify = 0x0078,
CFMemberStatus = 0x0079, CFMemberStatus = 0x0079,
CFDutyInfo = 0x007A, CFDutyInfo = 0x007A,
@ -73,157 +73,157 @@ namespace Sapphire::Network::Packets
SocialRequestResponse = 0x00BB, // updated 4.1 SocialRequestResponse = 0x00BB, // updated 4.1
CancelAllianceForming = 0x00C6, // updated 4.2 CancelAllianceForming = 0x00C6, // updated 4.2
Chat = 0x00F4, // updated 4.4 Chat = 0x00F7, // updated 4.5?
SocialList = 0x00FB, // updated 4.4 SocialList = 0x0103, // updated 4.5
UpdateSearchInfo = 0x00FE, // updated 4.4 UpdateSearchInfo = 0x0106, // updated 4.5
InitSearchInfo = 0x00FF, // updated 4.4 InitSearchInfo = 0x0107, // updated 4.4
ExamineSearchComment = 0x0102, // updated 4.1 ExamineSearchComment = 0x0102, // updated 4.1
ServerNotice = 0x0104, // updated 4.4 ServerNotice = 0x010C, // updated 4.5
SetOnlineStatus = 0x0105, // updated 4.4 SetOnlineStatus = 0x010D, // updated 4.5
CountdownInitiate = 0x010C, // updated 4.4 CountdownInitiate = 0x0114, // updated 4.5
CountdownCancel = 0x010D, // updated 4.4 CountdownCancel = 0x0115, // updated 4.5
BlackList = 0x0110, // updated 4.4 BlackList = 0x0118, // updated 4.5
LogMessage = 0x00D0, LogMessage = 0x00D0,
LinkshellList = 0x0117, // updated 4.4 LinkshellList = 0x011F, // updated 4.5
MailDeleteRequest = 0x0118, // updated 4.4 MailDeleteRequest = 0x0120, // updated 4.5
ReqMoogleMailList = 0x0119, // updated 4.4 ReqMoogleMailList = 0x0121, // updated 4.5
ReqMoogleMailLetter = 0x011A, // updated 4.4 ReqMoogleMailLetter = 0x0122, // updated 4.5
MailLetterNotification = 0x011B, // updated 4.4 MailLetterNotification = 0x0123, // updated 4.5
MarketBoardItemListingCount = 0x011C, // updated 4.4 MarketBoardItemListingCount = 0x0125, // updated 4.5
MarketBoardItemListing = 0x011D, // updated 4.4 MarketBoardItemListing = 0x0126, // updated 4.5
MarketBoardItemListingHistory = 0x0121, // updated 4.4 MarketBoardItemListingHistory = 0x012A, // updated 4.5
MarketBoardSearchResult = 0x0125, // updated 4.4 MarketBoardSearchResult = 0x0139, // updated 4.5
CharaFreeCompanyTag = 0x0127, // updated 4.4 CharaFreeCompanyTag = 0x013B, // updated 4.5
FreeCompanyBoardMsg = 0x0128, // updated 4.4 FreeCompanyBoardMsg = 0x013C, // updated 4.5
FreeCompanyInfo = 0x0129, // updated 4.4 FreeCompanyInfo = 0x013D, // updated 4.5
ExamineFreeCompanyInfo = 0x013A, // updated 4.1 ExamineFreeCompanyInfo = 0x013E, // updated 4.5
StatusEffectList = 0x0149, // updated 4.4 StatusEffectList = 0x0151, // updated 4.5
Effect = 0x014C, // updated 4.4 Effect = 0x0154, // updated 4.5
AoeEffect8 = 0x014F, // updated 4.4 AoeEffect8 = 0x0157, // updated 4.5
AoeEffect16 = 0x0150, // updated 4.4 AoeEffect16 = 0x0158, // updated 4.5
AoeEffect24 = 0x0151, // updated 4.4 AoeEffect24 = 0x0159, // updated 4.5
AoeEffect32 = 0x0152, // updated 4.4 AoeEffect32 = 0x015A, // updated 4.5
PersistantEffect = 0x0153, // updated 4.4 PersistantEffect = 0x015B, // updated 4.5
GCAffiliation = 0x015D, // updated 4.4 GCAffiliation = 0x0165, // updated 4.5
PlayerSpawn = 0x016D, // updated 4.4 PlayerSpawn = 0x0175, // updated 4.5
NpcSpawn = 0x016E, // updated 4.4 NpcSpawn = 0x0176, // updated 4.5
ActorMove = 0x0170, // updated 4.4 ActorMove = 0x0178, // updated 4.5
ActorSetPos = 0x0172, // updated 4.4 ActorSetPos = 0x017A, // updated 4.5
ActorCast = 0x0174, // updated 4.4 ActorCast = 0x017C, // updated 4.5
PartyList = 0x0176, // updated 4.4 PartyList = 0x017E, // updated 4.5
HateList = 0x0177, // updated 4.4 HateList = 0x017F, // updated 4.5
ObjectSpawn = 0x0179, // updated 4.4 ObjectSpawn = 0x0181, // updated 4.5
ObjectDespawn = 0x017A, // updated 4.4 ObjectDespawn = 0x0182, // updated 4.5
UpdateClassInfo = 0x017B, // updated 4.4 UpdateClassInfo = 0x0183, // updated 4.5
SilentSetClassJob = 0x017C, // updated 4.4 - seems to be the case, not sure if it's actually used for anything SilentSetClassJob = 0x0184, // updated 4.5 - seems to be the case, not sure if it's actually used for anything
InitUI = 0x017D, // updated 4.4 InitUI = 0x0185, // updated 4.5
PlayerStats = 0x017E, // updated 4.4 PlayerStats = 0x0186, // updated 4.5
ActorOwner = 0x017F, // updated 4.4 ? ActorOwner = 0x0187, // updated 4.5
PlayerStateFlags = 0x0180, // updated 4.4 PlayerStateFlags = 0x0188, // updated 4.5
PlayerClassInfo = 0x0181, // updated 4.4 PlayerClassInfo = 0x0189, // updated 4.5
ModelEquip = 0x0182, // updated 4.4 ModelEquip = 0x018B, // updated 4.5
Examine = 0x0183, // updated 4.4 Examine = 0x018C, // updated 4.5
CharaNameReq = 0x0185, // updated 4.4 CharaNameReq = 0x018D, // updated 4.5
SetLevelSync = 0x0186, // not updated for 4.4, not sure what it is anymore SetLevelSync = 0x1186, // not updated for 4.4, not sure what it is anymore
ItemInfo = 0x018C, // updated 4.4 ItemInfo = 0x0196, // updated 4.5
ContainerInfo = 0x018D, // updated 4.4 ContainerInfo = 0x0197, // updated 4.5
InventoryTransactionFinish = 0x018E, // updated 4.4 InventoryTransactionFinish = 0x0198, // updated 4.5
InventoryTransaction = 0x018F, // updated 4.4 InventoryTransaction = 0x0199, // updated 4.5
CurrencyCrystalInfo = 0x0190, // updated 4.4 CurrencyCrystalInfo = 0x019B, // updated 4.5
InventoryActionAck = 0x0193, // updated 4.4 InventoryActionAck = 0x019D, // updated 4.5
UpdateInventorySlot = 0x0194, // updated 4.4 UpdateInventorySlot = 0x019E, // updated 4.5
EventPlay = 0x01A2, // updated 4.4 EventPlay = 0x01AB, // updated 4.5
EventOpenGilShop = 0x01A9, // updated 4.4 DirectorPlayScene = 0x01AF, // updated 4.5
DirectorPlayScene = 0x01A6, // updated 4.4 EventOpenGilShop = 0x01B2, // updated 4.5
EventStart = 0x01AB, // updated 4.4 EventStart = 0x01B4, // updated 4.5
EventFinish = 0x01AC, // updated 4.4 EventFinish = 0x01B5, // updated 4.5
EventLinkshell = 0x1169, EventLinkshell = 0x1169,
QuestActiveList = 0x01BF, // updated 4.4 QuestActiveList = 0x01C8, // updated 4.5
QuestUpdate = 0x01C0, // updated 4.4 QuestUpdate = 0x01C9, // updated 4.5
QuestCompleteList = 0x01C1, // updated 4.4 QuestCompleteList = 0x01CA, // updated 4.5
QuestFinish = 0x01C2, // updated 4.4 QuestFinish = 0x01CB, // updated 4.5
MSQTrackerComplete = 0x01C3, // updated 4.4 MSQTrackerComplete = 0x01CC, // updated 4.5
MSQTrackerProgress = 0x01C4, // updated 4.4 MSQTrackerProgress = 0xF1CD, // updated 4.5 ? this actually looks like the two opcodes have been combined, see #474
QuestMessage = 0x01CA, // updated 4.4 QuestMessage = 0x01D3, // updated 4.5
QuestTracker = 0x01CF, // updated 4.4 QuestTracker = 0x01D8, // updated 4.5
Mount = 0x01DF, // updated 4.4 Mount = 0x01E8, // updated 4.5
DirectorVars = 0x01E1, // updated 4.4 DirectorVars = 0x01EA, // updated 4.5
CFAvailableContents = 0xF1FD, // updated 4.2 CFAvailableContents = 0xF1FD, // updated 4.2
WeatherChange = 0x01FC, // updated 4.4 WeatherChange = 0x0205, // updated 4.5
PlayerTitleList = 0x01FD, // updated 4.4 PlayerTitleList = 0x0206, // updated 4.5?
Discovery = 0x01FE, // updated 4.4 Discovery = 0x0207, // updated 4.5?
EorzeaTimeOffset = 0x0200, // updated 4.4 EorzeaTimeOffset = 0x0209, // updated 4.5
EquipDisplayFlags = 0x020C, // updated 4.4 EquipDisplayFlags = 0x0215, // updated 4.5
/// Housing ////////////////////////////////////// /// Housing //////////////////////////////////////
LandSetInitialize = 0x0220, // updated 4.4 LandSetInitialize = 0x0229, // updated 4.5
LandUpdate = 0x0221, // updated 4.4 LandUpdate = 0x022A, // updated 4.5
YardObjectSpawn = 0x0222, // updated 4.4 YardObjectSpawn = 0x022B, // updated 4.5
HousingIndoorInitialize = 0x0223, HousingIndoorInitialize = 0x022C, // updated 4.5
LandPriceUpdate = 0x0224, // updated 4.4 LandPriceUpdate = 0x022D, // updated 4.5
LandInfoSign = 0x0225, // updated 4.4 LandInfoSign = 0x022E, // updated 4.5
LandRename = 0x0226, // updated 4.4 LandRename = 0x022F, // updated 4.5
HousingEstateGreeting = 0x0227, // updated 4.4 HousingEstateGreeting = 0x0230, // updated 4.5
HousingUpdateLandFlagsSlot = 0x0228, // updated 4.4 HousingUpdateLandFlagsSlot = 0x0231, // updated 4.5
HousingLandFlags = 0x0229, // updated 4.4 HousingLandFlags = 0x0232, // updated 4.5
HousingShowEstateGuestAccess = 0x022A, // updated 4.4 HousingShowEstateGuestAccess = 0x0233, // updated 4.5
HousingObjectInitialize = 0x022C, // updated 4.4 HousingObjectInitialize = 0x0235, // updated 4.45
HousingInternalObjectSpawn = 0x22D, // updated 4.4 HousingInternalObjectSpawn = 0x236, // updated 4.5
HousingWardInfo = 0x022F, // updated 4.4 HousingWardInfo = 0x0238, // updated 4.5
HousingObjectMove = 0x0230, // updated 4.4 HousingObjectMove = 0x0239, // updated 4.5
SharedEstateSettingsResponse = 0x023C, // updated 4.4 SharedEstateSettingsResponse = 0x0245, // updated 4.5
LandUpdateHouseName = 0x024D, // updated 4.4 LandUpdateHouseName = 0x0257, // updated 4.5
LandSetMap = 0x0251, // updated 4.4 LandSetMap = 0x025B, // updated 4.5
////////////////////////////////////////////////// //////////////////////////////////////////////////
DuelChallenge = 0x0277, // 4.2; this is responsible for opening the ui DuelChallenge = 0x0277, // 4.2; this is responsible for opening the ui
PerformNote = 0x0286, // updated 4.3 PerformNote = 0x0286, // updated 4.3
PrepareZoning = 0x028F, // updated 4.4 PrepareZoning = 0x0299, // updated 4.5
ActorGauge = 0x0292, // updated 4.3 ActorGauge = 0x0292, // updated 4.3
// Unknown IPC types that still need to be sent // Unknown IPC types that still need to be sent
// TODO: figure all these out properly // TODO: figure all these out properly
IPCTYPE_UNK_320 = 0x0249, // updated 4.4 IPCTYPE_UNK_320 = 0x0253, // updated 4.5
IPCTYPE_UNK_322 = 0x024B, // updated 4.4 IPCTYPE_UNK_322 = 0x0255, // updated 4.5
}; };
@ -233,42 +233,42 @@ namespace Sapphire::Network::Packets
enum ClientZoneIpcType : uint16_t enum ClientZoneIpcType : uint16_t
{ {
PingHandler = 0x0065, // unchanged 4.3 PingHandler = 0x0065, // unchanged 4.5
InitHandler = 0x0066, // unchanged 4.3 InitHandler = 0x0066, // unchanged 4.5
FinishLoadingHandler = 0x0069, // unchanged 4.3 FinishLoadingHandler = 0x0069, // unchanged 4.5
CFCommenceHandler = 0x006F, CFCommenceHandler = 0x006F,
CFRegisterDuty = 0x0071, CFRegisterDuty = 0x0071,
CFRegisterRoulette = 0x0072, CFRegisterRoulette = 0x0072,
PlayTimeHandler = 0x0073, // unchanged 4.3 PlayTimeHandler = 0x0073, // unchanged 4.5
LogoutHandler = 0x0074, // unchanged 4.3 LogoutHandler = 0x0074, // unchanged 4.5
CFDutyInfoHandler = 0x0078, // updated 4.2 CFDutyInfoHandler = 0x0078, // updated 4.2
SocialReqSendHandler = 0x00AE, // updated 4.1 SocialReqSendHandler = 0x00AE, // updated 4.1
CreateCrossWorldLS = 0x00AF, // updated 4.3 CreateCrossWorldLS = 0x00AF, // updated 4.3
ChatHandler = 0x00D3, // updated 4.3 ChatHandler = 0x00D7, // updated 4.5
SocialListHandler = 0x00DB, // updated 4.3 SocialListHandler = 0x00DF, // updated 4.5
ReqSearchInfoHandler = 0x00E0, // updated 4.3 ReqSearchInfoHandler = 0x00E4, // updated 4.5
ReqExamineSearchCommentHandler = 0x00E1, // updated 4.1 ReqExamineSearchCommentHandler = 0x00E5, // updated 4.5
SetSearchInfoHandler = 0x00DE, // updated 4.3 SetSearchInfoHandler = 0x00E2, // unchanged 4.5
BlackListHandler = 0x00EC, // updated 4.3 BlackListHandler = 0x00F0, // updated 4.5
PlayerSearchHandler = 0x00E2, // updated 4.2 PlayerSearchHandler = 0x00E6, // updated 4.5
LinkshellListHandler = 0x00F4, // updated 4.3 LinkshellListHandler = 0x00F8, // updated 4.5
MarketBoardRequestItemListingInfo = 0x00FE, // updated 4.4 MarketBoardRequestItemListingInfo = 0x0102, // updated 4.5
MarketBoardRequestItemListings = 0x00FF, // updated 4.4 MarketBoardRequestItemListings = 0x0103, // updated 4.5
MarketBoardSearch = 0x0103, // updated 4.4 MarketBoardSearch = 0x0107, // updated 4.5
ReqExamineFcInfo = 0x010F, // updated 4.1 ReqExamineFcInfo = 0x0113, // updated 4.1
FcInfoReqHandler = 0x011A, // updated 4.2 FcInfoReqHandler = 0x011A, // updated 4.2
@ -276,51 +276,51 @@ namespace Sapphire::Network::Packets
ReqJoinNoviceNetwork = 0x0129, // updated 4.2 ReqJoinNoviceNetwork = 0x0129, // updated 4.2
ReqCountdownInitiate = 0x012F, // updated 4.4 ReqCountdownInitiate = 0x0133, // updated 4.5
ReqCountdownCancel = 0x0130, // updated 4.4 ReqCountdownCancel = 0x0134, // updated 4.5
ClearWaymarks = 0x0131, // updated 4.4 ClearWaymarks = 0x0135, // updated 4.5
ZoneLineHandler = 0x0133, // updated 4.4 ZoneLineHandler = 0x0137, // updated 4.5
ClientTrigger = 0x0134, // updated 4.4 was 13D in 4.3 ClientTrigger = 0x0138, // updated 4.5
DiscoveryHandler = 0x0135, // updated 4.4 DiscoveryHandler = 0x0139, // updated 4.5
AddWaymark = 0x013F, // updated 4.3 AddWaymark = 0x013A, // updated 4.5
SkillHandler = 0x0137, // updated 4.4 SkillHandler = 0x013B, // updated 4.5
GMCommand1 = 0x0138, // updated 4.4 GMCommand1 = 0x013C, // updated 4.5
GMCommand2 = 0x0139, // updated 4.4 GMCommand2 = 0x013D, // updated 4.5
UpdatePositionHandler = 0x013B, // updated 4.4 was 144 UpdatePositionHandler = 0x013F, // updated 4.5
UpdatePositionInstance = 0x0183, // updated 4.3 UpdatePositionInstance = 0x0183, // updated 4.3
InventoryModifyHandler = 0x0142, // updated 4.4 InventoryModifyHandler = 0x0146, // updated 4.5 ( +4 )
ReqPlaceHousingItem = 0x145, // updated 4.4 ReqPlaceHousingItem = 0x149, // updated 4.5
BuildPresetHandler = 0x014A, // updated 4.4 BuildPresetHandler = 0x014E, // updated 4.5
TalkEventHandler = 0x014B, // updated 4.4 TalkEventHandler = 0x014F, // updated 4.5
EmoteEventHandler = 0x014C, // updated 4.4 EmoteEventHandler = 0x0150, // updated 4.5
WithinRangeEventHandler = 0x014D, // updated 4.4 WithinRangeEventHandler = 0x0151, // updated 4.5
OutOfRangeEventHandler = 0x014E, // updated 4.4 OutOfRangeEventHandler = 0x0152, // updated 4.5
EnterTeriEventHandler = 0x014F, // updated 4.4 EnterTeriEventHandler = 0x0153, // updated 4.5
ShopEventHandler = 0x0151, // updated 4.4 ShopEventHandler = 0x0155, // updated 4.5
ReturnEventHandler = 0x0154, // updated 4.4 ReturnEventHandler = 0x0158, // updated 4.5
TradeReturnEventHandler = 0x0155, // updated 4.4 TradeReturnEventHandler = 0x0159, // updated 4.5
LinkshellEventHandler = 0x1150, // updated 4.1 ?? LinkshellEventHandler = 0x1150, // updated 4.1 ??
LinkshellEventHandler1 = 0x1151, // updated 4.1 ?? LinkshellEventHandler1 = 0x1151, // updated 4.1 ??
LandRenameHandler = 0x0171, // updated 4.4 LandRenameHandler = 0x0175, // updated 4.5
HousingUpdateHouseGreeting = 0x0172, // updated 4.4 HousingUpdateHouseGreeting = 0x0176, // updated 4.5
HousingUpdateObjectPosition = 0x0173, // updated 4.4 HousingUpdateObjectPosition = 0x0177, // updated 4.5
SetSharedEstateSettings = 0x0177, // updated 4.4 SetSharedEstateSettings = 0x017B, // updated 4.5
PerformNoteHandler = 0x029B, // updated 4.3 PerformNoteHandler = 0x029B, // updated 4.3
ReqEquipDisplayFlagsChange = 0x016F, // updated 4.4 ReqEquipDisplayFlagsChange = 0x0173, // updated 4.5
}; };

View file

@ -29,8 +29,9 @@ struct FFXIVIpcGmCommand2 :
/* 0008 */ uint32_t param2; /* 0008 */ uint32_t param2;
/* 000C */ uint32_t param3; /* 000C */ uint32_t param3;
/* 0010 */ uint32_t param4; /* 0010 */ uint32_t param4;
/* 0014 */ char target[0x20]; /* 0014 */ uint16_t worldId;
/* 0034 */ uint32_t unknown1; /* 0016 */ char target[0x20];
/* 0036 */ uint16_t unknown1;
}; };
struct FFXIVIpcClientTrigger : struct FFXIVIpcClientTrigger :
@ -146,12 +147,16 @@ struct FFXIVIpcSetSearchInfo :
/* 0012 */ char searchComment[193]; /* 0012 */ char searchComment[193];
}; };
struct FFXIVIpcTellHandler : struct FFXIVIpcTellHandler : FFXIVIpcBasePacket< TellReq >
FFXIVIpcBasePacket< TellReq >
{ {
/* 0000 */ char pad_0000[4]; uint64_t contentId;
uint16_t worldId;
uint16_t u0A;
uint32_t u0C;
uint16_t worldId1;
uint8_t preName;
/* 0004 */ char targetPCName[32]; /* 0004 */ char targetPCName[32];
/* 0024 */ char message[1012]; /* 0024 */ char message[1029];
}; };
struct FFXIVIpcChatHandler : struct FFXIVIpcChatHandler :

View file

@ -158,7 +158,7 @@ struct FFXIVIpcServerNotice :
FFXIVIpcBasePacket< ServerNotice > FFXIVIpcBasePacket< ServerNotice >
{ {
/* 0000 */ uint8_t padding; /* 0000 */ uint8_t padding;
char message[307]; char message[775];
}; };
struct FFXIVIpcSetOnlineStatus : struct FFXIVIpcSetOnlineStatus :
@ -482,10 +482,8 @@ struct FFXIVIpcPlayerSpawn :
{ {
uint16_t title; uint16_t title;
uint16_t u1b; uint16_t u1b;
uint8_t u2b; uint16_t currentWorldId;
uint8_t u2ab; uint16_t homeWorldId;
uint8_t u3a;
uint8_t u3b;
uint8_t gmRank; uint8_t gmRank;
uint8_t u3c; uint8_t u3c;
@ -759,7 +757,9 @@ struct FFXIVIpcInitZone : FFXIVIpcBasePacket< InitZone >
uint32_t unknown9; uint32_t unknown9;
uint32_t unknown10; uint32_t unknown10;
uint32_t unknown11; uint32_t unknown11;
uint32_t unknown12[4];
Common::FFXIVARR_POSITION3 pos; Common::FFXIVARR_POSITION3 pos;
uint32_t unknown13;
}; };
@ -833,70 +833,70 @@ struct FFXIVIpcInitUI : FFXIVIpcBasePacket< InitUI >
unsigned char unknown95[10]; unsigned char unknown95[10];
unsigned char unknown9F[2]; unsigned char unknown9F[2];
unsigned char unknownA1[3]; unsigned char unknownA1[3];
unsigned int exp[25]; unsigned int exp[26];
unsigned int unknown108; unsigned int unknown108;
unsigned int pvpTotalExp; unsigned int pvpTotalExp;
unsigned int unknownPvp110; unsigned int unknownPvp110;
unsigned int pvpExp; unsigned int pvpExp;
unsigned int pvpFrontlineOverallRanks[3]; unsigned int pvpFrontlineOverallRanks[3];
unsigned int exploratoryMissionNextTimestamp; unsigned short levels[26];
unsigned short levels[25];
unsigned short unknown15C[9]; unsigned short unknown15C[9];
unsigned short u1;
unsigned short u2;
unsigned short unknown112[23];
unsigned short fishingRecordsFish[26]; unsigned short fishingRecordsFish[26];
unsigned short fishingRecordsFishWeight[26];
unsigned short beastExp[11]; unsigned short beastExp[11];
unsigned short unknown1EA[5]; unsigned short unknown1EA[5];
unsigned short pvpFrontlineWeeklyRanks[3]; unsigned short pvpFrontlineWeeklyRanks[3];
unsigned short unknownMask1FA[3]; unsigned short unknownMask1FA[4];
unsigned char companionName[21]; unsigned char companionName[21];
unsigned char companionDefRank; unsigned char companionDefRank;
unsigned char companionAttRank; unsigned char companionAttRank;
unsigned char companionHealRank; unsigned char companionHealRank;
unsigned char u19[2];
unsigned char mountGuideMask[17]; unsigned char mountGuideMask[17];
char name[32]; char name[32];
unsigned char unknownOword[16]; unsigned char unknownOword[16];
unsigned char unknown258; unsigned char unknownOw;
unsigned char unlockBitmask[64]; unsigned char unlockBitmask[64];
unsigned char aetheryte[17]; unsigned char aetheryte[17];
unsigned char discovery[421]; unsigned char discovery[421];
unsigned char howto[33]; unsigned char howto[34];
unsigned char minions[40]; unsigned char minions[42];
unsigned char chocoboTaxiMask[8]; unsigned char chocoboTaxiMask[8];
unsigned char watchedCutscenes[115]; unsigned char watchedCutscenes[118];
unsigned char companionBardingMask[9]; unsigned char companionBardingMask[9];
unsigned char companionEquippedHead; unsigned char companionEquippedHead;
unsigned char companionEquippedBody; unsigned char companionEquippedBody;
unsigned char companionEquippedLegs; unsigned char companionEquippedLegs;
unsigned char unknown519[4]; unsigned char unknown52A[4];
unsigned char unknownMask51D[11]; unsigned char unknownMask52E[11];
unsigned char fishingGuideMask[89]; unsigned char fishingGuideMask[89];
unsigned char fishingSpotVisited[25]; unsigned char fishingSpotVisited[25];
unsigned char unknown59A[15]; unsigned char unknown59A[15];
unsigned char unknown5A9[2]; unsigned char unknown5A9[5];
unsigned char unknownPvp5AB[2];
unsigned char pvpLevel;
unsigned char beastRank[11]; unsigned char beastRank[11];
unsigned char unknown5B9[11]; unsigned char unknownPvp5AB[11];
unsigned char unknown5B9[5];
unsigned char unknown5B91;
unsigned char pose; unsigned char pose;
unsigned char weaponPose;
unsigned char unknownMask5C4[3];
unsigned char unknown5C9[2];
unsigned char challengeLogComplete[9]; unsigned char challengeLogComplete[9];
unsigned char unknown5D4[11]; unsigned char weaponPose;
unsigned char unknownMask673[10];
unsigned char unknownMask5DD[28]; unsigned char unknownMask5DD[28];
unsigned char relicCompletion[12]; unsigned char relicCompletion[12];
unsigned char sightseeingMask[26]; unsigned char sightseeingMask[26];
unsigned char huntingMarkMask[55]; unsigned char huntingMarkMask[55];
unsigned char tripleTriadCards[30]; unsigned char tripleTriadCards[32];
unsigned char unknownMask673[10]; unsigned char u12[11];
unsigned char unknown67D; unsigned char u13;
unsigned char aetherCurrentMask[22]; unsigned char aetherCurrentMask[22];
unsigned char unknown694[3]; unsigned char u10[3];
unsigned char orchestrionMask[40]; unsigned char orchestrionMask[40];
unsigned char hallOfNoviceCompleteMask[3]; unsigned char hallOfNoviceCompletion[3];
unsigned char animaCompletion[11]; unsigned char animaCompletion[11];
unsigned char unknown6CD[16]; unsigned char u14[16];
unsigned char unknownMask6DB[11]; unsigned char u15[13];
unsigned char unlockedRaids[28]; unsigned char unlockedRaids[28];
unsigned char unlockedDungeons[18]; unsigned char unlockedDungeons[18];
unsigned char unlockedGuildhests[10]; unsigned char unlockedGuildhests[10];
@ -907,15 +907,17 @@ struct FFXIVIpcInitUI : FFXIVIpcBasePacket< InitUI >
unsigned char clearedGuildhests[10]; unsigned char clearedGuildhests[10];
unsigned char clearedTrials[8]; unsigned char clearedTrials[8];
unsigned char clearedPvp[5]; unsigned char clearedPvp[5];
unsigned short fishingRecordsFishWeight[26];
unsigned int exploratoryMissionNextTimestamp;
unsigned char pvpLevel;
}; };
/** /**
* Structural representation of the packet sent by the server * Structural representation of the packet sent by the server
* to set a players stats * to set a players stats
*/ */
struct FFXIVIpcPlayerStats : struct FFXIVIpcPlayerStats : FFXIVIpcBasePacket< PlayerStats >
FFXIVIpcBasePacket< PlayerStats >
{ {
uint32_t strength; uint32_t strength;
uint32_t dexterity; uint32_t dexterity;
@ -1439,7 +1441,7 @@ struct FFXIVIpcPrepareZoning :
uint8_t fadeOut; uint8_t fadeOut;
uint8_t param7; uint8_t param7;
uint8_t fadeOutTime; uint8_t fadeOutTime;
uint8_t unknown; uint8_t unknown; // this changes whether or not the destination zone's name displays during the loading screen. Seems to always be 9 (=hidden) when going to an instance and certain zones, 0 otherwise.
uint16_t padding; uint16_t padding;
}; };
@ -1561,6 +1563,11 @@ struct FFXIVIpcDirectorVars : FFXIVIpcBasePacket< DirectorVars >
uint8_t m_branch; uint8_t m_branch;
/*! raw storage for flags/vars */ /*! raw storage for flags/vars */
uint8_t m_unionData[10]; uint8_t m_unionData[10];
/*! unknown */
uint16_t u20;
uint16_t u22;
uint16_t u24;
uint16_t u28;
}; };
@ -1692,7 +1699,7 @@ struct FFXIVIpcHousingObjectMove : FFXIVIpcBasePacket< HousingObjectMove >
uint16_t itemRotation; uint16_t itemRotation;
uint8_t objectArray; uint8_t objectArray;
uint8_t landId; uint8_t landId;
Common::FFXIVARR_POSITION3_U16 pos; Common::FFXIVARR_POSITION3 pos;
uint16_t unknown1; uint16_t unknown1;
uint16_t unknown2; uint16_t unknown2;
uint16_t unknown3; uint16_t unknown3;
@ -1723,7 +1730,7 @@ struct FFXIVIpcHousingInternalObjectSpawn : FFXIVIpcBasePacket< HousingInternalO
uint8_t unk2; uint8_t unk2;
uint8_t pad2; uint8_t pad2;
uint16_t rotation; uint16_t rotation;
Common::FFXIVARR_POSITION3_U16 pos; Common::FFXIVARR_POSITION3 pos;
}; };
struct FFXIVIpcHousingIndoorInitialize : FFXIVIpcBasePacket< HousingIndoorInitialize > struct FFXIVIpcHousingIndoorInitialize : FFXIVIpcBasePacket< HousingIndoorInitialize >

View file

@ -15,7 +15,6 @@
#include "RestConnector.h" #include "RestConnector.h"
#include "LobbySession.h" #include "LobbySession.h"
extern Sapphire::Logger g_log;
extern Sapphire::ServerLobby g_serverLobby; extern Sapphire::ServerLobby g_serverLobby;
extern Sapphire::Network::RestConnector g_restConnector; extern Sapphire::Network::RestConnector g_restConnector;
@ -44,13 +43,13 @@ void Sapphire::Network::GameConnection::OnAccept( const std::string& host, uint1
auto connection = make_GameConnection( m_hive, m_pAcceptor, m_pFw ); auto connection = make_GameConnection( m_hive, m_pAcceptor, m_pFw );
m_pAcceptor->Accept( connection ); m_pAcceptor->Accept( connection );
g_log.info( "Connect from " + m_socket.remote_endpoint().address().to_string() ); Logger::info( "Connect from {0}", m_socket.remote_endpoint().address().to_string() );
} }
void Sapphire::Network::GameConnection::OnDisconnect() void Sapphire::Network::GameConnection::OnDisconnect()
{ {
g_log.debug( "DISCONNECT" ); Logger::debug( "DISCONNECT" );
} }
void Sapphire::Network::GameConnection::OnRecv( std::vector< uint8_t >& buffer ) void Sapphire::Network::GameConnection::OnRecv( std::vector< uint8_t >& buffer )
@ -60,15 +59,15 @@ void Sapphire::Network::GameConnection::OnRecv( std::vector< uint8_t >& buffer )
if( headerResult == Incomplete ) if( headerResult == Incomplete )
{ {
g_log.info( "Dropping connection due to incomplete packet header." ); Logger::info( "Dropping connection due to incomplete packet header." );
g_log.info( "FIXME: Packet message bounary is not implemented." ); Logger::info( "FIXME: Packet message bounary is not implemented." );
Disconnect(); Disconnect();
return; return;
} }
if( headerResult == Malformed ) if( headerResult == Malformed )
{ {
g_log.info( "Dropping connection due to malformed packet header." ); Logger::info( "Dropping connection due to malformed packet header." );
Disconnect(); Disconnect();
return; return;
} }
@ -80,15 +79,15 @@ void Sapphire::Network::GameConnection::OnRecv( std::vector< uint8_t >& buffer )
if( packetResult == Incomplete ) if( packetResult == Incomplete )
{ {
g_log.info( "Dropping connection due to incomplete packets." ); Logger::info( "Dropping connection due to incomplete packets." );
g_log.info( "FIXME: Packet message bounary is not implemented." ); Logger::info( "FIXME: Packet message bounary is not implemented." );
Disconnect(); Disconnect();
return; return;
} }
if( packetResult == Malformed ) if( packetResult == Malformed )
{ {
g_log.info( "Dropping connection due to malformed packets." ); Logger::info( "Dropping connection due to malformed packets." );
Disconnect(); Disconnect();
return; return;
} }
@ -100,7 +99,7 @@ void Sapphire::Network::GameConnection::OnRecv( std::vector< uint8_t >& buffer )
void Sapphire::Network::GameConnection::OnError( const asio::error_code& error ) void Sapphire::Network::GameConnection::OnError( const asio::error_code& error )
{ {
g_log.info( "GameConnection closed: " + error.message() ); Logger::info( "GameConnection closed: {0}", error.message() );
} }
void void
@ -119,20 +118,19 @@ Sapphire::Network::GameConnection::sendError( uint64_t sequence, uint32_t errorc
void Sapphire::Network::GameConnection::getCharList( FFXIVARR_PACKET_RAW& packet, uint32_t tmpId ) void Sapphire::Network::GameConnection::getCharList( FFXIVARR_PACKET_RAW& packet, uint32_t tmpId )
{ {
uint64_t sequence = *reinterpret_cast< uint64_t* >( &packet.data[ 0 ] + 0x10 ); uint64_t sequence = *reinterpret_cast< uint64_t* >( &packet.data[ 0 ] + 0x10 );
g_log.info( "Sequence [" + std::to_string( sequence ) + "]" ); Logger::info( "Sequence [{0}]", sequence );
g_log.info( "[" + std::to_string( m_pSession->getAccountID() ) + "] ReqCharList" ); Logger::info( "[{0}] ReqCharList", m_pSession->getAccountID() );
Packets::LobbyPacketContainer pRP( m_encKey ); Packets::LobbyPacketContainer pRP( m_encKey );
auto serverListPacket = makeLobbyPacket< FFXIVIpcServerList >( tmpId ); auto serverListPacket = makeLobbyPacket< FFXIVIpcServerList >( tmpId );
serverListPacket->data().seq = 1; serverListPacket->data().seq = 1;
serverListPacket->data().offset = 0; serverListPacket->data().offset = 0;
serverListPacket->data().numServers = 1; serverListPacket->data().numServers = 1;
serverListPacket->data().server[ 0 ].id = g_serverLobby.getConfig()->getValue< uint16_t >( "Lobby", "WorldID", 1 ); serverListPacket->data().server[ 0 ].id = g_serverLobby.getConfig().global.general.worldID;
serverListPacket->data().server[ 0 ].index = 0; serverListPacket->data().server[ 0 ].index = 0;
serverListPacket->data().final = 1; serverListPacket->data().final = 1;
strcpy( serverListPacket->data().server[ 0 ].name, strcpy( serverListPacket->data().server[ 0 ].name, g_serverLobby.getConfig().worldName.c_str() );
g_serverLobby.getConfig()->getValue< std::string >( "Lobby", "WorldName", "Sapphire" ).c_str() );
pRP.addPacket( serverListPacket ); pRP.addPacket( serverListPacket );
auto retainerListPacket = makeLobbyPacket< FFXIVIpcRetainerList >( tmpId ); auto retainerListPacket = makeLobbyPacket< FFXIVIpcRetainerList >( tmpId );
@ -162,22 +160,22 @@ void Sapphire::Network::GameConnection::getCharList( FFXIVARR_PACKET_RAW& packet
auto& charEntry = charList[ charIndex ]; auto& charEntry = charList[ charIndex ];
details.uniqueId = std::get< 1 >( charEntry ); details.uniqueId = std::get< 1 >( charEntry );
details.contentId = std::get< 2 >( charEntry ); details.contentId = std::get< 2 >( charEntry );
details.serverId = g_serverLobby.getConfig()->getValue< uint16_t >( "Lobby", "WorldID", 1 ); details.serverId = g_serverLobby.getConfig().global.general.worldID;
details.serverId1 = g_serverLobby.getConfig()->getValue< uint16_t >( "Lobby", "WorldID", 1 ); details.serverId1 = g_serverLobby.getConfig().global.general.worldID;
details.index = charIndex; details.index = charIndex;
strcpy( details.charDetailJson, std::get< 3 >( charEntry ).c_str() ); strcpy( details.charDetailJson, std::get< 3 >( charEntry ).c_str() );
strcpy( details.nameChara, std::get< 0 >( charEntry ).c_str() ); strcpy( details.nameChara, std::get< 0 >( charEntry ).c_str() );
strcpy( details.nameServer, strcpy( details.nameServer, g_serverLobby.getConfig().worldName.c_str() );
g_serverLobby.getConfig()->getValue< std::string >( "Lobby", "WorldName", "Sapphire" ).c_str() ); strcpy( details.nameServer1, g_serverLobby.getConfig().worldName.c_str() );
strcpy( details.nameServer1,
g_serverLobby.getConfig()->getValue< std::string >( "Lobby", "WorldName", "Sapphire" ).c_str() );
charListPacket->data().charaDetails[ j ] = details; charListPacket->data().charaDetails[ j ] = details;
g_log.debug( "[" + std::to_string( charIndex ) + "] " + std::to_string( details.index ) + " - " Logger::debug( "[{0}] {1} - {2} - {3} - {4} - {5}",
+ std::get< 0 >( charEntry ) + " - " + charIndex,
std::to_string( std::get< 1 >( charEntry ) ) + " - " + details.index,
std::to_string( std::get< 2 >( charEntry ) ) + " - " + std::get< 0 >( charEntry ),
std::get< 1 >( charEntry ),
std::get< 2 >( charEntry ),
std::get< 3 >( charEntry ) ); std::get< 3 >( charEntry ) );
} }
charIndex++; charIndex++;
@ -204,9 +202,9 @@ void Sapphire::Network::GameConnection::getCharList( FFXIVARR_PACKET_RAW& packet
void Sapphire::Network::GameConnection::enterWorld( FFXIVARR_PACKET_RAW& packet, uint32_t tmpId ) void Sapphire::Network::GameConnection::enterWorld( FFXIVARR_PACKET_RAW& packet, uint32_t tmpId )
{ {
uint64_t sequence = *reinterpret_cast< uint64_t* >( &packet.data[ 0 ] + 0x10 ); uint64_t sequence = *reinterpret_cast< uint64_t* >( &packet.data[ 0 ] + 0x10 );
g_log.info( "Sequence [" + std::to_string( sequence ) + "]" ); Logger::info( "Sequence [{0}]", sequence );
g_log.info( "[" + std::to_string( m_pSession->getAccountID() ) + "] ReqEnterWorld" ); Logger::info( "[{0}] ReqEnterWorld", m_pSession->getAccountID() );
uint64_t lookupId = *reinterpret_cast< uint64_t* >( &packet.data[ 0 ] + 0x18 ); uint64_t lookupId = *reinterpret_cast< uint64_t* >( &packet.data[ 0 ] + 0x18 );
@ -228,17 +226,15 @@ void Sapphire::Network::GameConnection::enterWorld( FFXIVARR_PACKET_RAW& packet,
if( logInCharId == -1 ) if( logInCharId == -1 )
return; return;
g_log.info( "[" + std::to_string( m_pSession->getAccountID() ) + "] Logging in as " + logInCharName + "(" + Logger::info( "[{0}] Logging in as {1} ({2})", m_pSession->getAccountID(), logInCharName, logInCharId );
std::to_string( logInCharId ) + ")" );
Packets::LobbyPacketContainer pRP( m_encKey ); Packets::LobbyPacketContainer pRP( m_encKey );
auto enterWorldPacket = makeLobbyPacket< FFXIVIpcEnterWorld >( tmpId ); auto enterWorldPacket = makeLobbyPacket< FFXIVIpcEnterWorld >( tmpId );
enterWorldPacket->data().contentId = lookupId; enterWorldPacket->data().contentId = lookupId;
enterWorldPacket->data().seq = sequence; enterWorldPacket->data().seq = sequence;
strcpy( enterWorldPacket->data().host, strcpy( enterWorldPacket->data().host, g_serverLobby.getConfig().global.network.zoneHost.c_str() );
g_serverLobby.getConfig()->getValue< std::string >( "GlobalNetwork", "ZoneHost" ).c_str() ); enterWorldPacket->data().port = g_serverLobby.getConfig().global.network.zonePort;
enterWorldPacket->data().port = g_serverLobby.getConfig()->getValue< uint16_t >( "GlobalNetwork", "ZonePort" );
enterWorldPacket->data().charId = logInCharId; enterWorldPacket->data().charId = logInCharId;
memcpy( enterWorldPacket->data().sid, m_pSession->getSessionId(), 66 ); memcpy( enterWorldPacket->data().sid, m_pSession->getSessionId(), 66 );
pRP.addPacket( enterWorldPacket ); pRP.addPacket( enterWorldPacket );
@ -249,18 +245,18 @@ bool Sapphire::Network::GameConnection::sendServiceAccountList( FFXIVARR_PACKET_
{ {
LobbySessionPtr pSession = g_serverLobby.getSession( ( char* ) &packet.data[ 0 ] + 0x20 ); LobbySessionPtr pSession = g_serverLobby.getSession( ( char* ) &packet.data[ 0 ] + 0x20 );
if( g_serverLobby.getConfig()->getValue< bool >( "Lobby", "AllowNoSessionConnect" ) && pSession == nullptr ) if( g_serverLobby.getConfig().allowNoSessionConnect && pSession == nullptr )
{ {
auto session = make_LobbySession(); auto session = make_LobbySession();
session->setAccountID( 0 ); session->setAccountID( 0 );
session->setSessionId( ( uint8_t* ) &packet.data[ 0 ] + 0x20 ); session->setSessionId( ( uint8_t* ) &packet.data[ 0 ] + 0x20 );
pSession = session; pSession = session;
g_log.info( "Allowed connection with no session: " + std::string( ( char* ) &packet.data[ 0 ] + 0x20 ) ); Logger::info( "Allowed connection with no session: {0}", std::string( ( char* ) &packet.data[ 0 ] + 0x20 ) );
} }
if( pSession != nullptr ) if( pSession != nullptr )
{ {
g_log.info( "Found session linked to accountId: " + std::to_string( pSession->getAccountID() ) ); Logger::info( "Found session linked to accountId: {0}", pSession->getAccountID() );
m_pSession = pSession; m_pSession = pSession;
auto serviceIdInfoPacket = makeLobbyPacket< FFXIVIpcServiceIdInfo >( tmpId ); auto serviceIdInfoPacket = makeLobbyPacket< FFXIVIpcServiceIdInfo >( tmpId );
@ -276,7 +272,7 @@ bool Sapphire::Network::GameConnection::sendServiceAccountList( FFXIVARR_PACKET_
} }
else else
{ {
g_log.info( "Could not retrieve session: " + std::string( ( char* ) &packet.data[ 0 ] + 0x20 ) ); Logger::info( "Could not retrieve session: {0}", std::string( ( char* ) &packet.data[ 0 ] + 0x20 ) );
sendError( 1, 5006, 13001, tmpId ); sendError( 1, 5006, 13001, tmpId );
return true; return true;
@ -288,10 +284,10 @@ bool Sapphire::Network::GameConnection::createOrModifyChar( FFXIVARR_PACKET_RAW&
{ {
uint64_t sequence = *reinterpret_cast< uint64_t* >( &packet.data[ 0 ] + 0x10 ); uint64_t sequence = *reinterpret_cast< uint64_t* >( &packet.data[ 0 ] + 0x10 );
uint8_t type = *reinterpret_cast< uint8_t* >( &packet.data[ 0 ] + 0x29 ); uint8_t type = *reinterpret_cast< uint8_t* >( &packet.data[ 0 ] + 0x29 );
g_log.info( "Sequence [" + std::to_string( sequence ) + "]" ); Logger::info( "Sequence [{0}]", sequence );
g_log.info( "Type [" + std::to_string( type ) + "]" ); Logger::info( "Type [{0}]", type );
g_log.info( "[" + std::to_string( m_pSession->getAccountID() ) + "] ReqCharCreate" ); Logger::info( "[{0}] ReqCharCreate", m_pSession->getAccountID() );
std::string name; std::string name;
uint32_t newId = g_restConnector.getNextCharId(); uint32_t newId = g_restConnector.getNextCharId();
@ -301,7 +297,7 @@ bool Sapphire::Network::GameConnection::createOrModifyChar( FFXIVARR_PACKET_RAW&
{ {
name = std::string( ( char* ) &packet.data[ 0 ] + 0x2C ); name = std::string( ( char* ) &packet.data[ 0 ] + 0x2C );
g_log.info( "[" + std::to_string( m_pSession->getAccountID() ) + "] Type 1: " + name ); Logger::info( "[{0}] Type 1: {1}", m_pSession->getAccountID(), name );
Packets::LobbyPacketContainer pRP( m_encKey ); Packets::LobbyPacketContainer pRP( m_encKey );
@ -316,8 +312,7 @@ bool Sapphire::Network::GameConnection::createOrModifyChar( FFXIVARR_PACKET_RAW&
auto charCreatePacket = makeLobbyPacket< FFXIVIpcCharCreate >( tmpId ); auto charCreatePacket = makeLobbyPacket< FFXIVIpcCharCreate >( tmpId );
charCreatePacket->data().content_id = newContentId; charCreatePacket->data().content_id = newContentId;
strcpy( charCreatePacket->data().name, name.c_str() ); strcpy( charCreatePacket->data().name, name.c_str() );
strcpy( charCreatePacket->data().world, strcpy( charCreatePacket->data().world, g_serverLobby.getConfig().worldName.c_str() );
g_serverLobby.getConfig()->getValue< std::string >( "Lobby", "WorldName", "Sapphire" ).c_str() );
charCreatePacket->data().type = 1; charCreatePacket->data().type = 1;
charCreatePacket->data().seq = sequence; charCreatePacket->data().seq = sequence;
charCreatePacket->data().unknown = 1; charCreatePacket->data().unknown = 1;
@ -330,7 +325,7 @@ bool Sapphire::Network::GameConnection::createOrModifyChar( FFXIVARR_PACKET_RAW&
else if( type == 2 ) //Character creation finalize else if( type == 2 ) //Character creation finalize
{ {
std::string charDetails( ( char* ) &packet.data[ 0 ] + 0x4C ); std::string charDetails( ( char* ) &packet.data[ 0 ] + 0x4C );
g_log.info( "[" + std::to_string( m_pSession->getAccountID() ) + "] Type 2: " + charDetails ); Logger::info( "[{0}] Type 2: {1}", m_pSession->getAccountID(), charDetails );
if( g_restConnector.createCharacter( ( char* ) m_pSession->getSessionId(), m_pSession->newCharName, charDetails ) != if( g_restConnector.createCharacter( ( char* ) m_pSession->getSessionId(), m_pSession->newCharName, charDetails ) !=
-1 ) -1 )
@ -340,10 +335,8 @@ bool Sapphire::Network::GameConnection::createOrModifyChar( FFXIVARR_PACKET_RAW&
auto charCreatePacket = makeLobbyPacket< FFXIVIpcCharCreate >( tmpId ); auto charCreatePacket = makeLobbyPacket< FFXIVIpcCharCreate >( tmpId );
charCreatePacket->data().content_id = newContentId; charCreatePacket->data().content_id = newContentId;
strcpy( charCreatePacket->data().name, name.c_str() ); strcpy( charCreatePacket->data().name, name.c_str() );
strcpy( charCreatePacket->data().world, strcpy( charCreatePacket->data().world, g_serverLobby.getConfig().worldName.c_str() );
g_serverLobby.getConfig()->getValue< std::string >( "Lobby", "WorldName", "Sapphire" ).c_str() ); strcpy( charCreatePacket->data().world2, g_serverLobby.getConfig().worldName.c_str() );
strcpy( charCreatePacket->data().world2,
g_serverLobby.getConfig()->getValue< std::string >( "Lobby", "WorldName", "Sapphire" ).c_str() );
charCreatePacket->data().type = 2; charCreatePacket->data().type = 2;
charCreatePacket->data().seq = sequence; charCreatePacket->data().seq = sequence;
charCreatePacket->data().unknown = 1; charCreatePacket->data().unknown = 1;
@ -361,7 +354,7 @@ bool Sapphire::Network::GameConnection::createOrModifyChar( FFXIVARR_PACKET_RAW&
else if( type == 4 ) //Character delete else if( type == 4 ) //Character delete
{ {
name = std::string( ( char* ) &packet.data[ 0 ] + 0x2C ); name = std::string( ( char* ) &packet.data[ 0 ] + 0x2C );
g_log.info( "[" + std::to_string( m_pSession->getAccountID() ) + "] Type 4: " + name ); Logger::info( "[{0}] Type 4: {1}", m_pSession->getAccountID(), name );
if( g_restConnector.deleteCharacter( ( char* ) m_pSession->getSessionId(), name ) ) if( g_restConnector.deleteCharacter( ( char* ) m_pSession->getSessionId(), name ) )
@ -371,8 +364,7 @@ bool Sapphire::Network::GameConnection::createOrModifyChar( FFXIVARR_PACKET_RAW&
//charCreatePacket->data().content_id = deletePlayer.getContentId(); //charCreatePacket->data().content_id = deletePlayer.getContentId();
charCreatePacket->data().content_id = 0; charCreatePacket->data().content_id = 0;
strcpy( charCreatePacket->data().name, name.c_str() ); strcpy( charCreatePacket->data().name, name.c_str() );
strcpy( charCreatePacket->data().world, strcpy( charCreatePacket->data().world, g_serverLobby.getConfig().worldName.c_str() );
g_serverLobby.getConfig()->getValue< std::string >( "Lobby", "WorldName", "Sapphire" ).c_str() );
charCreatePacket->data().type = 4; charCreatePacket->data().type = 4;
charCreatePacket->data().seq = sequence; charCreatePacket->data().seq = sequence;
charCreatePacket->data().unknown = 1; charCreatePacket->data().unknown = 1;
@ -391,8 +383,7 @@ bool Sapphire::Network::GameConnection::createOrModifyChar( FFXIVARR_PACKET_RAW&
} }
else else
{ {
g_log.error( "[" + std::to_string( m_pSession->getAccountID() ) + "] Unknown Character Creation Type: " + Logger::error( "[{0}] Unknown Character Creation Type: {1}", m_pSession->getAccountID(), type );
std::to_string( type ) );
} }
return false; return false;
} }
@ -402,7 +393,7 @@ void Sapphire::Network::GameConnection::handleGamePacket( Packets::FFXIVARR_PACK
uint32_t tmpId = packet.segHdr.target_actor; uint32_t tmpId = packet.segHdr.target_actor;
g_log.info( "OpCode [" + std::to_string( *reinterpret_cast< uint16_t* >( &packet.data[ 2 ] ) ) + "]" ); Logger::info( "OpCode [{0}]", *reinterpret_cast< uint16_t* >( &packet.data[ 2 ] ) );
switch( *reinterpret_cast< uint16_t* >( &packet.data[ 2 ] ) ) switch( *reinterpret_cast< uint16_t* >( &packet.data[ 2 ] ) )
{ {
@ -446,7 +437,6 @@ void Sapphire::Network::GameConnection::sendPacket( Packets::LobbyPacketContaine
void Sapphire::Network::GameConnection::sendPackets( Packets::PacketContainer* pPacket ) void Sapphire::Network::GameConnection::sendPackets( Packets::PacketContainer* pPacket )
{ {
//g_log.Log(LoggingSeverity::info, pPacket->toString());
std::vector< uint8_t > sendBuffer; std::vector< uint8_t > sendBuffer;
pPacket->fillSendBuffer( sendBuffer ); pPacket->fillSendBuffer( sendBuffer );
@ -511,7 +501,7 @@ void Sapphire::Network::GameConnection::handlePackets( const Sapphire::Network::
case SEGMENTTYPE_IPC: // game packet case SEGMENTTYPE_IPC: // game packet
{ {
g_log.info( "GamePacket [" + std::to_string( inPacket.segHdr.type ) + "]" ); Logger::info( "GamePacket [{0}]", inPacket.segHdr.type );
handleGamePacket( inPacket ); handleGamePacket( inPacket );
break; break;
} }

View file

@ -8,8 +8,6 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
extern Sapphire::Logger g_log;
typedef std::vector< std::tuple< std::string, uint32_t, uint64_t, std::string > > CharList; typedef std::vector< std::tuple< std::string, uint32_t, uint64_t, std::string > > CharList;
Sapphire::Network::RestConnector::RestConnector() Sapphire::Network::RestConnector::RestConnector()
@ -35,7 +33,7 @@ HttpResponse Sapphire::Network::RestConnector::requestApi( std::string endpoint,
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
g_log.error( endpoint + " failed, REST is not reachable: " + std::string( e.what() ) ); Logger::error( "{0} failed, Api is not reachable: {1}", endpoint, e.what() );
return nullptr; return nullptr;
} }
return r; return r;
@ -61,7 +59,7 @@ Sapphire::LobbySessionPtr Sapphire::Network::RestConnector::getSession( char* sI
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
g_log.debug( "Could not parse REST response: " + std::string( e.what() ) ); Logger::debug( "Could not parse Api response: {0}", e.what() );
return nullptr; return nullptr;
} }
@ -103,7 +101,7 @@ bool Sapphire::Network::RestConnector::checkNameTaken( std::string name )
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
g_log.debug( "Could not parse REST response: " + std::string( e.what() ) ); Logger::debug( "Could not parse Api response: {0}", e.what() );
return true; return true;
} }
@ -137,7 +135,7 @@ uint32_t Sapphire::Network::RestConnector::getNextCharId()
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
g_log.debug( "Could not parse REST response: " + std::string( e.what() ) ); Logger::debug( "Could not parse Api response: {0}", e.what() );
return -1; return -1;
} }
@ -176,7 +174,7 @@ uint64_t Sapphire::Network::RestConnector::getNextContentId()
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
g_log.debug( "Could not parse REST response: " + std::string( e.what() ) ); Logger::debug( "Could not parse Api response: {0}", e.what() );
return -1; return -1;
} }
@ -206,7 +204,7 @@ CharList Sapphire::Network::RestConnector::getCharList( char* sId )
return list; return list;
std::string content = std::string( std::istreambuf_iterator< char >( r->content ), {} ); std::string content = std::string( std::istreambuf_iterator< char >( r->content ), {} );
g_log.debug( content ); Logger::debug( content );
if( r->status_code.find( "200" ) != std::string::npos ) if( r->status_code.find( "200" ) != std::string::npos )
{ {
auto json = nlohmann::json(); auto json = nlohmann::json();
@ -217,18 +215,18 @@ CharList Sapphire::Network::RestConnector::getCharList( char* sId )
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
g_log.debug( "Could not parse REST response: " + std::string( e.what() ) ); Logger::debug( "Could not parse Api response: {0}", e.what() );
return list; return list;
} }
if( json["result"].get< std::string >().find( "invalid" ) == std::string::npos ) if( json["result"].get< std::string >().find( "invalid" ) == std::string::npos )
{ {
g_log.debug( json["result"] ); Logger::debug( json["result"] );
for( auto& child : json["charArray"] ) for( auto& child : json["charArray"] )
{ {
g_log.info( child["contentId"] ); Logger::info( child["contentId"] );
//std::string, uint32_t, uint64_t, std::string //std::string, uint32_t, uint64_t, std::string
list.push_back( { child["name"], list.push_back( { child["name"],
std::stoi( std::string( child["charId"] ) ), std::stoi( std::string( child["charId"] ) ),
@ -271,7 +269,7 @@ bool Sapphire::Network::RestConnector::deleteCharacter( char* sId, std::string n
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
g_log.debug( "Could not parse REST response: " + std::string( e.what() ) ); Logger::debug( "Could not parse Api response: {0}", e.what() );
return false; return false;
} }
@ -297,7 +295,7 @@ int Sapphire::Network::RestConnector::createCharacter( char* sId, std::string na
return -1; return -1;
std::string content = std::string( std::istreambuf_iterator< char >( r->content ), {} ); std::string content = std::string( std::istreambuf_iterator< char >( r->content ), {} );
g_log.debug( content ); Logger::debug( content );
if( r->status_code.find( "200" ) != std::string::npos ) if( r->status_code.find( "200" ) != std::string::npos )
{ {
auto json = nlohmann::json(); auto json = nlohmann::json();
@ -308,7 +306,7 @@ int Sapphire::Network::RestConnector::createCharacter( char* sId, std::string na
} }
catch( std::exception& e ) catch( std::exception& e )
{ {
g_log.debug( "Could not parse REST response: " + std::string( e.what() ) ); Logger::debug( "Could not parse Api response: {0}", e.what() );
return -1; return -1;
} }

View file

@ -41,9 +41,9 @@ namespace Sapphire
return g_restConnector.getSession( sessionId ); return g_restConnector.getSession( sessionId );
} }
ConfigMgrPtr ServerLobby::getConfig() const Sapphire::Common::Config::LobbyConfig& ServerLobby::getConfig()
{ {
return m_pConfig; return m_config;
} }
void ServerLobby::run( int32_t argc, char* argv[] ) void ServerLobby::run( int32_t argc, char* argv[] )
@ -67,9 +67,7 @@ namespace Sapphire
Network::HivePtr hive( new Network::Hive() ); Network::HivePtr hive( new Network::Hive() );
Network::addServerToHive< Network::GameConnection >( m_ip, m_port, hive, pFw ); Network::addServerToHive< Network::GameConnection >( m_ip, m_port, hive, pFw );
Logger::info( Logger::info( "Lobby server running on {0}:{1}", m_ip, m_port );
"Lobby server running on " + m_pConfig->getValue< std::string >( "LobbyNetwork", "ListenIp", "0.0.0.0" ) + ":" +
m_pConfig->getValue< std::string >( "LobbyNetwork", "ListenPort", "80" ) );
std::vector< std::thread > threadGroup; std::vector< std::thread > threadGroup;
@ -85,12 +83,33 @@ namespace Sapphire
{ {
Logger::info( "Loading config {0}", m_configPath ); Logger::info( "Loading config {0}", m_configPath );
bool failedLoad = false;
if( !m_pConfig->loadGlobalConfig( m_config.global, "global.ini" ) )
{
Logger::fatal( "Error loading config global.ini, copying default..." );
failedLoad = true;
}
if( !m_pConfig->loadConfig( m_configPath ) ) if( !m_pConfig->loadConfig( m_configPath ) )
{ {
Logger::fatal( "Error loading config {0}", m_configPath ); Logger::fatal( "Error loading config {0}", m_configPath );
Logger::fatal( "If this is the first time starting the server, we've copied the default one for your editing pleasure." ); failedLoad = true;
}
if( failedLoad )
{
Logger::fatal( "If this is the first time starting the server, "
"we've copied the default configs for your editing pleasure." );
return false; return false;
} }
// load lobby config
m_config.allowNoSessionConnect = m_pConfig->getValue< bool >( "Lobby", "AllowNoSessionConnect", false );
m_config.worldName = m_pConfig->getValue< std::string >( "Lobby", "WorldName", "Sapphire" );
m_config.network.listenIp = m_pConfig->getValue< std::string >( "Network", "ListenIp", "0.0.0.0" );
m_config.network.listenPort = m_pConfig->getValue< uint16_t >( "Network", "ListenPort", 54994 );
std::vector< std::string > args( argv + 1, argv + argc ); std::vector< std::string > args( argv + 1, argv + argc );
for( size_t i = 0; i + 1 < args.size(); i += 2 ) for( size_t i = 0; i + 1 < args.size(); i += 2 )
{ {
@ -108,19 +127,19 @@ namespace Sapphire
if( arg == "ip" ) if( arg == "ip" )
{ {
// todo: ip addr in config // todo: ip addr in config
m_pConfig->setValue< std::string >( "LobbyNetwork.ListenIp", val ); m_config.network.listenIp = val;
} }
else if( arg == "p" || arg == "port" ) else if( arg == "p" || arg == "port" )
{ {
m_pConfig->setValue< std::string >( "LobbyNetwork.LobbyPort", val ); m_config.network.listenPort = std::stoi( val );
} }
else if( arg == "worldip" || arg == "worldip" ) else if( arg == "worldip" || arg == "worldip" )
{ {
m_pConfig->setValue< std::string >( "GlobalNetwork.ZoneHost", val ); m_config.global.network.zoneHost = val;
} }
else if( arg == "worldport" ) else if( arg == "worldport" )
{ {
m_pConfig->setValue< std::string >( "GlobalNetwork.ZonePort", val ); m_config.global.network.zonePort = std::stoi( val );
} }
} }
catch( ... ) catch( ... )
@ -130,12 +149,13 @@ namespace Sapphire
} }
} }
m_port = m_pConfig->getValue< uint16_t >( "LobbyNetwork", "ListenPort", 54994 ); m_port = m_config.network.listenPort;
m_ip = m_pConfig->getValue< std::string >( "LobbyNetwork", "ListenIp", "0.0.0.0" ); m_ip = m_config.network.listenIp;
g_restConnector.restHost = m_pConfig->getValue< std::string >( "GlobalNetwork", "RestHost" ) + ":" +
m_pConfig->getValue< std::string >( "GlobalNetwork", "RestPort" ); g_restConnector.restHost = m_config.global.network.restHost + ":" +
g_restConnector.serverSecret = m_pConfig->getValue< std::string >( "GlobalParameters", "ServerSecret" ); std::to_string( m_config.global.network.restPort );
g_restConnector.serverSecret = m_config.global.general.serverSecret;
return true; return true;
} }

View file

@ -4,6 +4,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <Config/ConfigDef.h>
#include "Forwards.h" #include "Forwards.h"
const std::string LOBBY_VERSION = "0.0.5"; const std::string LOBBY_VERSION = "0.0.5";
@ -44,12 +45,14 @@ namespace Sapphire
m_sessionMap[ std::string( sessionId ) ] = pSession; m_sessionMap[ std::string( sessionId ) ] = pSession;
} }
std::shared_ptr< ConfigMgr > getConfig() const; Sapphire::Common::Config::LobbyConfig& getConfig();
LobbySessionPtr getSession( char* sessionId ); LobbySessionPtr getSession( char* sessionId );
uint32_t m_numConnections; uint32_t m_numConnections;
Sapphire::Common::Config::LobbyConfig m_config;
}; };
} }

View file

@ -1,6 +1,6 @@
#include "ServerLobby.h" #include "ServerLobby.h"
Sapphire::ServerLobby g_serverLobby( "config.ini" ); Sapphire::ServerLobby g_serverLobby( "lobby.ini" );
int main( int32_t argc, char* argv[] ) int main( int32_t argc, char* argv[] )
{ {

View file

@ -56,8 +56,8 @@ private:
auto item = player.addItem( itemId, 1, false, true ); auto item = player.addItem( itemId, 1, false, true );
if( item ) //if( item )
player.equipItem( Common::GearSetSlot::Ring2, item, true ); // player.equipItem( Common::GearSetSlot::Ring2, item, true );
player.setOpeningSequence( 1 ); player.setOpeningSequence( 1 );
Scene00001( player ); Scene00001( player );
@ -65,12 +65,13 @@ private:
player.playScene( getId(), 0, NO_DEFAULT_CAMERA | INVIS_ENPC | player.playScene( getId(), 0, NO_DEFAULT_CAMERA | INVIS_ENPC |
CONDITION_CUTSCENE | HIDE_UI | CONDITION_CUTSCENE | HIDE_UI |
HIDE_HOTBAR | SILENT_ENTER_TERRI_ENV, 0, 1, callback ); HIDE_HOTBAR | SILENT_ENTER_TERRI_ENV | SILENT_ENTER_TERRI_BGM | SILENT_ENTER_TERRI_SE |
DISABLE_SKIP | DISABLE_STEALTH, 0, 1, callback );
} }
void Scene00001( Entity::Player& player ) void Scene00001( Entity::Player& player )
{ {
player.playScene( getId(), 1, NO_DEFAULT_CAMERA | HIDE_HOTBAR, 1, 0x32 ); player.playScene( getId(), 1, NO_DEFAULT_CAMERA | HIDE_HOTBAR, 0, 0 );
} }
void Scene00020( Entity::Player& player ) void Scene00020( Entity::Player& player )

View file

@ -81,7 +81,8 @@ private:
player.playScene( getId(), 0, NO_DEFAULT_CAMERA | INVIS_ENPC | player.playScene( getId(), 0, NO_DEFAULT_CAMERA | INVIS_ENPC |
CONDITION_CUTSCENE | HIDE_UI | CONDITION_CUTSCENE | HIDE_UI |
HIDE_HOTBAR | SILENT_ENTER_TERRI_ENV, 0, 1, callback ); HIDE_HOTBAR | SILENT_ENTER_TERRI_ENV | SILENT_ENTER_TERRI_BGM | SILENT_ENTER_TERRI_SE |
DISABLE_SKIP | DISABLE_STEALTH, 0, 1, callback );
} }
void Scene00001( Entity::Player& player ) void Scene00001( Entity::Player& player )

View file

@ -66,7 +66,8 @@ private:
player.playScene( getId(), 0, NO_DEFAULT_CAMERA | INVIS_ENPC | player.playScene( getId(), 0, NO_DEFAULT_CAMERA | INVIS_ENPC |
CONDITION_CUTSCENE | HIDE_UI | CONDITION_CUTSCENE | HIDE_UI |
HIDE_HOTBAR | SILENT_ENTER_TERRI_ENV, 0, 1, callback ); HIDE_HOTBAR | SILENT_ENTER_TERRI_ENV | SILENT_ENTER_TERRI_BGM | SILENT_ENTER_TERRI_SE |
DISABLE_SKIP | DISABLE_STEALTH, 0, 1, callback );
} }
void Scene00001( Entity::Player& player ) void Scene00001( Entity::Player& player )

View file

@ -21,8 +21,7 @@ Sapphire::Data::ExdDataGenerated g_exdData;
using namespace Sapphire; using namespace Sapphire;
//const std::string datLocation( "/opt/sapphire_3_15_0/bin/sqpack" ); //const std::string datLocation( "/opt/sapphire_3_15_0/bin/sqpack" );
const std::string datLocation( const std::string datLocation( "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack" );
"C:\\Data\\Games\\Final Fantasy XIV\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv" );
std::string generateEnum( const std::string& exd, int8_t nameIndex, const std::string& type, bool useLang = true ) std::string generateEnum( const std::string& exd, int8_t nameIndex, const std::string& type, bool useLang = true )
{ {

View file

@ -45,7 +45,7 @@ std::vector< std::string > cppKeyWords
}; };
//std::string datLocation( "/home/mordred/sqpack" ); //std::string datLocation( "/home/mordred/sqpack" );
std::string datLocation( "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack" ); std::string datLocation( "/mnt/c/Program Files (x86)/Steam/steamapps/common/FINAL FANTASY XIV Online/game/sqpack" );
std::map< uint8_t, std::string > g_typeMap; std::map< uint8_t, std::string > g_typeMap;

View file

@ -21,7 +21,7 @@ Sapphire::Data::ExdDataGenerated g_exdData;
using namespace Sapphire; using namespace Sapphire;
//const std::string datLocation( "/opt/sapphire_3_15_0/bin/sqpack" ); //const std::string datLocation( "/opt/sapphire_3_15_0/bin/sqpack" );
const std::string datLocation( "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack" ); const std::string datLocation( "/mnt/c/Program Files (x86)/Steam/steamapps/common/FINAL FANTASY XIV Online/game/sqpack" );
int main() int main()
@ -36,22 +36,14 @@ int main()
return 0; return 0;
} }
auto gld = g_exdData.get< Sapphire::Data::ClassJob >( 1 );
//Logger::info( "getting id list " ); if( gld )
//auto idList = g_exdData.getGilShopIdList();
//Logger::info( "getting id list done" );
//for( auto id : idList )
{ {
auto teri1 = g_exdData.get< Sapphire::Data::GilShopItem >( 262440, 0 ); Logger::info( "got {0}", gld->name );
Logger::info( "0 -> {0}", teri1->item );
auto teri2 = g_exdData.get< Sapphire::Data::GilShopItem >( 262440, 1 );
Logger::info( "1 -> {0} ", teri2->item );
auto teri3 = g_exdData.get< Sapphire::Data::GilShopItem >( 262440, 2 );
Logger::info( "2 -> {0}", teri3->item );
} }
else
Logger::warn( "failed to get classjob {}", 1 );
return 0; return 0;
} }

View file

@ -40,10 +40,11 @@ Sapphire::Entity::BNpc::BNpc( FrameworkPtr pFw ) :
{ {
} }
Sapphire::Entity::BNpc::BNpc( BNpcTemplatePtr pTemplate, float posX, float posY, float posZ, Sapphire::Entity::BNpc::BNpc( uint32_t id, BNpcTemplatePtr pTemplate, float posX, float posY, float posZ, float rot,
uint8_t level, FrameworkPtr pFw ) : uint8_t level, uint32_t maxHp, FrameworkPtr pFw ) :
Npc( ObjKind::BattleNpc, pFw ) Npc( ObjKind::BattleNpc, pFw )
{ {
m_id = id;
m_modelChara = pTemplate->getModelChara(); m_modelChara = pTemplate->getModelChara();
m_displayFlags = pTemplate->getDisplayFlags(); m_displayFlags = pTemplate->getDisplayFlags();
m_pose = pTemplate->getPose(); m_pose = pTemplate->getPose();
@ -56,14 +57,15 @@ Sapphire::Entity::BNpc::BNpc( BNpcTemplatePtr pTemplate, float posX, float posY,
m_pos.x = posX; m_pos.x = posX;
m_pos.y = posY; m_pos.y = posY;
m_pos.z = posZ; m_pos.z = posZ;
m_rot = rot;
m_level = level; m_level = level;
m_maxHp = 200; m_maxHp = maxHp;
m_maxMp = 200; m_maxMp = 200;
m_hp = 200; m_hp = maxHp;
m_mp = 200; m_mp = 200;
m_baseStats.max_hp = 200; m_baseStats.max_hp = maxHp;
m_baseStats.max_mp = 200; m_baseStats.max_mp = 200;
memcpy( m_customize, pTemplate->getCustomize(), sizeof( m_customize ) ); memcpy( m_customize, pTemplate->getCustomize(), sizeof( m_customize ) );

View file

@ -23,7 +23,8 @@ namespace Sapphire::Entity
public: public:
BNpc( FrameworkPtr pFw ); BNpc( FrameworkPtr pFw );
BNpc( BNpcTemplatePtr pTemplate, float posX, float posY, float posZ, uint8_t level, FrameworkPtr pFw ); BNpc( uint32_t id, BNpcTemplatePtr pTemplate, float posX, float posY, float posZ, float rot,
uint8_t level, uint32_t maxHp, FrameworkPtr pFw );
virtual ~BNpc() override; virtual ~BNpc() override;

View file

@ -11,11 +11,12 @@
#include "Session.h" #include "Session.h"
#include "Player.h" #include "Player.h"
#include "Manager/HousingMgr.h"
#include "Manager/TerritoryMgr.h" #include "Manager/TerritoryMgr.h"
#include "Territory/Zone.h" #include "Territory/Zone.h"
#include "Territory/ZonePosition.h" #include "Territory/ZonePosition.h"
#include "Territory/InstanceContent.h"
#include "Manager/HousingMgr.h"
#include "Territory/Land.h" #include "Territory/Land.h"
#include "Network/GameConnection.h" #include "Network/GameConnection.h"
@ -491,6 +492,9 @@ bool Sapphire::Entity::Player::exitInstance()
{ {
auto pTeriMgr = m_pFw->get< TerritoryMgr >(); auto pTeriMgr = m_pFw->get< TerritoryMgr >();
auto pZone = getCurrentZone();
auto pInstance = pZone->getAsInstanceContent();
// check if housing zone // check if housing zone
if( pTeriMgr->isHousingTerritory( m_prevTerritoryTypeId ) ) if( pTeriMgr->isHousingTerritory( m_prevTerritoryTypeId ) )
{ {
@ -510,6 +514,8 @@ bool Sapphire::Entity::Player::exitInstance()
sendZonePackets(); sendZonePackets();
//m_queuedZoneing = std::make_shared< QueuedZoning >( m_territoryTypeId, m_pos, Util::getTimeMs(), m_rot );
return true; return true;
} }
@ -1700,13 +1706,12 @@ Sapphire::Entity::Player::sendZoneInPackets( uint32_t param1, uint32_t param2 =
auto SetStatusPacket = makeActorControl142( getId(), SetStatus, static_cast< uint8_t >( Common::ActorStatus::Idle ) ); auto SetStatusPacket = makeActorControl142( getId(), SetStatus, static_cast< uint8_t >( Common::ActorStatus::Idle ) );
if( !getGmInvis() ) if( !getGmInvis() )
sendToInRangeSet( zoneInPacket, true ); sendToInRangeSet( zoneInPacket );
if( shouldSetStatus ) if( shouldSetStatus )
sendToInRangeSet( SetStatusPacket ); sendToInRangeSet( SetStatusPacket, true );
else
queuePacket( zoneInPacket ); queuePacket( zoneInPacket );
if( shouldSetStatus )
queuePacket( SetStatusPacket );
setZoningType( Common::ZoneingType::None ); setZoningType( Common::ZoneingType::None );
unsetStateFlag( PlayerStateFlag::BetweenAreas ); unsetStateFlag( PlayerStateFlag::BetweenAreas );

View file

@ -534,7 +534,7 @@ namespace Sapphire::Entity
void teleportQuery( uint16_t aetheryteId, FrameworkPtr pFw ); void teleportQuery( uint16_t aetheryteId, FrameworkPtr pFw );
/*! prepares zoning / fades out the screen */ /*! prepares zoning / fades out the screen */
void prepareZoning( uint16_t targetZone, bool fadeOut, uint8_t fadoutTime = 0, uint16_t animation = 0 ); void prepareZoning( uint16_t targetZone, bool fadeOut, uint8_t fadeOutTime = 0, uint16_t animation = 0 );
/*! get player's title list (available titles) */ /*! get player's title list (available titles) */
uint8_t* getTitleList(); uint8_t* getTitleList();
@ -1013,8 +1013,8 @@ namespace Sapphire::Entity
uint8_t m_discovery[421]; uint8_t m_discovery[421];
uint32_t m_playTime; uint32_t m_playTime;
uint16_t m_classArray[25]; uint16_t m_classArray[26];
uint32_t m_expArray[25]; uint32_t m_expArray[26];
uint8_t m_aetheryte[17]; uint8_t m_aetheryte[17];
uint8_t m_unlocks[64]; uint8_t m_unlocks[64];
uint8_t m_orchestrion[40]; uint8_t m_orchestrion[40];

View file

@ -1,7 +1,6 @@
#include <Common.h> #include <Common.h>
#include <Logging/Logger.h> #include <Logging/Logger.h>
#include <Network/PacketContainer.h> #include <Network/PacketContainer.h>
#include <Config/ConfigMgr.h>
#include "Network/GameConnection.h" #include "Network/GameConnection.h"
#include "Network/PacketWrappers/ActorControlPacket142.h" #include "Network/PacketWrappers/ActorControlPacket142.h"
@ -326,8 +325,8 @@ void Sapphire::Entity::Player::eventItemActionStart( uint32_t eventId,
void Sapphire::Entity::Player::onLogin() void Sapphire::Entity::Player::onLogin()
{ {
auto pConfig = m_pFw->get< ConfigMgr >(); auto pServerMgr = m_pFw->get< Sapphire::World::ServerMgr >();
auto motd = pConfig->getValue< std::string >( "General", "MotD", "" ); auto motd = pServerMgr->getConfig().motd;
std::istringstream ss( motd ); std::istringstream ss( motd );
std::string msg; std::string msg;

View file

@ -20,7 +20,7 @@ uint32_t Sapphire::Entity::SpawnGroup::getTemplateId() const
return m_bNpcTemplateId; return m_bNpcTemplateId;
} }
uint32_t Sapphire::Entity::SpawnGroup::getLevelId() const uint32_t Sapphire::Entity::SpawnGroup::getLevel() const
{ {
return m_level; return m_level;
} }

View file

@ -24,7 +24,7 @@ namespace Sapphire::Entity
uint32_t getId() const; uint32_t getId() const;
uint32_t getTemplateId() const; uint32_t getTemplateId() const;
uint32_t getLevelId() const; uint32_t getLevel() const;
uint32_t getMaxHp() const; uint32_t getMaxHp() const;
SpawnPointList& getSpawnPointList(); SpawnPointList& getSpawnPointList();

View file

@ -17,6 +17,16 @@ Sapphire::Entity::SpawnPoint::SpawnPoint( float x, float y, float z, float rot,
{ {
} }
uint32_t Sapphire::Entity::SpawnPoint::getTimeOfDeath() const
{
return m_timeOfDeath;
}
void Sapphire::Entity::SpawnPoint::setTimeOfDeath( uint32_t timeOfDeath )
{
m_timeOfDeath = timeOfDeath;
}
float Sapphire::Entity::SpawnPoint::getPosX() const float Sapphire::Entity::SpawnPoint::getPosX() const
{ {
return m_posX; return m_posX;

View file

@ -33,6 +33,9 @@ namespace Sapphire::Entity
BNpcPtr getLinkedBNpc(); BNpcPtr getLinkedBNpc();
void setLinkedBNpc( BNpcPtr pBnpc ); void setLinkedBNpc( BNpcPtr pBnpc );
uint32_t getTimeOfDeath() const;
void setTimeOfDeath( uint32_t m_timeOfDeath );
}; };
} }

View file

@ -8,22 +8,22 @@ Sapphire::Inventory::HousingItem::HousingItem( uint64_t uId, uint32_t catalogId,
m_reservedFlag = 1092616192; // wat? m_reservedFlag = 1092616192; // wat?
} }
uint16_t Sapphire::Inventory::HousingItem::getRot() const float Sapphire::Inventory::HousingItem::getRot() const
{ {
return m_rotation; return m_rotation;
} }
void Sapphire::Inventory::HousingItem::setRot( uint16_t rot ) void Sapphire::Inventory::HousingItem::setRot( float rot )
{ {
m_rotation = rot; m_rotation = rot;
} }
Sapphire::Common::FFXIVARR_POSITION3_U16 Sapphire::Inventory::HousingItem::getPos() const Sapphire::Common::FFXIVARR_POSITION3 Sapphire::Inventory::HousingItem::getPos() const
{ {
return m_position; return m_position;
} }
void Sapphire::Inventory::HousingItem::setPos( Sapphire::Common::FFXIVARR_POSITION3_U16 pos ) void Sapphire::Inventory::HousingItem::setPos( Sapphire::Common::FFXIVARR_POSITION3 pos )
{ {
m_position = pos; m_position = pos;
} }

View file

@ -11,15 +11,15 @@ namespace Sapphire::Inventory
HousingItem( uint64_t uId, uint32_t catalogId, FrameworkPtr pFw ); HousingItem( uint64_t uId, uint32_t catalogId, FrameworkPtr pFw );
virtual ~HousingItem() = default; virtual ~HousingItem() = default;
void setRot( uint16_t rot ); void setRot( float rot );
uint16_t getRot() const; float getRot() const;
void setPos( Common::FFXIVARR_POSITION3_U16 pos ); void setPos( Common::FFXIVARR_POSITION3 pos );
Common::FFXIVARR_POSITION3_U16 getPos() const; Common::FFXIVARR_POSITION3 getPos() const;
private: private:
Common::FFXIVARR_POSITION3_U16 m_position; Common::FFXIVARR_POSITION3 m_position;
uint16_t m_rotation; float m_rotation;
}; };
} }

View file

@ -9,7 +9,7 @@
#include "Forwards.h" #include "Forwards.h"
#include "ItemContainer.h" #include "ItemContainer.h"
Sapphire::ItemContainer::ItemContainer( uint16_t storageId, uint16_t maxSize, const std::string& tableName, Sapphire::ItemContainer::ItemContainer( uint16_t storageId, uint8_t maxSize, const std::string& tableName,
bool isMultiStorage, FrameworkPtr pFw, bool isPersistentStorage ) : bool isMultiStorage, FrameworkPtr pFw, bool isPersistentStorage ) :
m_id( storageId ), m_id( storageId ),
m_size( maxSize ), m_size( maxSize ),
@ -31,15 +31,15 @@ uint16_t Sapphire::ItemContainer::getId() const
return m_id; return m_id;
} }
uint16_t Sapphire::ItemContainer::getEntryCount() const uint8_t Sapphire::ItemContainer::getEntryCount() const
{ {
return static_cast< uint16_t >( m_itemMap.size() ); return static_cast< uint8_t >( m_itemMap.size() );
} }
void Sapphire::ItemContainer::removeItem( uint16_t slotId, bool removeFromDb ) void Sapphire::ItemContainer::removeItem( uint8_t slotId, bool removeFromDb )
{ {
auto pDb = m_pFw->get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); auto pDb = m_pFw->get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
ItemMap::iterator it = m_itemMap.find( slotId ); auto it = m_itemMap.find( slotId );
if( it != m_itemMap.end() ) if( it != m_itemMap.end() )
{ {
@ -66,7 +66,7 @@ const Sapphire::ItemMap& Sapphire::ItemContainer::getItemMap() const
return m_itemMap; return m_itemMap;
} }
int16_t Sapphire::ItemContainer::getFreeSlot() int8_t Sapphire::ItemContainer::getFreeSlot()
{ {
for( uint16_t slotId = 0; slotId < m_size; slotId++ ) for( uint16_t slotId = 0; slotId < m_size; slotId++ )
{ {
@ -78,7 +78,7 @@ int16_t Sapphire::ItemContainer::getFreeSlot()
return -1; return -1;
} }
Sapphire::ItemPtr Sapphire::ItemContainer::getItem( uint16_t slotId ) Sapphire::ItemPtr Sapphire::ItemContainer::getItem( uint8_t slotId )
{ {
if( ( slotId > m_size ) ) if( ( slotId > m_size ) )
@ -90,7 +90,7 @@ Sapphire::ItemPtr Sapphire::ItemContainer::getItem( uint16_t slotId )
return m_itemMap[ slotId ]; return m_itemMap[ slotId ];
} }
void Sapphire::ItemContainer::setItem( uint16_t slotId, ItemPtr pItem ) void Sapphire::ItemContainer::setItem( uint8_t slotId, ItemPtr pItem )
{ {
if( slotId > m_size ) if( slotId > m_size )
return; return;
@ -98,7 +98,7 @@ void Sapphire::ItemContainer::setItem( uint16_t slotId, ItemPtr pItem )
m_itemMap[ slotId ] = pItem; m_itemMap[ slotId ] = pItem;
} }
uint16_t Sapphire::ItemContainer::getMaxSize() const uint8_t Sapphire::ItemContainer::getMaxSize() const
{ {
return m_size; return m_size;
} }

View file

@ -8,34 +8,34 @@
namespace Sapphire namespace Sapphire
{ {
using ItemMap = std::map< uint16_t, ItemPtr >; using ItemMap = std::map< uint8_t, ItemPtr >;
class ItemContainer class ItemContainer
{ {
public: public:
ItemContainer( uint16_t storageId, uint16_t maxSize, const std::string& tableName, bool isMultiStorage, ItemContainer( uint16_t storageId, uint8_t maxSize, const std::string& tableName, bool isMultiStorage,
FrameworkPtr pFw, bool isPersistentStorage = true ); FrameworkPtr pFw, bool isPersistentStorage = true );
~ItemContainer(); ~ItemContainer();
uint16_t getId() const; uint16_t getId() const;
uint16_t getEntryCount() const; uint8_t getEntryCount() const;
void removeItem( uint16_t slotId, bool removeFromDb = true ); void removeItem( uint8_t slotId, bool removeFromDb = true );
ItemMap& getItemMap(); ItemMap& getItemMap();
const ItemMap& getItemMap() const; const ItemMap& getItemMap() const;
ItemPtr getItem( uint16_t slotId ); ItemPtr getItem( uint8_t slotId );
void setItem( uint16_t slotId, ItemPtr item ); void setItem( uint8_t slotId, ItemPtr item );
int16_t getFreeSlot(); int8_t getFreeSlot();
uint16_t getMaxSize() const; uint8_t getMaxSize() const;
std::string getTableName() const; std::string getTableName() const;
@ -45,7 +45,7 @@ namespace Sapphire
private: private:
uint16_t m_id; uint16_t m_id;
uint16_t m_size; uint8_t m_size;
std::string m_tableName; std::string m_tableName;
bool m_bMultiStorage; bool m_bMultiStorage;
FrameworkPtr m_pFw; FrameworkPtr m_pFw;

View file

@ -432,13 +432,16 @@ void Sapphire::World::Manager::DebugCommandMgr::add( char* data, Entity::Player&
player.sendNotice( "Template {0} not found in cache!", params ); player.sendNotice( "Template {0} not found in cache!", params );
return; return;
} }
auto pBNpc = std::make_shared< Entity::BNpc >( bNpcTemplate, auto playerZone = player.getCurrentZone();
auto pBNpc = std::make_shared< Entity::BNpc >( playerZone->getNextActorId(),
bNpcTemplate,
player.getPos().x, player.getPos().x,
player.getPos().y, player.getPos().y,
player.getPos().z, player.getPos().z,
1, framework() ); player.getRot(),
1, 1000, framework() );
auto playerZone = player.getCurrentZone();
//pBNpc->setCurrentZone( playerZone ); //pBNpc->setCurrentZone( playerZone );
//pBNpc->setPos( player.getPos().x, player.getPos().y, player.getPos().z ); //pBNpc->setPos( player.getPos().x, player.getPos().y, player.getPos().z );
@ -791,14 +794,14 @@ Sapphire::World::Manager::DebugCommandMgr::instance( char* data, Entity::Player&
if( subCommand == "create" || subCommand == "cr" ) if( subCommand == "create" || subCommand == "cr" )
{ {
uint32_t instanceContentId; uint32_t contentFinderConditionId;
sscanf( params.c_str(), "%d", &instanceContentId ); sscanf( params.c_str(), "%d", &contentFinderConditionId );
auto instance = pTeriMgr->createInstanceContent( instanceContentId ); auto instance = pTeriMgr->createInstanceContent( contentFinderConditionId );
if( instance ) if( instance )
player.sendDebug( "Created instance with id#{0} -> {1}", instance->getGuId(), instance->getName() ); player.sendDebug( "Created instance with id#{0} -> {1}", instance->getGuId(), instance->getName() );
else else
player.sendDebug( "Failed to create instance with id#{0}", instanceContentId ); player.sendDebug( "Failed to create instance with id#{0}", contentFinderConditionId );
} }
else if( subCommand == "bind" ) else if( subCommand == "bind" )
{ {

View file

@ -139,19 +139,25 @@ bool Sapphire::World::Manager::HousingMgr::loadEstateInventories()
if( isPlacedItemsInventory( static_cast< Common::InventoryType >( containerId ) ) ) if( isPlacedItemsInventory( static_cast< Common::InventoryType >( containerId ) ) )
{ {
item->setPos( { item->setPos( {
res->getUInt16( "PosX" ), res->getFloat( "PosX" ),
res->getUInt16( "PosY" ), res->getFloat( "PosY" ),
res->getUInt16( "PosZ" ) res->getFloat( "PosZ" )
} ); } );
item->setRot( res->getUInt16( "Rotation" ) ); item->setRot( res->getFloat( "Rotation" ) );
} }
ContainerIdToContainerMap& estateInv = m_estateInventories[ ident ]; ContainerIdToContainerMap& estateInv = m_estateInventories[ ident ];
// check if containerId exists, it always should - if it doesn't, something went wrong // check if containerId exists, it always should - if it doesn't, something went wrong
auto container = estateInv.find( containerId ); auto container = estateInv.find( containerId );
assert( container != estateInv.end() ); if( container == estateInv.end() )
{
Logger::warn( "Skipping item#{0} for ident#{1} - container#{2} doesn't exist for estate.",
itemId, ident, containerId );
continue;
}
container->second->setItem( slot, item ); container->second->setItem( slot, item );
@ -854,12 +860,12 @@ void Sapphire::World::Manager::HousingMgr::sendEstateInventory( Entity::Player&
return; return;
auto& containers = getEstateInventory( targetLand->getLandIdent() ); auto& containers = getEstateInventory( targetLand->getLandIdent() );
auto needle = containers.find( inventoryType ); auto it = containers.find( inventoryType );
if( needle == containers.end() ) if( it == containers.end() )
return; return;
auto invMgr = framework()->get< Manager::InventoryMgr >(); auto invMgr = framework()->get< Manager::InventoryMgr >();
invMgr->sendInventoryContainer( player, needle->second ); invMgr->sendInventoryContainer( player, it->second );
} }
const Sapphire::World::Manager::HousingMgr::LandSetLandCacheMap& const Sapphire::World::Manager::HousingMgr::LandSetLandCacheMap&
@ -1007,13 +1013,8 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity
return; return;
// set params // set params
item->setPos( { item->setPos( pos );
Util::floatToUInt16( pos.x ), item->setRot( rotation );
Util::floatToUInt16( pos.y ),
Util::floatToUInt16( pos.z )
} );
item->setRot( Util::floatToUInt16Rot( rotation ) );
} }
else else
{ {
@ -1084,11 +1085,11 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceItemInStore( Sapphire::Entity
{ {
for( auto houseContainer : m_internalStoreroomContainers ) for( auto houseContainer : m_internalStoreroomContainers )
{ {
auto needle = containers.find( houseContainer ); auto it = containers.find( houseContainer );
if( needle == containers.end() ) if( it == containers.end() )
continue; continue;
auto container = needle->second; auto container = it->second;
auto freeSlot = container->getFreeSlot(); auto freeSlot = container->getFreeSlot();
if( freeSlot == -1 ) if( freeSlot == -1 )
{ {
@ -1156,11 +1157,11 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl
uint8_t containerIdx = 0; uint8_t containerIdx = 0;
for( auto containerId : m_internalPlacedItemContainers ) for( auto containerId : m_internalPlacedItemContainers )
{ {
auto needle = containers.find( containerId ); auto it = containers.find( containerId );
if( needle == containers.end() ) if( it == containers.end() )
continue; continue;
auto container = needle->second; auto container = it->second;
auto freeSlot = container->getFreeSlot(); auto freeSlot = container->getFreeSlot();
if( freeSlot == -1 ) if( freeSlot == -1 )
{ {
@ -1192,7 +1193,7 @@ Sapphire::Common::HousingObject Sapphire::World::Manager::HousingMgr::getYardObj
Sapphire::Common::HousingObject obj {}; Sapphire::Common::HousingObject obj {};
obj.pos = item->getPos(); obj.pos = item->getPos();
obj.itemRotation = item->getRot(); obj.rotation = item->getRot();
obj.itemId = item->getAdditionalData(); obj.itemId = item->getAdditionalData();
return obj; return obj;
@ -1271,23 +1272,18 @@ bool Sapphire::World::Manager::HousingMgr::moveInternalItem( Entity::Player& pla
auto& containers = getEstateInventory( ident ); auto& containers = getEstateInventory( ident );
auto needle = containers.find( containerId ); auto it = containers.find( containerId );
if( needle == containers.end() ) if( it == containers.end() )
return false; return false;
auto container = needle->second; auto container = it->second;
auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( container->getItem( slotIdx ) ); auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( container->getItem( slotIdx ) );
if( !item ) if( !item )
return false; return false;
item->setPos( { item->setPos( pos );
Util::floatToUInt16( pos.x ), item->setRot( rot );
Util::floatToUInt16( pos.y ),
Util::floatToUInt16( pos.z )
} );
item->setRot( Util::floatToUInt16Rot( rot ) );
// save // save
auto invMgr = framework()->get< InventoryMgr >(); auto invMgr = framework()->get< InventoryMgr >();
@ -1314,23 +1310,18 @@ bool Sapphire::World::Manager::HousingMgr::moveExternalItem( Entity::Player& pla
return false; return false;
auto& containers = getEstateInventory( ident ); auto& containers = getEstateInventory( ident );
auto needle = containers.find( InventoryType::HousingExteriorPlacedItems ); auto it = containers.find( InventoryType::HousingExteriorPlacedItems );
if( needle == containers.end() ) if( it == containers.end() )
return false; return false;
auto container = needle->second; auto container = it->second;
auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( container->getItem( slot ) ); auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( container->getItem( slot ) );
if( !item ) if( !item )
return false; return false;
item->setPos( { item->setPos( pos );
Util::floatToUInt16( pos.x ), item->setRot( rot );
Util::floatToUInt16( pos.y ),
Util::floatToUInt16( pos.z )
} );
item->setRot( Util::floatToUInt16Rot( rot ) );
auto invMgr = framework()->get< InventoryMgr >(); auto invMgr = framework()->get< InventoryMgr >();
invMgr->updateHousingItemPosition( item ); invMgr->updateHousingItemPosition( item );
@ -1403,11 +1394,11 @@ bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& p
// eg, remove a permit and reuse it elsewhere // eg, remove a permit and reuse it elsewhere
// I'm not going to bother fixing it for now, but worth noting for future reference // I'm not going to bother fixing it for now, but worth noting for future reference
auto needle = containers.find( containerId ); auto it = containers.find( containerId );
if( needle == containers.end() ) if( it == containers.end() )
return false; return false;
auto container = needle->second; auto container = it->second;
auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( container->getItem( slotId ) ); auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( container->getItem( slotId ) );
if( !item ) if( !item )
@ -1470,11 +1461,11 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p
{ {
auto& containers = getEstateInventory( land.getLandIdent() ); auto& containers = getEstateInventory( land.getLandIdent() );
auto needle = containers.find( containerType ); auto it = containers.find( containerType );
if( needle == containers.end() ) if( it == containers.end() )
return false; return false;
auto& sourceContainer = needle->second; auto& sourceContainer = it->second;
auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( sourceContainer->getItem( slotId ) ); auto item = std::dynamic_pointer_cast< Inventory::HousingItem >( sourceContainer->getItem( slotId ) );
if( !item ) if( !item )
@ -1531,11 +1522,11 @@ Sapphire::ItemContainerPtr Sapphire::World::Manager::HousingMgr::getFreeEstateIn
for( auto bag : bagList ) for( auto bag : bagList )
{ {
auto needle = estateContainers.find( bag ); auto it = estateContainers.find( bag );
if( needle == estateContainers.end() ) if( it == estateContainers.end() )
continue; continue;
auto container = needle->second; auto container = it->second;
auto freeSlot = container->getFreeSlot(); auto freeSlot = container->getFreeSlot();
@ -1563,13 +1554,13 @@ void Sapphire::World::Manager::HousingMgr::reqEstateExteriorRemodel( Sapphire::E
return; return;
auto& inv = getEstateInventory( land->getLandIdent() ); auto& inv = getEstateInventory( land->getLandIdent() );
auto needle = inv.find( InventoryType::HousingExteriorAppearance ); auto it = inv.find( InventoryType::HousingExteriorAppearance );
if( needle == inv.end() ) if( it == inv.end() )
return; return;
auto invMgr = framework()->get< InventoryMgr >(); auto invMgr = framework()->get< InventoryMgr >();
invMgr->sendInventoryContainer( player, needle->second ); invMgr->sendInventoryContainer( player, it->second );
auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateExternalAppearanceUI, plot ); auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateExternalAppearanceUI, plot );
player.queuePacket( pkt ); player.queuePacket( pkt );
@ -1593,13 +1584,13 @@ void Sapphire::World::Manager::HousingMgr::reqEstateInteriorRemodel( Sapphire::E
return; return;
auto& inv = getEstateInventory( land->getLandIdent() ); auto& inv = getEstateInventory( land->getLandIdent() );
auto needle = inv.find( InventoryType::HousingInteriorAppearance ); auto it = inv.find( InventoryType::HousingInteriorAppearance );
if( needle == inv.end() ) if( it == inv.end() )
return; return;
auto invMgr = framework()->get< InventoryMgr >(); auto invMgr = framework()->get< InventoryMgr >();
invMgr->sendInventoryContainer( player, needle->second ); invMgr->sendInventoryContainer( player, it->second );
auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateInternalAppearanceUI ); auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateInternalAppearanceUI );
player.queuePacket( pkt ); player.queuePacket( pkt );

View file

@ -535,8 +535,8 @@ bool Sapphire::World::Manager::TerritoryMgr::movePlayer( ZonePtr pZone, Sapphire
// mark character as zoning in progress // mark character as zoning in progress
pPlayer->setLoadingComplete( false ); pPlayer->setLoadingComplete( false );
//if( pPlayer->getLastPing() != 0 ) if( pPlayer->getLastPing() != 0 )
// pPlayer->getCurrentZone()->removeActor( pPlayer ); pPlayer->getCurrentZone()->removeActor( pPlayer );
pPlayer->setCurrentZone( pZone ); pPlayer->setCurrentZone( pZone );
pZone->pushActor( pPlayer ); pZone->pushActor( pPlayer );

View file

@ -276,7 +276,6 @@ void Sapphire::Network::GameConnection::handlePacket( Sapphire::Network::Packets
void Sapphire::Network::GameConnection::sendPackets( Packets::PacketContainer* pPacket ) void Sapphire::Network::GameConnection::sendPackets( Packets::PacketContainer* pPacket )
{ {
//g_log.Log(LoggingSeverity::info, pPacket->toString());
std::vector< uint8_t > sendBuffer; std::vector< uint8_t > sendBuffer;
pPacket->fillSendBuffer( sendBuffer ); pPacket->fillSendBuffer( sendBuffer );

View file

@ -82,7 +82,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( FrameworkPtr pFw,
Logger::debug( "[{0}] Incoming action: {1:04X}\nparam1: {2:016X}\nparam2: {3:08X}\nparam3: {4:016x}", Logger::debug( "[{0}] Incoming action: {1:04X}\nparam1: {2:016X}\nparam2: {3:08X}\nparam3: {4:016x}",
m_pSession->getId(), commandId, param1, param2, param3 ); m_pSession->getId(), commandId, param1, param2, param3 );
//g_log.Log(LoggingSeverity::debug, "[" + std::to_string(m_pSession->getId()) + "] " + pInPacket->toString()); //Logger::Log(LoggingSeverity::debug, "[" + std::to_string(m_pSession->getId()) + "] " + pInPacket->toString());
switch( commandId ) switch( commandId )
{ {
@ -294,7 +294,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( FrameworkPtr pFw,
} }
case ClientTriggerType::RequestInstanceLeave: case ClientTriggerType::RequestInstanceLeave:
{ {
// todo: apply cf penalty if applicable, make sure player isnt in combat // todo: apply cf penalty if applicable, make sure player isn't in combat
player.exitInstance(); player.exitInstance();
break; break;
} }

View file

@ -141,10 +141,13 @@ void Sapphire::Network::GameConnection::gm1Handler( FrameworkPtr pFw,
targetPlayer->spawn( targetPlayer ); targetPlayer->spawn( targetPlayer );
auto inRange = targetPlayer->getInRangeActors(); auto inRange = targetPlayer->getInRangeActors();
for( auto actor : inRange ) for( auto actor : inRange )
{
if( actor->isPlayer() )
{ {
targetPlayer->despawn( actor->getAsPlayer() ); targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() ); targetPlayer->spawn( actor->getAsPlayer() );
} }
}
break; break;
} }
case GmCommand::Tribe: case GmCommand::Tribe:
@ -154,10 +157,13 @@ void Sapphire::Network::GameConnection::gm1Handler( FrameworkPtr pFw,
targetPlayer->spawn( targetPlayer ); targetPlayer->spawn( targetPlayer );
auto inRange = targetPlayer->getInRangeActors(); auto inRange = targetPlayer->getInRangeActors();
for( auto actor : inRange ) for( auto actor : inRange )
{
if( actor->isPlayer() )
{ {
targetPlayer->despawn( actor->getAsPlayer() ); targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() ); targetPlayer->spawn( actor->getAsPlayer() );
} }
}
break; break;
} }
case GmCommand::Sex: case GmCommand::Sex:
@ -167,10 +173,13 @@ void Sapphire::Network::GameConnection::gm1Handler( FrameworkPtr pFw,
targetPlayer->spawn( targetPlayer ); targetPlayer->spawn( targetPlayer );
auto inRange = targetActor->getInRangeActors(); auto inRange = targetActor->getInRangeActors();
for( auto actor : inRange ) for( auto actor : inRange )
{
if( actor->isPlayer() )
{ {
targetPlayer->despawn( actor->getAsPlayer() ); targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() ); targetPlayer->spawn( actor->getAsPlayer() );
} }
}
break; break;
} }
case GmCommand::Time: case GmCommand::Time:
@ -230,8 +239,11 @@ void Sapphire::Network::GameConnection::gm1Handler( FrameworkPtr pFw,
for( auto actor : player.getInRangeActors() ) for( auto actor : player.getInRangeActors() )
{ {
player.despawn( actor->getAsPlayer() ); if( actor->isPlayer() )
player.spawn( actor->getAsPlayer() ); {
targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() );
}
} }
break; break;
} }
@ -610,12 +622,25 @@ void Sapphire::Network::GameConnection::gm2Handler( FrameworkPtr pFw,
} }
case GmCommand::Jump: case GmCommand::Jump:
{ {
if( targetPlayer->getZoneId() != player.getZoneId() ) player.prepareZoning( targetPlayer->getZoneId(), true, 1, 0 );
if( player.getCurrentInstance() )
{ {
player.setZone( targetPlayer->getZoneId() ); player.exitInstance();
}
if( targetPlayer->getCurrentZone()->getGuId() != player.getCurrentZone()->getGuId() )
{
// Checks if the target player is in an InstanceContent to avoid binding to a Zone or PublicContent
if( targetPlayer->getCurrentInstance() )
{
auto pInstanceContent = targetPlayer->getCurrentInstance()->getAsInstanceContent();
// Not sure if GMs actually get bound to an instance they jump to on retail. It's mostly here to avoid a crash for now
pInstanceContent->bindPlayer( player.getId() );
}
player.setInstance( targetPlayer->getCurrentZone()->getGuId() );
} }
player.changePosition( targetActor->getPos().x, targetActor->getPos().y, targetActor->getPos().z, player.changePosition( targetActor->getPos().x, targetActor->getPos().y, targetActor->getPos().z,
targetActor->getRot() ); targetActor->getRot() );
player.sendZoneInPackets( 0x00, 0x00, 0, 0, false );
player.sendNotice( "Jumping to {0}", targetPlayer->getName() ); player.sendNotice( "Jumping to {0}", targetPlayer->getName() );
break; break;
} }
@ -627,10 +652,17 @@ void Sapphire::Network::GameConnection::gm2Handler( FrameworkPtr pFw,
player.sendUrgent( "You are unable to call a player while bound to a battle instance." ); player.sendUrgent( "You are unable to call a player while bound to a battle instance." );
return; return;
} }
targetPlayer->prepareZoning( player.getZoneId(), true, 1, 0 );
targetPlayer->setInstance( player.getCurrentZone() ); if( targetPlayer->getCurrentInstance() )
{
targetPlayer->exitInstance();
}
if( targetPlayer->getCurrentZone()->getGuId() != player.getCurrentZone()->getGuId() )
{
targetPlayer->setInstance( player.getCurrentZone()->getGuId() );
}
targetPlayer->changePosition( player.getPos().x, player.getPos().y, player.getPos().z, player.getRot() ); targetPlayer->changePosition( player.getPos().x, player.getPos().y, player.getPos().z, player.getRot() );
targetPlayer->sendZoneInPackets( 0x00, 0x00, 0, 0, false );
player.sendNotice( "Calling {0}", targetPlayer->getName() ); player.sendNotice( "Calling {0}", targetPlayer->getName() );
break; break;
} }

View file

@ -652,10 +652,17 @@ void Sapphire::Network::GameConnection::tellHandler( FrameworkPtr pFw,
auto tellPacket = makeChatPacket< FFXIVIpcTell >( player.getId() ); auto tellPacket = makeChatPacket< FFXIVIpcTell >( player.getId() );
strcpy( tellPacket->data().msg, packet.data().message ); strcpy( tellPacket->data().msg, packet.data().message );
strcpy( tellPacket->data().receipientName, player.getName().c_str() ); strcpy( tellPacket->data().receipientName, player.getName().c_str() );
// TODO: world id from server
tellPacket->data().contentId = player.getContentId();
tellPacket->data().worldId = 67;
// TODO: do these have a meaning? // TODO: do these have a meaning?
//tellPacket.data().u1 = 0x92CD7337; //tellPacket.data().u1 = 0x92CD7337;
//tellPacket.data().u2a = 0x2E; //tellPacket.data().u2a = 0x2E;
//tellPacket.data().u2b = 0x40; //tellPacket.data().u2b = 0x40;
if( player.isActingAsGm() )
{
//tellPacket->data().isGm = true;
}
pTargetPlayer->queueChatPacket( tellPacket ); pTargetPlayer->queueChatPacket( tellPacket );
} }

View file

@ -1,7 +1,7 @@
#include "NativeScriptMgr.h" #include "NativeScriptMgr.h"
#include <Crypt/md5.h> #include <Crypt/md5.h>
#include <Config/ConfigMgr.h> #include "ServerMgr.h"
#include "Framework.h" #include "Framework.h"
@ -124,8 +124,8 @@ namespace Sapphire::Scripting
NativeScriptMgr::NativeScriptMgr( FrameworkPtr pFw ) : NativeScriptMgr::NativeScriptMgr( FrameworkPtr pFw ) :
World::Manager::BaseManager( pFw ) World::Manager::BaseManager( pFw )
{ {
auto pConfig = framework()->get< ConfigMgr >(); auto pServerMgr = framework()->get< Sapphire::World::ServerMgr >();
m_loader.setCachePath( pConfig->getValue< std::string >( "Scripts", "CachePath", "./cache/" ) ); m_loader.setCachePath( pServerMgr->getConfig().scripts.cachePath );
} }

View file

@ -1,6 +1,5 @@
#include <Logging/Logger.h> #include <Logging/Logger.h>
#include <Exd/ExdDataGenerated.h> #include <Exd/ExdDataGenerated.h>
#include <Config/ConfigMgr.h>
#include <watchdog/Watchdog.h> #include <watchdog/Watchdog.h>
@ -48,10 +47,9 @@ void Sapphire::Scripting::ScriptMgr::update()
bool Sapphire::Scripting::ScriptMgr::init() bool Sapphire::Scripting::ScriptMgr::init()
{ {
std::set< std::string > files; std::set< std::string > files;
auto pConfig = framework()->get< ConfigMgr >(); auto pServerMgr = framework()->get< World::ServerMgr >();
auto status = loadDir( pConfig->getValue< std::string >( "Scripts", "Path", "./compiledscripts/" ), auto status = loadDir( pServerMgr->getConfig().scripts.path, files, m_nativeScriptMgr->getModuleExtension() );
files, m_nativeScriptMgr->getModuleExtension() );
if( !status ) if( !status )
{ {
@ -81,12 +79,12 @@ bool Sapphire::Scripting::ScriptMgr::init()
void Sapphire::Scripting::ScriptMgr::watchDirectories() void Sapphire::Scripting::ScriptMgr::watchDirectories()
{ {
auto pConfig = framework()->get< ConfigMgr >(); auto pServerMgr = framework()->get< World::ServerMgr >();
auto shouldWatch = pConfig->getValue< bool >( "Scripts", "HotSwap", true ); auto shouldWatch = pServerMgr->getConfig().scripts.hotSwap;
if( !shouldWatch ) if( !shouldWatch )
return; return;
Watchdog::watchMany( pConfig->getValue< std::string >( "Scripts", "Path", "./compiledscripts/" ) + "*" + Watchdog::watchMany( pServerMgr->getConfig().scripts.path + "*" +
m_nativeScriptMgr->getModuleExtension(), m_nativeScriptMgr->getModuleExtension(),
[ this ]( const std::vector< ci::fs::path >& paths ) [ this ]( const std::vector< ci::fs::path >& paths )
{ {
@ -157,7 +155,6 @@ void Sapphire::Scripting::ScriptMgr::onPlayerFirstEnterWorld( Entity::Player& pl
// catch( const std::exception &e ) // catch( const std::exception &e )
// { // {
// std::string what = e.what(); // std::string what = e.what();
// g_log.Log( LoggingSeverity::error, what );
// } // }
} }

View file

@ -67,15 +67,43 @@ bool Sapphire::World::ServerMgr::loadSettings( int32_t argc, char* argv[] )
Logger::info( "Loading config {0}", m_configName ); Logger::info( "Loading config {0}", m_configName );
bool failedLoad = false;
// load global cfg first
if( !pConfig->loadGlobalConfig( m_config.global ) )
{
Logger::fatal( "Error loading config global.ini, copying default..." );
failedLoad = true;
}
if( !pConfig->loadConfig( m_configName ) ) if( !pConfig->loadConfig( m_configName ) )
{ {
Logger::fatal( "Error loading config {0}", m_configName ); Logger::fatal( "Error loading config {0}", m_configName );
Logger::fatal( "If this is the first time starting the server, we've copied the default one for your editing pleasure." ); failedLoad = true;
}
if( failedLoad )
{
Logger::fatal( "If this is the first time starting the server, "
"we've copied the default configs for your editing pleasure." );
return false; return false;
} }
m_port = pConfig->getValue< uint16_t >( "ZoneNetwork", "ListenPort", 54992 ); // load world specific config
m_ip = pConfig->getValue< std::string >( "ZoneNetwork", "ListenIp", "0.0.0.0" ); m_config.scripts.hotSwap = pConfig->getValue( "Scripts", "HotSwap", true );
m_config.scripts.path = pConfig->getValue< std::string >( "Scripts", "Path", "./compiledscripts/" );
m_config.scripts.cachePath = pConfig->getValue< std::string >( "Scripts", "CachePath", "./cache/" );
m_config.network.disconnectTimeout = pConfig->getValue< uint16_t >( "Network", "DisconnectTimeout", 20 );
m_config.network.listenIp = pConfig->getValue< std::string >( "Network", "ListenIp", "0.0.0.0" );
m_config.network.listenPort = pConfig->getValue< uint16_t >( "Network", "ListenPort", 54992 );
m_config.motd = pConfig->getValue< std::string >( "General", "MotD", "" );
m_config.housing.defaultEstateName = pConfig->getValue< std::string >( "Housing", "DefaultEstateName", "Estate #{}" );
m_port = m_config.network.listenPort;
m_ip = m_config.network.listenIp;
return true; return true;
} }
@ -99,27 +127,18 @@ void Sapphire::World::ServerMgr::run( int32_t argc, char* argv[] )
Logger::info( "Setting up generated EXD data" ); Logger::info( "Setting up generated EXD data" );
auto pExdData = std::make_shared< Data::ExdDataGenerated >(); auto pExdData = std::make_shared< Data::ExdDataGenerated >();
auto dataPath = pConfig->getValue< std::string >( "GlobalParameters", "DataPath", "" ); auto dataPath = m_config.global.general.dataPath;
if( !pExdData->init( dataPath ) ) if( !pExdData->init( dataPath ) )
{ {
Logger::fatal( "Error setting up generated EXD data. Make sure that DataPath is set correctly in config.ini" ); Logger::fatal( "Error setting up generated EXD data. Make sure that DataPath is set correctly in global.ini" );
Logger::fatal( "DataPath: {0}", dataPath ); Logger::fatal( "DataPath: {0}", dataPath );
return; return;
} }
framework()->set< Data::ExdDataGenerated >( pExdData ); framework()->set< Data::ExdDataGenerated >( pExdData );
Sapphire::Db::ConnectionInfo info;
info.password = pConfig->getValue< std::string >( "Database", "Password", "" );
info.host = pConfig->getValue< std::string >( "Database", "Host", "127.0.0.1" );
info.database = pConfig->getValue< std::string >( "Database", "Database", "sapphire" );
info.port = pConfig->getValue< uint16_t >( "Database", "Port", 3306 );
info.user = pConfig->getValue< std::string >( "Database", "Username", "root" );
info.syncThreads = pConfig->getValue< uint8_t >( "Database", "SyncThreads", 2 );
info.asyncThreads = pConfig->getValue< uint8_t >( "Database", "AsyncThreads", 2 );
auto pDb = std::make_shared< Db::DbWorkerPool< Db::ZoneDbConnection > >(); auto pDb = std::make_shared< Db::DbWorkerPool< Db::ZoneDbConnection > >();
Sapphire::Db::DbLoader loader; Sapphire::Db::DbLoader loader;
loader.addDb( *pDb, info ); loader.addDb( *pDb, m_config.global.database );
if( !loader.initDbs() ) if( !loader.initDbs() )
{ {
Logger::fatal( "Database not initialized properly!" ); Logger::fatal( "Database not initialized properly!" );
@ -144,6 +163,8 @@ void Sapphire::World::ServerMgr::run( int32_t argc, char* argv[] )
} }
framework()->set< Scripting::ScriptMgr >( pScript ); framework()->set< Scripting::ScriptMgr >( pScript );
loadBNpcTemplates();
Logger::info( "TerritoryMgr: Setting up zones" ); Logger::info( "TerritoryMgr: Setting up zones" );
auto pTeriMgr = std::make_shared< Manager::TerritoryMgr >( framework() ); auto pTeriMgr = std::make_shared< Manager::TerritoryMgr >( framework() );
auto pHousingMgr = std::make_shared< Manager::HousingMgr >( framework() ); auto pHousingMgr = std::make_shared< Manager::HousingMgr >( framework() );
@ -170,7 +191,7 @@ void Sapphire::World::ServerMgr::run( int32_t argc, char* argv[] )
return; return;
} }
loadBNpcTemplates();
Network::HivePtr hive( new Network::Hive() ); Network::HivePtr hive( new Network::Hive() );
Network::addServerToHive< Network::GameConnection >( m_ip, m_port, hive, framework() ); Network::addServerToHive< Network::GameConnection >( m_ip, m_port, hive, framework() );
@ -402,7 +423,6 @@ void Sapphire::World::ServerMgr::updatePlayerName( uint32_t playerId, const std:
void Sapphire::World::ServerMgr::loadBNpcTemplates() void Sapphire::World::ServerMgr::loadBNpcTemplates()
{ {
auto pDb = framework()->get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); auto pDb = framework()->get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
auto pTeriMgr = framework()->get< TerritoryMgr >();
auto stmt = pDb->getPreparedStatement( Db::ZoneDbStatements::ZONE_SEL_BNPCTEMPLATES ); auto stmt = pDb->getPreparedStatement( Db::ZoneDbStatements::ZONE_SEL_BNPCTEMPLATES );
@ -461,3 +481,8 @@ Sapphire::Entity::BNpcTemplatePtr Sapphire::World::ServerMgr::getBNpcTemplate( u
return nullptr; return nullptr;
} }
Sapphire::Common::Config::WorldConfig& Sapphire::World::ServerMgr::getConfig()
{
return m_config;
}

View file

@ -7,6 +7,7 @@
#include <map> #include <map>
#include "ForwardsZone.h" #include "ForwardsZone.h"
#include "Manager/BaseManager.h" #include "Manager/BaseManager.h"
#include <Config/ConfigDef.h>
namespace Sapphire::World namespace Sapphire::World
{ {
@ -18,6 +19,8 @@ namespace Sapphire::World
~ServerMgr() override; ~ServerMgr() override;
using WorldConfigPtr = std::shared_ptr< Sapphire::Common::Config::WorldConfig >;
void run( int32_t argc, char* argv[] ); void run( int32_t argc, char* argv[] );
bool createSession( uint32_t sessionId ); bool createSession( uint32_t sessionId );
@ -48,6 +51,8 @@ namespace Sapphire::World
std::string getPlayerNameFromDb( uint32_t playerId, bool forceDbLoad = false ); std::string getPlayerNameFromDb( uint32_t playerId, bool forceDbLoad = false );
void updatePlayerName( uint32_t playerId, const std::string& playerNewName ); void updatePlayerName( uint32_t playerId, const std::string& playerNewName );
Sapphire::Common::Config::WorldConfig& getConfig();
private: private:
uint16_t m_port; uint16_t m_port;
std::string m_ip; std::string m_ip;
@ -59,6 +64,8 @@ namespace Sapphire::World
std::mutex m_sessionMutex; std::mutex m_sessionMutex;
Sapphire::Common::Config::WorldConfig m_config;
std::map< uint32_t, SessionPtr > m_sessionMapById; std::map< uint32_t, SessionPtr > m_sessionMapById;
std::map< std::string, SessionPtr > m_sessionMapByName; std::map< std::string, SessionPtr > m_sessionMapByName;
std::map< uint32_t, std::string > m_playerNameMapById; std::map< uint32_t, std::string > m_playerNameMapById;

View file

@ -196,13 +196,13 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::spawnHousing
void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateHousingObjectPosition( Entity::Player& sourcePlayer, void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateHousingObjectPosition( Entity::Player& sourcePlayer,
uint16_t slot, uint16_t slot,
Common::FFXIVARR_POSITION3_U16 pos, Common::FFXIVARR_POSITION3 pos,
uint16_t rot ) uint16_t rot )
{ {
auto& obj = m_housingObjects[ slot ]; auto& obj = m_housingObjects[ slot ];
obj.pos = pos; obj.pos = pos;
obj.itemRotation = rot; obj.rotation = rot;
// todo: how does this update on other clients? // todo: how does this update on other clients?
@ -213,7 +213,7 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::updateHousin
auto moveObjPkt = makeZonePacket< Server::FFXIVIpcHousingObjectMove >( player.second->getId() ); auto moveObjPkt = makeZonePacket< Server::FFXIVIpcHousingObjectMove >( player.second->getId() );
moveObjPkt->data().itemRotation = obj.itemRotation; moveObjPkt->data().itemRotation = obj.rotation;
moveObjPkt->data().pos = obj.pos; moveObjPkt->data().pos = obj.pos;
// todo: how does this work when an item is in a slot >50 or u8 max? my guess is landid is the container index, but not sure... // todo: how does this work when an item is in a slot >50 or u8 max? my guess is landid is the container index, but not sure...

View file

@ -29,7 +29,7 @@ namespace Sapphire::World::Territory::Housing
void spawnHousingObject( uint8_t containerIdx, uint16_t slot, uint16_t containerType, void spawnHousingObject( uint8_t containerIdx, uint16_t slot, uint16_t containerType,
Inventory::HousingItemPtr item ); Inventory::HousingItemPtr item );
void updateHousingObjectPosition( void updateHousingObjectPosition(
Entity::Player& sourcePlayer, uint16_t slot, Sapphire::Common::FFXIVARR_POSITION3_U16 pos, uint16_t rot ); Entity::Player& sourcePlayer, uint16_t slot, Sapphire::Common::FFXIVARR_POSITION3 pos, uint16_t rot );
void removeHousingObject( uint16_t slot ); void removeHousingObject( uint16_t slot );
private: private:

View file

@ -353,7 +353,7 @@ void Sapphire::HousingZone::spawnYardObject( uint8_t landId, uint16_t slotId, In
Common::HousingObject obj {}; Common::HousingObject obj {};
obj.itemId = item.getAdditionalData(); obj.itemId = item.getAdditionalData();
obj.itemRotation = item.getRot(); obj.rotation = item.getRot();
obj.pos = item.getPos(); obj.pos = item.getPos();
@ -383,7 +383,7 @@ void Sapphire::HousingZone::updateYardObjectPos( Entity::Player& sourcePlayer, u
auto& obj = m_yardObjects[ yardMapIndex ][ offset ]; auto& obj = m_yardObjects[ yardMapIndex ][ offset ];
obj.itemRotation = item.getRot(); obj.rotation = item.getRot();
obj.pos = item.getPos(); obj.pos = item.getPos();
for( const auto& player : m_playerMap ) for( const auto& player : m_playerMap )

View file

@ -89,11 +89,8 @@ void Sapphire::InstanceContent::onLeaveTerritory( Entity::Player& player )
{ {
Logger::debug( "InstanceContent::onLeaveTerritory: Zone#{0}|{1}, Entity#{2}", Logger::debug( "InstanceContent::onLeaveTerritory: Zone#{0}|{1}, Entity#{2}",
getGuId(), getTerritoryTypeId(), player.getId() ); getGuId(), getTerritoryTypeId(), player.getId() );
sendDirectorClear( player );
player.setDirectorInitialized( false ); clearDirector( player );
// remove "bound by duty" state
player.unsetStateFlag( PlayerStateFlag::BoundByDuty );
} }
void Sapphire::InstanceContent::onUpdate( uint32_t currTime ) void Sapphire::InstanceContent::onUpdate( uint32_t currTime )
@ -450,3 +447,11 @@ void Sapphire::InstanceContent::unbindPlayer( uint32_t playerId )
if( it != m_playerMap.end() ) if( it != m_playerMap.end() )
it->second->exitInstance(); it->second->exitInstance();
} }
void Sapphire::InstanceContent::clearDirector( Entity::Player& player )
{
sendDirectorClear( player );
player.setDirectorInitialized( false );
// remove "bound by duty" state
player.unsetStateFlag( PlayerStateFlag::BoundByDuty );}

View file

@ -64,6 +64,8 @@ public:
void endEventCutscene(); void endEventCutscene();
void clearDirector( Entity::Player& player );
/*! set the current bgm index (inside bgm.exd) */ /*! set the current bgm index (inside bgm.exd) */
void setCurrentBGM( uint16_t bgmId ); void setCurrentBGM( uint16_t bgmId );

View file

@ -1,6 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <vector> #include <vector>
#include <time.h> #include <time.h>
#include <random>
#include <Logging/Logger.h> #include <Logging/Logger.h>
#include <Util/Util.h> #include <Util/Util.h>
@ -53,7 +54,8 @@ Sapphire::Zone::Zone() :
m_currentWeather( Weather::FairSkies ), m_currentWeather( Weather::FairSkies ),
m_weatherOverride( Weather::None ), m_weatherOverride( Weather::None ),
m_lastMobUpdate( 0 ), m_lastMobUpdate( 0 ),
m_nextEObjId( 0x400D0000 ) m_nextEObjId( 0x400D0000 ),
m_nextActorId( 0x500D0000 )
{ {
} }
@ -435,6 +437,7 @@ bool Sapphire::Zone::update( uint32_t currTime )
//updateBnpcs( tickCount ); //updateBnpcs( tickCount );
onUpdate( currTime ); onUpdate( currTime );
updateSpawnPoints();
return true; return true;
} }
@ -740,6 +743,12 @@ uint32_t Sapphire::Zone::getNextEObjId()
return ++m_nextEObjId; return ++m_nextEObjId;
} }
uint32_t Sapphire::Zone::getNextActorId()
{
return ++m_nextActorId;
}
Sapphire::Entity::EventObjectPtr Sapphire::Zone::registerEObj( const std::string& name, uint32_t objectId, uint32_t mapLink, Sapphire::Entity::EventObjectPtr Sapphire::Zone::registerEObj( const std::string& name, uint32_t objectId, uint32_t mapLink,
uint8_t state, FFXIVARR_POSITION3 pos, float scale, uint8_t state, FFXIVARR_POSITION3 pos, float scale,
float rotation ) float rotation )
@ -772,7 +781,7 @@ bool Sapphire::Zone::loadSpawnGroups()
m_spawnGroups.emplace_back( id, templateId, level, maxHp ); m_spawnGroups.emplace_back( id, templateId, level, maxHp );
Logger::debug( "id: {0}, template: {1}, level: {2}, maxHp: {3}", id, templateId, level, maxHp ); Logger::debug( "id: {0}, template: {1}, level: {2}, maxHp: {3}", id, m_spawnGroups.back().getTemplateId(), level, maxHp );
} }
res.reset(); res.reset();
@ -800,3 +809,44 @@ bool Sapphire::Zone::loadSpawnGroups()
} }
return false; return false;
} }
void Sapphire::Zone::updateSpawnPoints()
{
std::random_device rd;
std::mt19937 mt( rd() );
std::uniform_real_distribution< float > dist( 0.0, PI * 2 );
for( auto& group : m_spawnGroups )
{
for( auto& point : group.getSpawnPointList() )
{
if( !point->getLinkedBNpc() && ( Util::getTimeSeconds() - point->getTimeOfDeath() ) > 60 )
{
auto serverZone = m_pFw->get< World::ServerMgr >();
auto bNpcTemplate = serverZone->getBNpcTemplate( group.getTemplateId() );
if( !bNpcTemplate )
{
//Logger::error( "No template found for templateId#{0}", group.getTemplateId() );
continue;
}
uint32_t random = rand() % 20;
auto pBNpc = std::make_shared< Entity::BNpc >( getNextActorId(),
bNpcTemplate,
point->getPosX(),
point->getPosY(),
point->getPosZ(),
dist( mt ),
group.getLevel(),
group.getMaxHp(), m_pFw );
point->setLinkedBNpc( pBNpc );
pushActor( pBNpc );
}
}
}
}

View file

@ -57,6 +57,7 @@ namespace Sapphire
std::map< uint8_t, int32_t > m_weatherRateMap; std::map< uint8_t, int32_t > m_weatherRateMap;
uint32_t m_nextEObjId; uint32_t m_nextEObjId;
uint32_t m_nextActorId;
FrameworkPtr m_pFw; FrameworkPtr m_pFw;
std::vector< Entity::SpawnGroup > m_spawnGroups; std::vector< Entity::SpawnGroup > m_spawnGroups;
@ -128,6 +129,8 @@ namespace Sapphire
uint32_t getNextEObjId(); uint32_t getNextEObjId();
uint32_t getNextActorId();
const std::string& getName() const; const std::string& getName() const;
const std::string& getInternalName() const; const std::string& getInternalName() const;
@ -154,6 +157,7 @@ namespace Sapphire
InstanceContentPtr getAsInstanceContent(); InstanceContentPtr getAsInstanceContent();
void updateSpawnPoints();
}; };
} }

View file

@ -9,7 +9,7 @@ using namespace Sapphire::World;
int main( int32_t argc, char* argv[] ) int main( int32_t argc, char* argv[] )
{ {
auto pFramework = Sapphire::make_Framework(); auto pFramework = Sapphire::make_Framework();
auto pServer = std::make_shared< ServerMgr >( "config.ini", pFramework ); auto pServer = std::make_shared< ServerMgr >( "world.ini", pFramework );
pFramework->set< ServerMgr >( pServer ); pFramework->set< ServerMgr >( pServer );
pServer->run( argc, argv ); pServer->run( argc, argv );
return 0; return 0;