mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-26 22:37:45 +00:00
Merge remote-tracking branch 'origin/housing' into develop
This commit is contained in:
commit
a25cfcd9d1
32 changed files with 670 additions and 147 deletions
|
@ -734,7 +734,7 @@ void defaultGet( shared_ptr< HttpServer::Response > response, shared_ptr< HttpSe
|
||||||
|
|
||||||
int main( int argc, char* argv[] )
|
int main( int argc, char* argv[] )
|
||||||
{
|
{
|
||||||
Logger::init( "log/SapphireAPI" );
|
Logger::init( "log/api" );
|
||||||
|
|
||||||
Logger::info( "===========================================================" );
|
Logger::info( "===========================================================" );
|
||||||
Logger::info( "Sapphire API Server " );
|
Logger::info( "Sapphire API Server " );
|
||||||
|
|
|
@ -791,7 +791,7 @@ namespace Sapphire::Common
|
||||||
ExteriorFence
|
ExteriorFence
|
||||||
};
|
};
|
||||||
|
|
||||||
enum HousingInteriorSlot
|
enum HouseInteriorSlot
|
||||||
{
|
{
|
||||||
InteriorWall,
|
InteriorWall,
|
||||||
InteriorFloor,
|
InteriorFloor,
|
||||||
|
@ -866,13 +866,13 @@ namespace Sapphire::Common
|
||||||
Mansion
|
Mansion
|
||||||
};
|
};
|
||||||
|
|
||||||
enum HouseState : uint8_t
|
enum HouseStatus : uint8_t
|
||||||
{
|
{
|
||||||
none,
|
none,
|
||||||
forSale,
|
ForSale,
|
||||||
sold,
|
Sold,
|
||||||
privateHouse,
|
PrivateEstate,
|
||||||
fcHouse,
|
FreeCompanyEstate,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum HouseIconAdd : uint8_t
|
enum HouseIconAdd : uint8_t
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace Sapphire
|
||||||
|
|
||||||
void Logger::init( const std::string& logPath )
|
void Logger::init( const std::string& logPath )
|
||||||
{
|
{
|
||||||
auto pos = logPath.find_last_of( '/' );
|
auto pos = logPath.find_last_of( fs::path::preferred_separator );
|
||||||
|
|
||||||
if( pos != std::string::npos )
|
if( pos != std::string::npos )
|
||||||
{
|
{
|
||||||
|
@ -58,6 +58,11 @@ namespace Sapphire
|
||||||
spdlog::get( "logger" )->error( text );
|
spdlog::get( "logger" )->error( text );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Logger::warn( const std::string& text )
|
||||||
|
{
|
||||||
|
spdlog::get( "logger" )->warn( text );
|
||||||
|
}
|
||||||
|
|
||||||
void Logger::info( const std::string& text )
|
void Logger::info( const std::string& text )
|
||||||
{
|
{
|
||||||
spdlog::get( "logger" )->info( text );
|
spdlog::get( "logger" )->info( text );
|
||||||
|
@ -73,4 +78,9 @@ namespace Sapphire
|
||||||
spdlog::get( "logger" )->critical( text );
|
spdlog::get( "logger" )->critical( text );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Logger::trace( const std::string& text )
|
||||||
|
{
|
||||||
|
spdlog::get( "logger" )->trace( text );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,16 @@ namespace Sapphire
|
||||||
|
|
||||||
static void error( const std::string& text );
|
static void error( const std::string& text );
|
||||||
|
|
||||||
|
static void warn( const std::string& text );
|
||||||
|
|
||||||
static void info( const std::string& text );
|
static void info( const std::string& text );
|
||||||
|
|
||||||
static void debug( const std::string& text );
|
static void debug( const std::string& text );
|
||||||
|
|
||||||
static void fatal( const std::string& text );
|
static void fatal( const std::string& text );
|
||||||
|
|
||||||
|
static void trace( const std::string& text );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,6 +240,7 @@ enum ActorControlType : uint16_t
|
||||||
*/
|
*/
|
||||||
HousingItemMoveConfirm = 0x3F9,
|
HousingItemMoveConfirm = 0x3F9,
|
||||||
OpenEstateSettingsUI = 0x3FF,
|
OpenEstateSettingsUI = 0x3FF,
|
||||||
|
HideAdditionalChambersDoor = 0x400,
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* param1 = outdoor furnishings
|
* param1 = outdoor furnishings
|
||||||
|
|
|
@ -176,7 +176,7 @@ namespace Sapphire::Network::Packets
|
||||||
|
|
||||||
DirectorVars = 0x01E1, // updated 4.4
|
DirectorVars = 0x01E1, // updated 4.4
|
||||||
|
|
||||||
CFAvailableContents = 0x01FD, // updated 4.2
|
CFAvailableContents = 0xF1FD, // updated 4.2
|
||||||
|
|
||||||
WeatherChange = 0x01FC, // updated 4.4
|
WeatherChange = 0x01FC, // updated 4.4
|
||||||
PlayerTitleList = 0x01FD, // updated 4.4
|
PlayerTitleList = 0x01FD, // updated 4.4
|
||||||
|
@ -264,10 +264,10 @@ namespace Sapphire::Network::Packets
|
||||||
|
|
||||||
LinkshellListHandler = 0x00F4, // updated 4.3
|
LinkshellListHandler = 0x00F4, // updated 4.3
|
||||||
|
|
||||||
MarketBoardRequestItemInformation = 0x00FE, // updated 4.4
|
MarketBoardRequestItemListingInfo = 0x00FE, // updated 4.4
|
||||||
MarketBoardRequestItemListings = 0x00FF, // updated 4.4
|
MarketBoardRequestItemListings = 0x00FF, // updated 4.4
|
||||||
|
MarketBoardSearch = 0x0103, // updated 4.4
|
||||||
|
|
||||||
SearchMarketboard = 0x0103, // updated 4.3
|
|
||||||
ReqExamineFcInfo = 0x010F, // updated 4.1
|
ReqExamineFcInfo = 0x010F, // updated 4.1
|
||||||
|
|
||||||
FcInfoReqHandler = 0x011A, // updated 4.2
|
FcInfoReqHandler = 0x011A, // updated 4.2
|
||||||
|
|
|
@ -237,8 +237,9 @@ struct FFXIVIpcSetSharedEstateSettings :
|
||||||
struct FFXIVIpcMarketBoardRequestItemListings :
|
struct FFXIVIpcMarketBoardRequestItemListings :
|
||||||
FFXIVIpcBasePacket< MarketBoardRequestItemListings >
|
FFXIVIpcBasePacket< MarketBoardRequestItemListings >
|
||||||
{
|
{
|
||||||
/* 0000 */ uint32_t itemCatalogId;
|
/* 0000 */ uint16_t padding1;
|
||||||
/* 0004 */ uint32_t padding;
|
/* 0002 */ uint16_t itemCatalogId;
|
||||||
|
/* 0004 */ uint32_t padding2;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FFXIVIpcReqPlaceHousingItem :
|
struct FFXIVIpcReqPlaceHousingItem :
|
||||||
|
@ -253,7 +254,7 @@ struct FFXIVIpcReqPlaceHousingItem :
|
||||||
/* 000C */ Common::FFXIVARR_POSITION3 position;
|
/* 000C */ Common::FFXIVARR_POSITION3 position;
|
||||||
/* 0018 */ float rotation;
|
/* 0018 */ float rotation;
|
||||||
|
|
||||||
/* 001C */ uint32_t unknown3; // always 1?
|
/* 001C */ uint32_t shouldPlaceItem; // 1 if placing an item, 0 if placing in store
|
||||||
/* 0020 */ uint32_t unknown4[2]; // always 0 it looks like
|
/* 0020 */ uint32_t unknown4[2]; // always 0 it looks like
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -270,6 +271,26 @@ struct FFXIVIpcHousingUpdateObjectPosition :
|
||||||
/* 001C */ uint32_t padding;
|
/* 001C */ uint32_t padding;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcMarketBoardSearch :
|
||||||
|
FFXIVIpcBasePacket< MarketBoardSearch >
|
||||||
|
{
|
||||||
|
/* 0000 */ uint32_t startIdx;
|
||||||
|
/* 0004 */ uint16_t requestId;
|
||||||
|
/* 0006 */ uint8_t itemSearchCategory;
|
||||||
|
/* 0007 */ uint8_t shouldCheckClassJobId; // wat? seems only 1 there at least...
|
||||||
|
/* 0008 */ uint8_t maxEquipLevel;
|
||||||
|
/* 0009 */ uint8_t classJobId;
|
||||||
|
/* 000A */ char searchStr[40];
|
||||||
|
/* 0032 */ uint16_t unk4[43];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FFXIVIpcMarketBoardRequestItemListingInfo :
|
||||||
|
FFXIVIpcBasePacket< MarketBoardRequestItemListingInfo >
|
||||||
|
{
|
||||||
|
/* 0000 */ uint32_t catalogId;
|
||||||
|
/* 0000 */ uint32_t requestId;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1701,6 +1701,10 @@ struct FFXIVIpcHousingObjectMove : FFXIVIpcBasePacket< HousingObjectMove >
|
||||||
struct FFXIVIpcHousingObjectInitialize : FFXIVIpcBasePacket< HousingObjectInitialize >
|
struct FFXIVIpcHousingObjectInitialize : FFXIVIpcBasePacket< HousingObjectInitialize >
|
||||||
{
|
{
|
||||||
Common::LandIdent landIdent;
|
Common::LandIdent landIdent;
|
||||||
|
/*!
|
||||||
|
* when this is 2, actrl 0x400 will hide the additional quarters door
|
||||||
|
* if it's any other value, it will stay there regardless
|
||||||
|
*/
|
||||||
int8_t u1; //Outdoor -1 / Indoor 0 - probably indicator
|
int8_t u1; //Outdoor -1 / Indoor 0 - probably indicator
|
||||||
uint8_t packetNum;
|
uint8_t packetNum;
|
||||||
uint8_t packetTotal;
|
uint8_t packetTotal;
|
||||||
|
@ -1843,13 +1847,14 @@ struct FFXIVIpcMarketBoardSearchResult :
|
||||||
struct MarketBoardItem
|
struct MarketBoardItem
|
||||||
{
|
{
|
||||||
uint32_t itemCatalogId;
|
uint32_t itemCatalogId;
|
||||||
uint32_t quantity;
|
uint16_t quantity;
|
||||||
|
uint16_t demand;
|
||||||
} items[20];
|
} items[20];
|
||||||
|
|
||||||
uint32_t itemIndexEnd;
|
uint32_t itemIndexEnd;
|
||||||
uint32_t padding1;
|
uint32_t padding1;
|
||||||
uint32_t itemIndexStart;
|
uint32_t itemIndexStart;
|
||||||
uint32_t padding2;
|
uint32_t requestId;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FFFXIVIpcMarketBoardItemListingCount :
|
struct FFFXIVIpcMarketBoardItemListingCount :
|
||||||
|
@ -1857,9 +1862,9 @@ struct FFFXIVIpcMarketBoardItemListingCount :
|
||||||
{
|
{
|
||||||
uint32_t itemCatalogId;
|
uint32_t itemCatalogId;
|
||||||
uint32_t unknown1; // does some shit if nonzero
|
uint32_t unknown1; // does some shit if nonzero
|
||||||
uint16_t unknown2;
|
uint16_t requestId;
|
||||||
uint16_t quantity; // high/low u8s read separately?
|
uint16_t quantity; // high/low u8s read separately?
|
||||||
uint32_t padding3;
|
uint32_t unknown3;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FFXIVIpcMarketBoardItemListingHistory :
|
struct FFXIVIpcMarketBoardItemListingHistory :
|
||||||
|
@ -1871,14 +1876,14 @@ struct FFXIVIpcMarketBoardItemListingHistory :
|
||||||
struct MarketListing
|
struct MarketListing
|
||||||
{
|
{
|
||||||
uint32_t salePrice;
|
uint32_t salePrice;
|
||||||
time_t purchaseTime;
|
uint32_t purchaseTime;
|
||||||
uint32_t quantity;
|
uint32_t quantity;
|
||||||
uint16_t unknown1;
|
uint8_t isHq;
|
||||||
uint8_t unknown2;
|
uint8_t padding;
|
||||||
|
uint8_t onMannequin;
|
||||||
|
|
||||||
char sellerName[32];
|
char buyerName[33];
|
||||||
|
|
||||||
uint8_t unknown3;
|
|
||||||
uint32_t itemCatalogId;
|
uint32_t itemCatalogId;
|
||||||
} listing[20];
|
} listing[20];
|
||||||
};
|
};
|
||||||
|
|
|
@ -104,7 +104,7 @@ int main( int32_t argc, char* argv[] )
|
||||||
std::string database;
|
std::string database;
|
||||||
std::string pass;
|
std::string pass;
|
||||||
|
|
||||||
Logger::init( "log/SapphireDbm" );
|
Logger::init( "log/dbm" );
|
||||||
|
|
||||||
std::string sFile;
|
std::string sFile;
|
||||||
std::string iFile;
|
std::string iFile;
|
||||||
|
|
|
@ -31,12 +31,10 @@ namespace Sapphire
|
||||||
m_configPath( configPath ),
|
m_configPath( configPath ),
|
||||||
m_numConnections( 0 )
|
m_numConnections( 0 )
|
||||||
{
|
{
|
||||||
m_pConfig = std::shared_ptr< ConfigMgr >( new ConfigMgr );
|
m_pConfig = std::make_shared< ConfigMgr >();
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerLobby::~ServerLobby( void )
|
ServerLobby::~ServerLobby( void ) = default;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
LobbySessionPtr ServerLobby::getSession( char* sessionId )
|
LobbySessionPtr ServerLobby::getSession( char* sessionId )
|
||||||
{
|
{
|
||||||
|
@ -50,7 +48,7 @@ namespace Sapphire
|
||||||
|
|
||||||
void ServerLobby::run( int32_t argc, char* argv[] )
|
void ServerLobby::run( int32_t argc, char* argv[] )
|
||||||
{
|
{
|
||||||
Logger::init( "log/SapphireLobby" );
|
Logger::init( "log/lobby" );
|
||||||
|
|
||||||
Logger::info( "===========================================================" );
|
Logger::info( "===========================================================" );
|
||||||
Logger::info( "Sapphire Server Project " );
|
Logger::info( "Sapphire Server Project " );
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "Actor/EventObject.h"
|
#include "Actor/EventObject.h"
|
||||||
#include "Territory/HousingZone.h"
|
#include "Territory/HousingZone.h"
|
||||||
#include "Manager/TerritoryMgr.h"
|
#include "Manager/TerritoryMgr.h"
|
||||||
|
#include "Territory/Land.h"
|
||||||
#include "Framework.h"
|
#include "Framework.h"
|
||||||
|
|
||||||
using namespace Sapphire;
|
using namespace Sapphire;
|
||||||
|
@ -19,8 +20,6 @@ public:
|
||||||
|
|
||||||
void onTalk( uint32_t eventId, Entity::Player& player, Entity::EventObject& eobj ) override
|
void onTalk( uint32_t eventId, Entity::Player& player, Entity::EventObject& eobj ) override
|
||||||
{
|
{
|
||||||
player.sendDebug( "Found plot entrance for plot: " + std::to_string( eobj.getHousingLink() >> 8 ) );
|
|
||||||
|
|
||||||
player.playScene( eventId, 0, 0, [this, eobj]( Entity::Player& player, const Event::SceneResult& result )
|
player.playScene( eventId, 0, 0, [this, eobj]( Entity::Player& player, const Event::SceneResult& result )
|
||||||
{
|
{
|
||||||
// param2 == 1 when player wants to enter house
|
// param2 == 1 when player wants to enter house
|
||||||
|
@ -42,15 +41,45 @@ public:
|
||||||
ident.worldId = 67;
|
ident.worldId = 67;
|
||||||
|
|
||||||
auto internalZone = terriMgr->findOrCreateHousingInterior( ident );
|
auto internalZone = terriMgr->findOrCreateHousingInterior( ident );
|
||||||
if( internalZone )
|
if( !internalZone )
|
||||||
{
|
{
|
||||||
player.sendDebug( "created zone with guid: " + std::to_string( internalZone->getGuId() ) + "\nname: " + internalZone->getName() );
|
// an error occurred during event movement
|
||||||
|
// lol
|
||||||
|
player.sendLogMessage( 1311 );
|
||||||
|
player.eventFinish( result.eventId, 1 );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.eventFinish( result.eventId, 1 );
|
player.eventFinish( result.eventId, 1 );
|
||||||
|
|
||||||
player.setPos( { 0.f, 0.f, 0.f } );
|
Common::FFXIVARR_POSITION3 pos {};
|
||||||
player.setInstance( internalZone );
|
|
||||||
|
auto land = zone->getLand( eobj.getHousingLink() >> 8 );
|
||||||
|
if( !land )
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch( land->getSize() )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
pos = { 0.1321167f, 0.f, 2.746273f };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
pos = { 1.337722f, 0.f, 3.995964f };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
pos = { 0.07214607f, 0.f, 8.217761f };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.setInstance( internalZone, pos );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -459,6 +459,33 @@ bool Sapphire::Entity::Player::setInstance( ZonePtr instance )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Entity::Player::setInstance( ZonePtr instance, Common::FFXIVARR_POSITION3 pos )
|
||||||
|
{
|
||||||
|
if( !instance )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_onEnterEventDone = false;
|
||||||
|
|
||||||
|
auto pTeriMgr = m_pFw->get< TerritoryMgr >();
|
||||||
|
auto currentZone = getCurrentZone();
|
||||||
|
|
||||||
|
m_prevPos = m_pos;
|
||||||
|
m_prevRot = m_rot;
|
||||||
|
m_prevTerritoryTypeId = currentZone->getTerritoryTypeId();
|
||||||
|
m_prevTerritoryId = getTerritoryId();
|
||||||
|
|
||||||
|
if( pTeriMgr->movePlayer( instance, getAsPlayer() ) )
|
||||||
|
{
|
||||||
|
m_pos = pos;
|
||||||
|
|
||||||
|
sendZonePackets();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Sapphire::Entity::Player::exitInstance()
|
bool Sapphire::Entity::Player::exitInstance()
|
||||||
{
|
{
|
||||||
auto pTeriMgr = m_pFw->get< TerritoryMgr >();
|
auto pTeriMgr = m_pFw->get< TerritoryMgr >();
|
||||||
|
|
|
@ -482,6 +482,9 @@ namespace Sapphire::Entity
|
||||||
/*! sets the players instance & initiates zoning process */
|
/*! sets the players instance & initiates zoning process */
|
||||||
bool setInstance( ZonePtr instance );
|
bool setInstance( ZonePtr instance );
|
||||||
|
|
||||||
|
/*! sets the players instance & initiates zoning process */
|
||||||
|
bool setInstance( Sapphire::ZonePtr instance, Sapphire::Common::FFXIVARR_POSITION3 pos );
|
||||||
|
|
||||||
/*! returns the player to their position before zoning into an instance */
|
/*! returns the player to their position before zoning into an instance */
|
||||||
bool exitInstance();
|
bool exitInstance();
|
||||||
|
|
||||||
|
@ -916,7 +919,7 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
uint32_t getNextInventorySequence();
|
uint32_t getNextInventorySequence();
|
||||||
|
|
||||||
void send();
|
bool findFirstItemWithId( uint32_t catalogId, Inventory::InventoryContainerPair& location );
|
||||||
|
|
||||||
uint8_t getFreeSlotsInBags();
|
uint8_t getFreeSlotsInBags();
|
||||||
|
|
||||||
|
|
|
@ -933,3 +933,24 @@ void Sapphire::Entity::Player::insertInventoryItem( Sapphire::Common::InventoryT
|
||||||
queuePacket( slotUpdate );
|
queuePacket( slotUpdate );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Entity::Player::findFirstItemWithId( uint32_t catalogId,
|
||||||
|
Inventory::InventoryContainerPair& location )
|
||||||
|
{
|
||||||
|
for( auto bagId : { Bag0, Bag1, Bag2, Bag3 } )
|
||||||
|
{
|
||||||
|
auto& container = m_storageMap[ bagId ];
|
||||||
|
|
||||||
|
for( const auto& item : container->getItemMap() )
|
||||||
|
{
|
||||||
|
if( item.second->getId() != catalogId )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
location = std::make_pair( bagId, item.first );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -179,8 +179,8 @@ void Sapphire::World::Manager::HousingMgr::initLandCache()
|
||||||
entry.m_landId = res->getUInt( "LandId" );
|
entry.m_landId = res->getUInt( "LandId" );
|
||||||
|
|
||||||
entry.m_type = static_cast< Common::LandType >( res->getUInt( "Type" ) );
|
entry.m_type = static_cast< Common::LandType >( res->getUInt( "Type" ) );
|
||||||
entry.m_size = res->getUInt8( "Size" );
|
entry.m_size = static_cast< Common::HouseSize >( res->getUInt8( "Size" ) );
|
||||||
entry.m_status = res->getUInt8( "Status" );
|
entry.m_status = static_cast< Common::HouseStatus >( res->getUInt8( "Status" ) );
|
||||||
entry.m_currentPrice = res->getUInt64( "LandPrice" );
|
entry.m_currentPrice = res->getUInt64( "LandPrice" );
|
||||||
entry.m_updateTime = res->getUInt64( "UpdateTime" );
|
entry.m_updateTime = res->getUInt64( "UpdateTime" );
|
||||||
entry.m_ownerId = res->getUInt64( "OwnerId" );
|
entry.m_ownerId = res->getUInt64( "OwnerId" );
|
||||||
|
@ -365,7 +365,7 @@ Sapphire::LandPurchaseResult Sapphire::World::Manager::HousingMgr::purchaseLand(
|
||||||
if( !pLand )
|
if( !pLand )
|
||||||
return LandPurchaseResult::ERR_INTERNAL;
|
return LandPurchaseResult::ERR_INTERNAL;
|
||||||
|
|
||||||
if( pLand->getState() != HouseState::forSale )
|
if( pLand->getStatus() != HouseStatus::ForSale )
|
||||||
return LandPurchaseResult::ERR_NOT_AVAILABLE;
|
return LandPurchaseResult::ERR_NOT_AVAILABLE;
|
||||||
|
|
||||||
if( gilAvailable < plotPrice )
|
if( gilAvailable < plotPrice )
|
||||||
|
@ -388,7 +388,7 @@ Sapphire::LandPurchaseResult Sapphire::World::Manager::HousingMgr::purchaseLand(
|
||||||
|
|
||||||
player.removeCurrency( CurrencyType::Gil, plotPrice );
|
player.removeCurrency( CurrencyType::Gil, plotPrice );
|
||||||
pLand->setOwnerId( player.getId() );
|
pLand->setOwnerId( player.getId() );
|
||||||
pLand->setState( HouseState::sold );
|
pLand->setStatus( HouseStatus::Sold );
|
||||||
pLand->setLandType( Common::LandType::Private );
|
pLand->setLandType( Common::LandType::Private );
|
||||||
|
|
||||||
player.setLandFlags( LandFlagsSlot::Private, 0x00, pLand->getLandIdent() );
|
player.setLandFlags( LandFlagsSlot::Private, 0x00, pLand->getLandIdent() );
|
||||||
|
@ -416,11 +416,10 @@ bool Sapphire::World::Manager::HousingMgr::relinquishLand( Entity::Player& playe
|
||||||
|
|
||||||
auto pLand = pHousing->getLand( plot );
|
auto pLand = pHousing->getLand( plot );
|
||||||
auto plotMaxPrice = pLand->getCurrentPrice();
|
auto plotMaxPrice = pLand->getCurrentPrice();
|
||||||
auto landOwnerId = pLand->getOwnerId();
|
|
||||||
|
|
||||||
// can't relinquish when you are not the owner
|
// can't relinquish when you are not the owner
|
||||||
// TODO: actually use permissions here for FC houses
|
// TODO: actually use permissions here for FC houses
|
||||||
if( landOwnerId != player.getId() )
|
if( !hasPermission( player, *pLand, 0 ) )
|
||||||
{
|
{
|
||||||
auto msgPkt = makeActorControl143( player.getId(), ActorControl::LogMsg, 3304, 0 );
|
auto msgPkt = makeActorControl143( player.getId(), ActorControl::LogMsg, 3304, 0 );
|
||||||
player.queuePacket( msgPkt );
|
player.queuePacket( msgPkt );
|
||||||
|
@ -438,7 +437,7 @@ bool Sapphire::World::Manager::HousingMgr::relinquishLand( Entity::Player& playe
|
||||||
|
|
||||||
pLand->setCurrentPrice( pLand->getMaxPrice() );
|
pLand->setCurrentPrice( pLand->getMaxPrice() );
|
||||||
pLand->setOwnerId( 0 );
|
pLand->setOwnerId( 0 );
|
||||||
pLand->setState( HouseState::forSale );
|
pLand->setStatus( HouseStatus::ForSale );
|
||||||
pLand->setLandType( Common::LandType::none );
|
pLand->setLandType( Common::LandType::none );
|
||||||
pLand->updateLandDb();
|
pLand->updateLandDb();
|
||||||
|
|
||||||
|
@ -478,11 +477,11 @@ void Sapphire::World::Manager::HousingMgr::sendWardLandInfo( Entity::Player& pla
|
||||||
|
|
||||||
auto& entry = wardInfoPacket->data().houseInfoEntry[ i ];
|
auto& entry = wardInfoPacket->data().houseInfoEntry[ i ];
|
||||||
|
|
||||||
// retail always sends the house price in this packet, even after the house has been sold
|
// retail always sends the house price in this packet, even after the house has been Sold
|
||||||
// so I guess we do the same
|
// so I guess we do the same
|
||||||
entry.housePrice = land->getCurrentPrice();
|
entry.housePrice = land->getCurrentPrice();
|
||||||
|
|
||||||
if( land->getState() == Common::HouseState::forSale )
|
if( land->getStatus() == Common::HouseStatus::ForSale )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( auto house = land->getHouse() )
|
if( auto house = land->getHouse() )
|
||||||
|
@ -564,6 +563,18 @@ bool Sapphire::World::Manager::HousingMgr::initHouseModels( Entity::Player& play
|
||||||
if( !preset )
|
if( !preset )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// remove preset item
|
||||||
|
Inventory::InventoryContainerPair foundItem;
|
||||||
|
if( !player.findFirstItemWithId( presetCatalogId, foundItem ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto item = getHousingItemFromPlayer( player, foundItem.first, foundItem.second );
|
||||||
|
if( !item )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// move preset item into ext appearance container
|
||||||
|
houseInventory[ InventoryType::HousingExteriorAppearance ]->setItem( HouseExteriorSlot::HousePermit, item );
|
||||||
|
|
||||||
// high iq shit
|
// high iq shit
|
||||||
auto invMap = std::map< uint16_t, std::map< uint32_t, int32_t > >
|
auto invMap = std::map< uint16_t, std::map< uint32_t, int32_t > >
|
||||||
{
|
{
|
||||||
|
@ -583,19 +594,19 @@ bool Sapphire::World::Manager::HousingMgr::initHouseModels( Entity::Player& play
|
||||||
InventoryType::HousingInteriorAppearance,
|
InventoryType::HousingInteriorAppearance,
|
||||||
{
|
{
|
||||||
// lobby/middle floor
|
// lobby/middle floor
|
||||||
{ HousingInteriorSlot::InteriorWall, preset->interiorWall },
|
{ HouseInteriorSlot::InteriorWall, preset->interiorWall },
|
||||||
{ HousingInteriorSlot::InteriorFloor, preset->interiorFlooring },
|
{ HouseInteriorSlot::InteriorFloor, preset->interiorFlooring },
|
||||||
{ HousingInteriorSlot::InteriorLight, preset->interiorLighting },
|
{ HouseInteriorSlot::InteriorLight, preset->interiorLighting },
|
||||||
|
|
||||||
// attic
|
// attic
|
||||||
{ HousingInteriorSlot::InteriorWall_Attic, preset->otherFloorWall },
|
{ HouseInteriorSlot::InteriorWall_Attic, preset->otherFloorWall },
|
||||||
{ HousingInteriorSlot::InteriorFloor_Attic, preset->otherFloorFlooring },
|
{ HouseInteriorSlot::InteriorFloor_Attic, preset->otherFloorFlooring },
|
||||||
{ HousingInteriorSlot::InteriorLight_Attic, preset->otherFloorLighting },
|
{ HouseInteriorSlot::InteriorLight_Attic, preset->otherFloorLighting },
|
||||||
|
|
||||||
// basement
|
// basement
|
||||||
{ HousingInteriorSlot::InteriorWall_Basement, preset->basementWall },
|
{ HouseInteriorSlot::InteriorWall_Basement, preset->basementWall },
|
||||||
{ HousingInteriorSlot::InteriorFloor_Basement, preset->basementFlooring },
|
{ HouseInteriorSlot::InteriorFloor_Basement, preset->basementFlooring },
|
||||||
{ HousingInteriorSlot::InteriorLight_Basement, preset->basementLighting },
|
{ HouseInteriorSlot::InteriorLight_Basement, preset->basementLighting },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -641,7 +652,7 @@ void Sapphire::World::Manager::HousingMgr::createHouse( Sapphire::HousePtr house
|
||||||
pDb->execute( stmt );
|
pDb->execute( stmt );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetItem )
|
void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetCatalogId )
|
||||||
{
|
{
|
||||||
auto hZone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() );
|
auto hZone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() );
|
||||||
|
|
||||||
|
@ -652,12 +663,9 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl
|
||||||
if( !pLand )
|
if( !pLand )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: when doing FC houses, look up the type from the original purchase and check perms from FC and set state accordingly
|
if( !hasPermission( player, *pLand, 0 ) )
|
||||||
if( pLand->getOwnerId() != player.getId() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: check if permit is in inventory and remove one
|
|
||||||
|
|
||||||
// create house
|
// create house
|
||||||
auto ident = pLand->getLandIdent();
|
auto ident = pLand->getLandIdent();
|
||||||
auto house = make_House( getNextHouseId(), pLand->getLandSetId(), ident,
|
auto house = make_House( getNextHouseId(), pLand->getLandSetId(), ident,
|
||||||
|
@ -666,12 +674,15 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl
|
||||||
pLand->setHouse( house );
|
pLand->setHouse( house );
|
||||||
|
|
||||||
// create inventory items
|
// create inventory items
|
||||||
if( !initHouseModels( player, pLand, presetItem ) )
|
if( !initHouseModels( player, pLand, presetCatalogId ) )
|
||||||
|
{
|
||||||
|
pLand->setHouse( nullptr );
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
createHouse( house );
|
createHouse( house );
|
||||||
|
|
||||||
pLand->setState( HouseState::privateHouse );
|
pLand->setStatus( HouseStatus::PrivateEstate );
|
||||||
pLand->setLandType( LandType::Private );
|
pLand->setLandType( LandType::Private );
|
||||||
hZone->sendLandUpdate( plotNum );
|
hZone->sendLandUpdate( plotNum );
|
||||||
|
|
||||||
|
@ -750,8 +761,7 @@ void Sapphire::World::Manager::HousingMgr::updateEstateGreeting( Entity::Player&
|
||||||
if( !land )
|
if( !land )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: implement proper permissions checks
|
if( !hasPermission( player, *land, 0 ) )
|
||||||
if( land->getOwnerId() != player.getId() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto house = land->getHouse();
|
auto house = land->getHouse();
|
||||||
|
@ -776,8 +786,7 @@ void Sapphire::World::Manager::HousingMgr::requestEstateEditGuestAccess( Entity:
|
||||||
if( !land )
|
if( !land )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: add proper permission check
|
if( !hasPermission( player, *land, 0 ) )
|
||||||
if( land->getOwnerId() != player.getId() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto packet = makeZonePacket< Server::FFXIVIpcHousingShowEstateGuestAccess >( player.getId() );
|
auto packet = makeZonePacket< Server::FFXIVIpcHousingShowEstateGuestAccess >( player.getId() );
|
||||||
|
@ -841,8 +850,7 @@ void Sapphire::World::Manager::HousingMgr::sendEstateInventory( Entity::Player&
|
||||||
if( !targetLand )
|
if( !targetLand )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: add proper permissions checks
|
if( !hasPermission( player, *targetLand, 0 ) )
|
||||||
if( targetLand->getOwnerId() != player.getId() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& containers = getEstateInventory( targetLand->getLandIdent() );
|
auto& containers = getEstateInventory( targetLand->getLandIdent() );
|
||||||
|
@ -913,7 +921,7 @@ void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr
|
||||||
{
|
{
|
||||||
for( auto& item : intContainer->second->getItemMap() )
|
for( auto& item : intContainer->second->getItemMap() )
|
||||||
{
|
{
|
||||||
house->setInteriorModel( static_cast< Common::HousingInteriorSlot >( item.first ),
|
house->setInteriorModel( static_cast< Common::HouseInteriorSlot >( item.first ),
|
||||||
getItemAdditionalData( item.second->getId() ) );
|
getItemAdditionalData( item.second->getId() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -980,12 +988,11 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity
|
||||||
if( !land )
|
if( !land )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: add proper permissions checks
|
if( !hasPermission( player, *land, 0 ) )
|
||||||
if( land->getOwnerId() != player.getId() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: check item position and make sure it's not outside the plot
|
// todo: check item position and make sure it's not outside the plot
|
||||||
// retail uses a radius based check
|
// anecdotal evidence on reddit seems to imply retail uses a radius based check
|
||||||
|
|
||||||
// unlink item
|
// unlink item
|
||||||
Inventory::HousingItemPtr item;
|
Inventory::HousingItemPtr item;
|
||||||
|
@ -995,9 +1002,9 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity
|
||||||
containerId == InventoryType::Bag2 ||
|
containerId == InventoryType::Bag2 ||
|
||||||
containerId == InventoryType::Bag3 )
|
containerId == InventoryType::Bag3 )
|
||||||
{
|
{
|
||||||
auto tmpItem = player.dropInventoryItem( static_cast< Common::InventoryType >( containerId ), slotId );
|
item = getHousingItemFromPlayer( player, static_cast< Common::InventoryType >( containerId ), slotId );
|
||||||
|
if( !item )
|
||||||
item = Inventory::make_HousingItem( tmpItem->getUId(), tmpItem->getId(), framework() );
|
return;
|
||||||
|
|
||||||
// set params
|
// set params
|
||||||
item->setPos( {
|
item->setPos( {
|
||||||
|
@ -1029,6 +1036,76 @@ void Sapphire::World::Manager::HousingMgr::reqPlaceHousingItem( Sapphire::Entity
|
||||||
player.sendUrgent( "An internal error occurred when placing the item." );
|
player.sendUrgent( "An internal error occurred when placing the item." );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sapphire::World::Manager::HousingMgr::reqPlaceItemInStore( Sapphire::Entity::Player& player, uint16_t landId,
|
||||||
|
uint16_t containerId, uint16_t slotId )
|
||||||
|
{
|
||||||
|
LandPtr land;
|
||||||
|
bool isOutside = false;
|
||||||
|
|
||||||
|
if( auto zone = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() ) )
|
||||||
|
{
|
||||||
|
land = zone->getLand( landId );
|
||||||
|
isOutside = true;
|
||||||
|
}
|
||||||
|
else if( auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( player.getCurrentZone() ) )
|
||||||
|
{
|
||||||
|
// todo: this whole process is retarded and needs to be fixed
|
||||||
|
// perhaps maintain a list of estates by ident inside housingmgr?
|
||||||
|
auto ident = zone->getLandIdent();
|
||||||
|
auto landSet = toLandSetId( ident.territoryTypeId, ident.wardNum );
|
||||||
|
|
||||||
|
land = getHousingZoneByLandSetId( landSet )->getLand( ident.landId );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !hasPermission( player, *land, 0 ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto invMgr = framework()->get< InventoryMgr >();
|
||||||
|
auto ident = land->getLandIdent();
|
||||||
|
auto& containers = getEstateInventory( ident );
|
||||||
|
|
||||||
|
if( isOutside )
|
||||||
|
{
|
||||||
|
auto& container = containers[ InventoryType::HousingExteriorStoreroom ];
|
||||||
|
|
||||||
|
auto freeSlot = container->getFreeSlot();
|
||||||
|
if( freeSlot == -1 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto item = getHousingItemFromPlayer( player, static_cast< Common::InventoryType >( containerId ), slotId );
|
||||||
|
if( !item )
|
||||||
|
return;
|
||||||
|
|
||||||
|
container->setItem( freeSlot, item );
|
||||||
|
invMgr->sendInventoryContainer( player, container );
|
||||||
|
invMgr->saveHousingContainer( ident, container );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( auto houseContainer : m_internalStoreroomContainers )
|
||||||
|
{
|
||||||
|
auto needle = containers.find( houseContainer );
|
||||||
|
if( needle == containers.end() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto container = needle->second;
|
||||||
|
auto freeSlot = container->getFreeSlot();
|
||||||
|
if( freeSlot == -1 )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto item = getHousingItemFromPlayer( player, static_cast< Common::InventoryType >( containerId ), slotId );
|
||||||
|
if( !item )
|
||||||
|
return;
|
||||||
|
|
||||||
|
container->setItem( freeSlot, item );
|
||||||
|
invMgr->sendInventoryContainer( player, container );
|
||||||
|
invMgr->saveHousingContainer( ident, container );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Sapphire::World::Manager::HousingMgr::placeExternalItem( Entity::Player& player,
|
bool Sapphire::World::Manager::HousingMgr::placeExternalItem( Entity::Player& player,
|
||||||
Inventory::HousingItemPtr item,
|
Inventory::HousingItemPtr item,
|
||||||
Common::LandIdent ident )
|
Common::LandIdent ident )
|
||||||
|
@ -1094,9 +1171,6 @@ bool Sapphire::World::Manager::HousingMgr::placeInteriorItem( Entity::Player& pl
|
||||||
// have a free slot
|
// have a free slot
|
||||||
container->setItem( freeSlot, item );
|
container->setItem( freeSlot, item );
|
||||||
|
|
||||||
// todo: see comment above in placeExternalItem where the same func is called
|
|
||||||
invMgr->saveItem( player, item );
|
|
||||||
|
|
||||||
// resend container
|
// resend container
|
||||||
invMgr->sendInventoryContainer( player, container );
|
invMgr->sendInventoryContainer( player, container );
|
||||||
invMgr->saveHousingContainer( ident, container );
|
invMgr->saveHousingContainer( ident, container );
|
||||||
|
@ -1163,8 +1237,7 @@ void Sapphire::World::Manager::HousingMgr::reqMoveHousingItem( Entity::Player& p
|
||||||
if( !land )
|
if( !land )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: proper perms checks
|
if( !hasPermission( player, *land, 0 ) )
|
||||||
if( land->getOwnerId() != player.getId() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: what happens when either of these fail? how does the server let the client know that the moment failed
|
// todo: what happens when either of these fail? how does the server let the client know that the moment failed
|
||||||
|
@ -1237,8 +1310,7 @@ bool Sapphire::World::Manager::HousingMgr::moveExternalItem( Entity::Player& pla
|
||||||
{
|
{
|
||||||
auto land = terri.getLand( ident.landId );
|
auto land = terri.getLand( ident.landId );
|
||||||
|
|
||||||
// todo: add proper perms check
|
if( !hasPermission( player, *land, 0 ) )
|
||||||
if( land->getOwnerId() != player.getId() )
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto& containers = getEstateInventory( ident );
|
auto& containers = getEstateInventory( ident );
|
||||||
|
@ -1285,8 +1357,7 @@ void Sapphire::World::Manager::HousingMgr::reqRemoveHousingItem( Sapphire::Entit
|
||||||
if( !land )
|
if( !land )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: proper perms checks
|
if( !hasPermission( player, *land, 0 ) )
|
||||||
if( land->getOwnerId() != player.getId() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
removeInternalItem( player, *terri, containerId, slot, sendToStoreroom );
|
removeInternalItem( player, *terri, containerId, slot, sendToStoreroom );
|
||||||
|
@ -1297,7 +1368,7 @@ void Sapphire::World::Manager::HousingMgr::reqRemoveHousingItem( Sapphire::Entit
|
||||||
if( !land )
|
if( !land )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( land->getOwnerId() != player.getId() )
|
if( !hasPermission( player, *land, 0 ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto containerType = static_cast< Common::InventoryType >( containerId );
|
auto containerType = static_cast< Common::InventoryType >( containerId );
|
||||||
|
@ -1313,24 +1384,24 @@ bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& p
|
||||||
{
|
{
|
||||||
auto& containers = getEstateInventory( terri.getLandIdent() );
|
auto& containers = getEstateInventory( terri.getLandIdent() );
|
||||||
|
|
||||||
// validate the container id first
|
int8_t containerIdx = 0;
|
||||||
// we also need the idx of the container so we can get the slot offset
|
|
||||||
bool foundContainer = false;
|
if( isPlacedItemsInventory( static_cast< Common::InventoryType >( containerId ) ) )
|
||||||
uint8_t containerIdx = 0;
|
{
|
||||||
for( auto cId : m_internalPlacedItemContainers )
|
for( auto cId : m_internalPlacedItemContainers )
|
||||||
{
|
{
|
||||||
if( containerId == cId )
|
if( containerId == cId )
|
||||||
{
|
|
||||||
foundContainer = true;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
containerIdx++;
|
containerIdx++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
containerIdx = -1;
|
||||||
|
|
||||||
if( !foundContainer )
|
// its possible to remove an item from any container in basically all these remove functions
|
||||||
return false;
|
// eg, remove a permit and reuse it elsewhere
|
||||||
|
// I'm not going to bother fixing it for now, but worth noting for future reference
|
||||||
|
|
||||||
auto needle = containers.find( containerId );
|
auto needle = containers.find( containerId );
|
||||||
if( needle == containers.end() )
|
if( needle == containers.end() )
|
||||||
|
@ -1384,8 +1455,11 @@ bool Sapphire::World::Manager::HousingMgr::removeInternalItem( Entity::Player& p
|
||||||
}
|
}
|
||||||
|
|
||||||
// despawn
|
// despawn
|
||||||
|
if( containerIdx != -1 )
|
||||||
|
{
|
||||||
auto arraySlot = ( containerIdx * 50 ) + slotId;
|
auto arraySlot = ( containerIdx * 50 ) + slotId;
|
||||||
terri.removeHousingObject( arraySlot );
|
terri.removeHousingObject( arraySlot );
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1406,11 +1480,13 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p
|
||||||
if( !item )
|
if( !item )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
bool shouldDespawnItem = containerType != InventoryType::HousingExteriorStoreroom;
|
||||||
|
|
||||||
auto invMgr = framework()->get< InventoryMgr >();
|
auto invMgr = framework()->get< InventoryMgr >();
|
||||||
|
|
||||||
if( sendToStoreroom )
|
if( sendToStoreroom )
|
||||||
{
|
{
|
||||||
auto& storeroomContainer = containers[ InventoryType::HousingExteriorStoreroom ];
|
auto& storeroomContainer = containers[ containerType ];
|
||||||
auto freeSlot = storeroomContainer->getFreeSlot();
|
auto freeSlot = storeroomContainer->getFreeSlot();
|
||||||
|
|
||||||
if( freeSlot == -1 )
|
if( freeSlot == -1 )
|
||||||
|
@ -1418,8 +1494,8 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p
|
||||||
|
|
||||||
sourceContainer->removeItem( slotId );
|
sourceContainer->removeItem( slotId );
|
||||||
invMgr->sendInventoryContainer( player, sourceContainer );
|
invMgr->sendInventoryContainer( player, sourceContainer );
|
||||||
invMgr->removeHousingItemPosition( *item );
|
|
||||||
invMgr->removeItemFromHousingContainer( land.getLandIdent(), sourceContainer->getId(), slotId );
|
invMgr->removeItemFromHousingContainer( land.getLandIdent(), sourceContainer->getId(), slotId );
|
||||||
|
invMgr->removeHousingItemPosition( *item );
|
||||||
|
|
||||||
storeroomContainer->setItem( freeSlot, item );
|
storeroomContainer->setItem( freeSlot, item );
|
||||||
invMgr->sendInventoryContainer( player, storeroomContainer );
|
invMgr->sendInventoryContainer( player, storeroomContainer );
|
||||||
|
@ -1441,6 +1517,7 @@ bool Sapphire::World::Manager::HousingMgr::removeExternalItem( Entity::Player& p
|
||||||
player.insertInventoryItem( containerPair.first, containerPair.second, item );
|
player.insertInventoryItem( containerPair.first, containerPair.second, item );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( shouldDespawnItem )
|
||||||
terri.despawnYardObject( land.getLandIdent().landId, slotId );
|
terri.despawnYardObject( land.getLandIdent().landId, slotId );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1482,8 +1559,7 @@ void Sapphire::World::Manager::HousingMgr::reqEstateExteriorRemodel( Sapphire::E
|
||||||
if( !land )
|
if( !land )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: proper perms checks
|
if( !hasPermission( player, *land, 0 ) )
|
||||||
if( land->getOwnerId() != player.getId() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& inv = getEstateInventory( land->getLandIdent() );
|
auto& inv = getEstateInventory( land->getLandIdent() );
|
||||||
|
@ -1513,8 +1589,7 @@ void Sapphire::World::Manager::HousingMgr::reqEstateInteriorRemodel( Sapphire::E
|
||||||
if( !land )
|
if( !land )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// todo: proper perms checks
|
if( !hasPermission( player, *land, 0 ) )
|
||||||
if( land->getOwnerId() != player.getId() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& inv = getEstateInventory( land->getLandIdent() );
|
auto& inv = getEstateInventory( land->getLandIdent() );
|
||||||
|
@ -1529,3 +1604,25 @@ void Sapphire::World::Manager::HousingMgr::reqEstateInteriorRemodel( Sapphire::E
|
||||||
auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateInternalAppearanceUI );
|
auto pkt = Server::makeActorControl143( player.getId(), Network::ActorControl::ShowEstateInternalAppearanceUI );
|
||||||
player.queuePacket( pkt );
|
player.queuePacket( pkt );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sapphire::World::Manager::HousingMgr::hasPermission( Sapphire::Entity::Player& player, Sapphire::Land& land,
|
||||||
|
uint32_t permission )
|
||||||
|
{
|
||||||
|
// todo: proper perms checks pls
|
||||||
|
if( land.getOwnerId() == player.getId() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// todo: check perms here
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sapphire::Inventory::HousingItemPtr Sapphire::World::Manager::HousingMgr::getHousingItemFromPlayer(
|
||||||
|
Entity::Player& player, Common::InventoryType type, uint8_t slot )
|
||||||
|
{
|
||||||
|
auto tmpItem = player.dropInventoryItem( type, slot );
|
||||||
|
if( !tmpItem )
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return Inventory::make_HousingItem( tmpItem->getUId(), tmpItem->getId(), framework() );
|
||||||
|
}
|
|
@ -31,8 +31,8 @@ namespace Sapphire::World::Manager
|
||||||
uint16_t m_landId;
|
uint16_t m_landId;
|
||||||
|
|
||||||
Common::LandType m_type;
|
Common::LandType m_type;
|
||||||
uint8_t m_size;
|
Common::HouseSize m_size;
|
||||||
uint8_t m_status;
|
Common::HouseStatus m_status;
|
||||||
|
|
||||||
uint64_t m_currentPrice;
|
uint64_t m_currentPrice;
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ namespace Sapphire::World::Manager
|
||||||
|
|
||||||
bool relinquishLand( Entity::Player& player, uint8_t plot );
|
bool relinquishLand( Entity::Player& player, uint8_t plot );
|
||||||
|
|
||||||
void buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetItem );
|
void buildPresetEstate( Entity::Player& player, uint8_t plotNum, uint32_t presetCatalogId );
|
||||||
|
|
||||||
void requestEstateRename( Entity::Player& player, const Common::LandIdent ident );
|
void requestEstateRename( Entity::Player& player, const Common::LandIdent ident );
|
||||||
|
|
||||||
|
@ -159,6 +159,8 @@ namespace Sapphire::World::Manager
|
||||||
void reqPlaceHousingItem( Entity::Player& player, uint16_t landId, uint16_t containerId, uint16_t slotId,
|
void reqPlaceHousingItem( Entity::Player& player, uint16_t landId, uint16_t containerId, uint16_t slotId,
|
||||||
Common::FFXIVARR_POSITION3 pos, float rotation );
|
Common::FFXIVARR_POSITION3 pos, float rotation );
|
||||||
|
|
||||||
|
void reqPlaceItemInStore( Entity::Player& player, uint16_t landId, uint16_t containerId, uint16_t slotId );
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Returns the equivalent YardObject for a HousingItem
|
* @brief Returns the equivalent YardObject for a HousingItem
|
||||||
* @param item The item to convert into a YardObject
|
* @param item The item to convert into a YardObject
|
||||||
|
@ -179,8 +181,12 @@ namespace Sapphire::World::Manager
|
||||||
|
|
||||||
void reqEstateInteriorRemodel( Entity::Player& player );
|
void reqEstateInteriorRemodel( Entity::Player& player );
|
||||||
|
|
||||||
|
bool hasPermission( Entity::Player& player, Land& land, uint32_t permission );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
Inventory::HousingItemPtr getHousingItemFromPlayer( Entity::Player& player, Common::InventoryType type, uint8_t slot );
|
||||||
|
|
||||||
ItemContainerPtr getFreeEstateInventorySlot( Common::LandIdent ident,
|
ItemContainerPtr getFreeEstateInventorySlot( Common::LandIdent ident,
|
||||||
Inventory::InventoryContainerPair& pair,
|
Inventory::InventoryContainerPair& pair,
|
||||||
Inventory::InventoryTypeList bagList );
|
Inventory::InventoryTypeList bagList );
|
||||||
|
|
159
src/world/Manager/MarketMgr.cpp
Normal file
159
src/world/Manager/MarketMgr.cpp
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
#include "MarketMgr.h"
|
||||||
|
|
||||||
|
#include <Exd/ExdDataGenerated.h>
|
||||||
|
#include <Framework.h>
|
||||||
|
#include <Logging/Logger.h>
|
||||||
|
|
||||||
|
#include <Network/CommonNetwork.h>
|
||||||
|
#include <Network/GamePacketNew.h>
|
||||||
|
#include <Network/PacketDef/Zone/ServerZoneDef.h>
|
||||||
|
|
||||||
|
#include "Actor/Player.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
using namespace Sapphire::Network::Packets;
|
||||||
|
|
||||||
|
Sapphire::World::Manager::MarketMgr::MarketMgr( Sapphire::FrameworkPtr pFw ) :
|
||||||
|
BaseManager( pFw )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::World::Manager::MarketMgr::init()
|
||||||
|
{
|
||||||
|
// Logger::info( "MarketMgr: warming up marketable item cache..." );
|
||||||
|
//
|
||||||
|
// // build item cache
|
||||||
|
// auto exdData = framework()->get< Sapphire::Data::ExdDataGenerated >();
|
||||||
|
// auto idList = exdData->getItemIdList();
|
||||||
|
//
|
||||||
|
// for( auto id : idList )
|
||||||
|
// {
|
||||||
|
// if( id > 10000 )
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// auto item = exdData->get< Sapphire::Data::Item >( id );
|
||||||
|
// if( !item )
|
||||||
|
// continue;
|
||||||
|
//
|
||||||
|
// if( item->isUntradable )
|
||||||
|
// continue;
|
||||||
|
//
|
||||||
|
// MarketableItem cacheEntry {};
|
||||||
|
// cacheEntry.catalogId = id;
|
||||||
|
// cacheEntry.itemSearchCategory = item->itemSearchCategory;
|
||||||
|
// cacheEntry.maxEquipLevel = item->levelEquip;
|
||||||
|
// cacheEntry.name = item->name;
|
||||||
|
// cacheEntry.classJob = item->classJobUse;
|
||||||
|
// cacheEntry.itemLevel = item->levelItem;
|
||||||
|
//
|
||||||
|
// m_marketItemCache.push_back( std::move( cacheEntry ) );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// std::sort( m_marketItemCache.begin(), m_marketItemCache.end(), []( const MarketableItem& a, const MarketableItem& b )
|
||||||
|
// {
|
||||||
|
// return a.itemLevel > b.itemLevel;
|
||||||
|
// } );
|
||||||
|
//
|
||||||
|
// Logger::info( "MarketMgr: Cached " + std::to_string( m_marketItemCache.size() ) + " marketable items" );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::World::Manager::MarketMgr::requestItemListingInfo( Sapphire::Entity::Player& player, uint32_t catalogId,
|
||||||
|
uint32_t requestId )
|
||||||
|
{
|
||||||
|
auto countPkt = makeZonePacket< Server::FFFXIVIpcMarketBoardItemListingCount >( player.getId() );
|
||||||
|
countPkt->data().quantity = 1 << 8;
|
||||||
|
countPkt->data().itemCatalogId = catalogId;
|
||||||
|
countPkt->data().requestId = requestId;
|
||||||
|
|
||||||
|
player.queuePacket( countPkt );
|
||||||
|
|
||||||
|
auto historyPkt = makeZonePacket< Server::FFXIVIpcMarketBoardItemListingHistory >( player.getId() );
|
||||||
|
historyPkt->data().itemCatalogId = catalogId;
|
||||||
|
historyPkt->data().itemCatalogId2 = catalogId;
|
||||||
|
|
||||||
|
std::string name = "fix game pls se :(((";
|
||||||
|
|
||||||
|
for( int i = 0; i < 10; i++ )
|
||||||
|
{
|
||||||
|
auto& listing = historyPkt->data().listing[ i ];
|
||||||
|
|
||||||
|
listing.itemCatalogId = catalogId;
|
||||||
|
listing.quantity = i + 1;
|
||||||
|
listing.purchaseTime = time( nullptr );
|
||||||
|
listing.salePrice = 69420420;
|
||||||
|
listing.isHq = 1;
|
||||||
|
listing.onMannequin = 1;
|
||||||
|
|
||||||
|
|
||||||
|
strcpy( listing.buyerName, name.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
player.queuePacket( historyPkt );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Sapphire::World::Manager::MarketMgr::searchMarketboard( Entity::Player& player, uint8_t itemSearchCategory,
|
||||||
|
uint8_t maxEquipLevel, uint8_t classJob,
|
||||||
|
const std::string_view& searchStr, uint32_t requestId,
|
||||||
|
uint32_t startIdx )
|
||||||
|
{
|
||||||
|
ItemSearchResultList resultList;
|
||||||
|
findItems( searchStr, itemSearchCategory, maxEquipLevel, classJob, resultList );
|
||||||
|
|
||||||
|
auto numResults = resultList.size();
|
||||||
|
|
||||||
|
if( startIdx > numResults )
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto endIdx = std::min< size_t >( startIdx + 20, numResults );
|
||||||
|
auto size = endIdx - startIdx;
|
||||||
|
|
||||||
|
auto resultPkt = makeZonePacket< Server::FFXIVIpcMarketBoardSearchResult >( player.getId() );
|
||||||
|
resultPkt->data().itemIndexStart = startIdx;
|
||||||
|
resultPkt->data().requestId = requestId;
|
||||||
|
|
||||||
|
for( auto i = 0; i < size; i++ )
|
||||||
|
{
|
||||||
|
auto& item = resultList.at( startIdx + i );
|
||||||
|
auto& data = resultPkt->data().items[ i ];
|
||||||
|
|
||||||
|
data.itemCatalogId = item.catalogId;
|
||||||
|
data.quantity = item.quantity;
|
||||||
|
data.demand = 420;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( size < 20 )
|
||||||
|
resultPkt->data().itemIndexEnd = 0;
|
||||||
|
else
|
||||||
|
resultPkt->data().itemIndexEnd = startIdx + 20;
|
||||||
|
|
||||||
|
player.queuePacket( resultPkt );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::World::Manager::MarketMgr::requestItemListings( Sapphire::Entity::Player& player, uint16_t catalogId )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::World::Manager::MarketMgr::findItems( const std::string_view& searchStr, uint8_t itemSearchCat,
|
||||||
|
uint8_t maxEquipLevel, uint8_t classJob,
|
||||||
|
Sapphire::World::Manager::MarketMgr::ItemSearchResultList& resultList )
|
||||||
|
{
|
||||||
|
for( const auto& item : m_marketItemCache )
|
||||||
|
{
|
||||||
|
if( item.itemSearchCategory != itemSearchCat )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( maxEquipLevel > 0 && item.maxEquipLevel > maxEquipLevel )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( classJob > 0 && item.classJob != classJob )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
resultList.push_back( { item.catalogId, 1 } );
|
||||||
|
}
|
||||||
|
}
|
58
src/world/Manager/MarketMgr.h
Normal file
58
src/world/Manager/MarketMgr.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef SAPPHIRE_MARKETMGR_H
|
||||||
|
#define SAPPHIRE_MARKETMGR_H
|
||||||
|
|
||||||
|
#include "ForwardsZone.h"
|
||||||
|
#include "BaseManager.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Sapphire::World::Manager
|
||||||
|
{
|
||||||
|
class MarketMgr : public Manager::BaseManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit MarketMgr( FrameworkPtr pFw );
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
void searchMarketboard( Entity::Player& player, uint8_t itemSearchCategory,
|
||||||
|
uint8_t maxEquipLevel, uint8_t classJob,
|
||||||
|
const std::string_view& searchStr, uint32_t requestId,
|
||||||
|
uint32_t startIdx );
|
||||||
|
|
||||||
|
void requestItemListingInfo( Entity::Player& player, uint32_t catalogId, uint32_t requestId );
|
||||||
|
|
||||||
|
void requestItemListings( Entity::Player& player, uint16_t catalogId );
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ItemSearchResult
|
||||||
|
{
|
||||||
|
uint32_t catalogId;
|
||||||
|
uint16_t quantity;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MarketableItem
|
||||||
|
{
|
||||||
|
uint32_t catalogId;
|
||||||
|
uint8_t itemSearchCategory;
|
||||||
|
uint8_t maxEquipLevel;
|
||||||
|
uint16_t itemLevel;
|
||||||
|
uint8_t classJob;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ItemSearchResultList = std::vector< ItemSearchResult >;
|
||||||
|
using MarketableItemCacheList = std::vector< MarketableItem >;
|
||||||
|
|
||||||
|
MarketableItemCacheList m_marketItemCache;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void findItems( const std::string_view& searchStr, uint8_t itemSearchCat, uint8_t maxEquipLevel, uint8_t classJob,
|
||||||
|
ItemSearchResultList& resultList );
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SAPPHIRE_MARKETMGR_H
|
|
@ -1,3 +1,6 @@
|
||||||
|
#ifndef SAPPHIRE_PLAYERMGR_H
|
||||||
|
#define SAPPHIRE_PLAYERMGR_H
|
||||||
|
|
||||||
#include "ForwardsZone.h"
|
#include "ForwardsZone.h"
|
||||||
#include "BaseManager.h"
|
#include "BaseManager.h"
|
||||||
|
|
||||||
|
@ -11,3 +14,5 @@ class PlayerMgr : public Manager::BaseManager
|
||||||
void movePlayerToLandDestination( Sapphire::Entity::Player& player, uint32_t landId, uint16_t param = 0 );
|
void movePlayerToLandDestination( Sapphire::Entity::Player& player, uint32_t landId, uint16_t param = 0 );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // SAPPHIRE_PLAYERMGR_H
|
|
@ -287,7 +287,7 @@ Sapphire::ZonePtr Sapphire::World::Manager::TerritoryMgr::createInstanceContent(
|
||||||
pTeri->name, pInstanceContent->name, instanceContentId, framework() );
|
pTeri->name, pInstanceContent->name, instanceContentId, framework() );
|
||||||
pZone->init();
|
pZone->init();
|
||||||
|
|
||||||
m_instanceContentToInstanceMap[ instanceContentId ][ pZone->getGuId() ] = pZone;
|
m_instanceContentIdToInstanceMap[ instanceContentId ][ pZone->getGuId() ] = pZone;
|
||||||
m_instanceIdToZonePtrMap[ pZone->getGuId() ] = pZone;
|
m_instanceIdToZonePtrMap[ pZone->getGuId() ] = pZone;
|
||||||
m_instanceZoneSet.insert( pZone );
|
m_instanceZoneSet.insert( pZone );
|
||||||
|
|
||||||
|
@ -381,7 +381,7 @@ bool Sapphire::World::Manager::TerritoryMgr::removeTerritoryInstance( uint32_t i
|
||||||
if( isInstanceContentTerritory( pZone->getTerritoryTypeId() ) )
|
if( isInstanceContentTerritory( pZone->getTerritoryTypeId() ) )
|
||||||
{
|
{
|
||||||
auto instance = std::dynamic_pointer_cast< InstanceContent >( pZone );
|
auto instance = std::dynamic_pointer_cast< InstanceContent >( pZone );
|
||||||
m_instanceContentToInstanceMap[ instance->getInstanceContentId() ].erase( pZone->getGuId() );
|
m_instanceContentIdToInstanceMap[ instance->getInstanceContentId() ].erase( pZone->getGuId() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_territoryTypeIdToInstanceGuidMap[ pZone->getTerritoryTypeId() ].erase( pZone->getGuId() );
|
m_territoryTypeIdToInstanceGuidMap[ pZone->getTerritoryTypeId() ].erase( pZone->getGuId() );
|
||||||
|
@ -486,8 +486,8 @@ void Sapphire::World::Manager::TerritoryMgr::updateTerritoryInstances( uint32_t
|
||||||
Sapphire::World::Manager::TerritoryMgr::InstanceIdList Sapphire::World::Manager::TerritoryMgr::getInstanceContentIdList( uint16_t instanceContentId ) const
|
Sapphire::World::Manager::TerritoryMgr::InstanceIdList Sapphire::World::Manager::TerritoryMgr::getInstanceContentIdList( uint16_t instanceContentId ) const
|
||||||
{
|
{
|
||||||
std::vector< uint32_t > idList;
|
std::vector< uint32_t > idList;
|
||||||
auto zoneMap = m_instanceContentToInstanceMap.find( instanceContentId );
|
auto zoneMap = m_instanceContentIdToInstanceMap.find( instanceContentId );
|
||||||
if( zoneMap == m_instanceContentToInstanceMap.end() )
|
if( zoneMap == m_instanceContentIdToInstanceMap.end() )
|
||||||
return idList;
|
return idList;
|
||||||
|
|
||||||
for( auto& entry : zoneMap->second )
|
for( auto& entry : zoneMap->second )
|
||||||
|
|
|
@ -176,7 +176,7 @@ namespace Sapphire::World::Manager
|
||||||
LandSetIdToZonePtrMap m_landSetIdToZonePtrMap;
|
LandSetIdToZonePtrMap m_landSetIdToZonePtrMap;
|
||||||
|
|
||||||
/*! map holding actual instances of InstanceContent */
|
/*! map holding actual instances of InstanceContent */
|
||||||
InstanceContentIdToInstanceMap m_instanceContentToInstanceMap;
|
InstanceContentIdToInstanceMap m_instanceContentIdToInstanceMap;
|
||||||
|
|
||||||
/*! flat map for easier lookup of instances by guid */
|
/*! flat map for easier lookup of instances by guid */
|
||||||
InstanceIdToZonePtrMap m_instanceIdToZonePtrMap;
|
InstanceIdToZonePtrMap m_instanceIdToZonePtrMap;
|
||||||
|
|
|
@ -123,6 +123,12 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH
|
||||||
|
|
||||||
setZoneHandler( ClientZoneIpcType::PerformNoteHandler, "PerformNoteHandler", &GameConnection::performNoteHandler );
|
setZoneHandler( ClientZoneIpcType::PerformNoteHandler, "PerformNoteHandler", &GameConnection::performNoteHandler );
|
||||||
|
|
||||||
|
setZoneHandler( ClientZoneIpcType::MarketBoardSearch, "MarketBoardSearch", &GameConnection::marketBoardSearch );
|
||||||
|
setZoneHandler( ClientZoneIpcType::MarketBoardRequestItemListingInfo, "MarketBoardRequestItemListingInfo",
|
||||||
|
&GameConnection::marketBoardRequestItemInfo );
|
||||||
|
setZoneHandler( ClientZoneIpcType::MarketBoardRequestItemListings, "MarketBoardRequestItemListings",
|
||||||
|
&GameConnection::marketBoardRequestItemListings );
|
||||||
|
|
||||||
setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler );
|
setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,12 @@ namespace Sapphire::Network
|
||||||
|
|
||||||
DECLARE_HANDLER( reqMoveHousingItem );
|
DECLARE_HANDLER( reqMoveHousingItem );
|
||||||
|
|
||||||
|
DECLARE_HANDLER( marketBoardSearch );
|
||||||
|
|
||||||
|
DECLARE_HANDLER( marketBoardRequestItemInfo );
|
||||||
|
|
||||||
|
DECLARE_HANDLER( marketBoardRequestItemListings );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
#include "Manager/DebugCommandMgr.h"
|
#include "Manager/DebugCommandMgr.h"
|
||||||
#include "Manager/EventMgr.h"
|
#include "Manager/EventMgr.h"
|
||||||
|
#include "Manager/MarketMgr.h"
|
||||||
|
|
||||||
#include "Action/Action.h"
|
#include "Action/Action.h"
|
||||||
#include "Action/ActionTeleport.h"
|
#include "Action/ActionTeleport.h"
|
||||||
|
@ -731,9 +732,15 @@ void Sapphire::Network::GameConnection::reqPlaceHousingItem( FrameworkPtr pFw,
|
||||||
const auto packet = ZoneChannelPacket< Client::FFXIVIpcReqPlaceHousingItem >( inPacket );
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcReqPlaceHousingItem >( inPacket );
|
||||||
const auto& data = packet.data();
|
const auto& data = packet.data();
|
||||||
|
|
||||||
|
if( data.shouldPlaceItem == 1 )
|
||||||
|
{
|
||||||
housingMgr->reqPlaceHousingItem( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId,
|
housingMgr->reqPlaceHousingItem( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId,
|
||||||
data.position, data.rotation );
|
data.position, data.rotation );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
housingMgr->reqPlaceItemInStore( player, data.landId, data.sourceInvContainerId, data.sourceInvSlotId );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Sapphire::Network::GameConnection::reqMoveHousingItem( FrameworkPtr pFw,
|
void Sapphire::Network::GameConnection::reqMoveHousingItem( FrameworkPtr pFw,
|
||||||
const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||||
|
@ -747,3 +754,40 @@ void Sapphire::Network::GameConnection::reqMoveHousingItem( FrameworkPtr pFw,
|
||||||
housingMgr->reqMoveHousingItem( player, data.ident, data.slot, data.pos, data.rotation );
|
housingMgr->reqMoveHousingItem( player, data.ident, data.slot, data.pos, data.rotation );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sapphire::Network::GameConnection::marketBoardSearch( FrameworkPtr pFw,
|
||||||
|
const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||||
|
Entity::Player& player )
|
||||||
|
{
|
||||||
|
auto marketMgr = pFw->get< MarketMgr >();
|
||||||
|
|
||||||
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardSearch >( inPacket );
|
||||||
|
const auto& data = packet.data();
|
||||||
|
|
||||||
|
std::string_view searchStr( data.searchStr );
|
||||||
|
|
||||||
|
marketMgr->searchMarketboard( player, data.itemSearchCategory, data.maxEquipLevel, data.classJobId, data.searchStr,
|
||||||
|
data.requestId, data.startIdx );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Network::GameConnection::marketBoardRequestItemInfo( FrameworkPtr pFw,
|
||||||
|
const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||||
|
Entity::Player& player )
|
||||||
|
{
|
||||||
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemListingInfo >( inPacket );
|
||||||
|
|
||||||
|
auto marketMgr = pFw->get< MarketMgr >();
|
||||||
|
|
||||||
|
marketMgr->requestItemListingInfo( player, packet.data().catalogId, packet.data().requestId );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Network::GameConnection::marketBoardRequestItemListings( FrameworkPtr pFw,
|
||||||
|
const Packets::FFXIVARR_PACKET_RAW& inPacket,
|
||||||
|
Entity::Player& player )
|
||||||
|
{
|
||||||
|
const auto packet = ZoneChannelPacket< Client::FFXIVIpcMarketBoardRequestItemListings >( inPacket );
|
||||||
|
|
||||||
|
auto marketMgr = pFw->get< MarketMgr >();
|
||||||
|
|
||||||
|
marketMgr->requestItemListings( player, packet.data().itemCatalogId );
|
||||||
|
}
|
|
@ -39,6 +39,7 @@
|
||||||
#include "Manager/InventoryMgr.h"
|
#include "Manager/InventoryMgr.h"
|
||||||
#include "Manager/EventMgr.h"
|
#include "Manager/EventMgr.h"
|
||||||
#include "Manager/ItemMgr.h"
|
#include "Manager/ItemMgr.h"
|
||||||
|
#include "Manager/MarketMgr.h"
|
||||||
|
|
||||||
using namespace Sapphire::World::Manager;
|
using namespace Sapphire::World::Manager;
|
||||||
|
|
||||||
|
@ -160,6 +161,15 @@ void Sapphire::World::ServerMgr::run( int32_t argc, char* argv[] )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto pMarketMgr = std::make_shared< Manager::MarketMgr >( framework() );
|
||||||
|
framework()->set< Manager::MarketMgr >( pMarketMgr );
|
||||||
|
|
||||||
|
if( !pMarketMgr->init() )
|
||||||
|
{
|
||||||
|
Logger::fatal( "Failed to setup market manager!" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
loadBNpcTemplates();
|
loadBNpcTemplates();
|
||||||
|
|
||||||
Network::HivePtr hive( new Network::Hive() );
|
Network::HivePtr hive( new Network::Hive() );
|
||||||
|
|
|
@ -19,7 +19,10 @@ Sapphire::House::House( uint32_t houseId, uint32_t landSetId, Common::LandIdent
|
||||||
m_estateName( estateName ),
|
m_estateName( estateName ),
|
||||||
m_estateComment( estateComment ),
|
m_estateComment( estateComment ),
|
||||||
m_pFw( pFw )
|
m_pFw( pFw )
|
||||||
{}
|
{
|
||||||
|
m_interiorModelCache.fill( 0 );
|
||||||
|
m_exteriorModelCache.fill( std::make_pair( 0, 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
Sapphire::House::~House() = default;
|
Sapphire::House::~House() = default;
|
||||||
|
|
||||||
|
@ -57,7 +60,7 @@ uint32_t Sapphire::House::getId() const
|
||||||
return m_houseId;
|
return m_houseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sapphire::House::HouseModelsArray const& Sapphire::House::getHouseModels() const
|
Sapphire::House::ExteriorModelsArray const& Sapphire::House::getHouseModels() const
|
||||||
{
|
{
|
||||||
return m_exteriorModelCache;
|
return m_exteriorModelCache;
|
||||||
}
|
}
|
||||||
|
@ -96,12 +99,12 @@ Sapphire::House::HousePart Sapphire::House::getExteriorModel( Sapphire::Common::
|
||||||
return m_exteriorModelCache[ slot ];
|
return m_exteriorModelCache[ slot ];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::House::setInteriorModel( Sapphire::Common::HousingInteriorSlot slot, uint32_t modelId )
|
void Sapphire::House::setInteriorModel( Sapphire::Common::HouseInteriorSlot slot, uint32_t modelId )
|
||||||
{
|
{
|
||||||
m_interiorModelCache[ slot ] = modelId;
|
m_interiorModelCache[ slot ] = modelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Sapphire::House::getInteriorModel( Sapphire::Common::HousingInteriorSlot slot )
|
uint32_t Sapphire::House::getInteriorModel( Sapphire::Common::HouseInteriorSlot slot )
|
||||||
{
|
{
|
||||||
return m_interiorModelCache[ slot ];
|
return m_interiorModelCache[ slot ];
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <Common.h>
|
#include <Common.h>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace Sapphire
|
namespace Sapphire
|
||||||
{
|
{
|
||||||
|
@ -17,7 +18,8 @@ namespace Sapphire
|
||||||
virtual ~House();
|
virtual ~House();
|
||||||
|
|
||||||
using HousePart = std::pair< uint32_t, uint16_t >;
|
using HousePart = std::pair< uint32_t, uint16_t >;
|
||||||
using HouseModelsArray = std::array< HousePart, 8 >;
|
using ExteriorModelsArray = std::array< HousePart, 8 >;
|
||||||
|
using InteriorModelsArray = std::array< uint32_t, 10 >;
|
||||||
|
|
||||||
//gerneral
|
//gerneral
|
||||||
uint32_t getLandSetId() const;
|
uint32_t getLandSetId() const;
|
||||||
|
@ -34,10 +36,10 @@ namespace Sapphire
|
||||||
void setExteriorModel( Common::HouseExteriorSlot slot, uint32_t modelId, uint16_t stain );
|
void setExteriorModel( Common::HouseExteriorSlot slot, uint32_t modelId, uint16_t stain );
|
||||||
HousePart getExteriorModel( Common::HouseExteriorSlot slot );
|
HousePart getExteriorModel( Common::HouseExteriorSlot slot );
|
||||||
|
|
||||||
void setInteriorModel( Common::HousingInteriorSlot slot, uint32_t modelId );
|
void setInteriorModel( Common::HouseInteriorSlot slot, uint32_t modelId );
|
||||||
uint32_t getInteriorModel( Common::HousingInteriorSlot slot );
|
uint32_t getInteriorModel( Common::HouseInteriorSlot slot );
|
||||||
|
|
||||||
HouseModelsArray const& getHouseModels() const;
|
ExteriorModelsArray const& getHouseModels() const;
|
||||||
|
|
||||||
void updateHouseDb();
|
void updateHouseDb();
|
||||||
|
|
||||||
|
@ -52,8 +54,8 @@ namespace Sapphire
|
||||||
uint64_t m_buildTime;
|
uint64_t m_buildTime;
|
||||||
bool m_hasAetheryte;
|
bool m_hasAetheryte;
|
||||||
|
|
||||||
HouseModelsArray m_exteriorModelCache;
|
ExteriorModelsArray m_exteriorModelCache;
|
||||||
uint32_t m_interiorModelCache[10];
|
InteriorModelsArray m_interiorModelCache;
|
||||||
|
|
||||||
std::string m_estateComment;
|
std::string m_estateComment;
|
||||||
std::string m_estateName;
|
std::string m_estateName;
|
||||||
|
|
|
@ -71,17 +71,24 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onPlayerZone
|
||||||
for( auto i = 0; i < 10; i++ )
|
for( auto i = 0; i < 10; i++ )
|
||||||
{
|
{
|
||||||
indoorInitPacket->data().indoorItems[ i ] = pHouse->getInteriorModel(
|
indoorInitPacket->data().indoorItems[ i ] = pHouse->getInteriorModel(
|
||||||
static_cast< Common::HousingInteriorSlot >( i ) );
|
static_cast< Common::HouseInteriorSlot >( i ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
player.queuePacket( indoorInitPacket );
|
player.queuePacket( indoorInitPacket );
|
||||||
|
|
||||||
|
bool isFcHouse = pLand->getStatus() == Common::HouseStatus::PrivateEstate;
|
||||||
|
|
||||||
auto yardPacketTotal = static_cast< uint8_t >( 2 + pLand->getSize() );
|
auto yardPacketTotal = static_cast< uint8_t >( 2 + pLand->getSize() );
|
||||||
for( uint8_t yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ )
|
for( uint8_t yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ )
|
||||||
{
|
{
|
||||||
auto objectInitPacket = makeZonePacket< Server::FFXIVIpcHousingObjectInitialize >( player.getId() );
|
auto objectInitPacket = makeZonePacket< Server::FFXIVIpcHousingObjectInitialize >( player.getId() );
|
||||||
memcpy( &objectInitPacket->data().landIdent, &m_landIdent, sizeof( Common::LandIdent ) );
|
memcpy( &objectInitPacket->data().landIdent, &m_landIdent, sizeof( Common::LandIdent ) );
|
||||||
|
|
||||||
|
if( isFcHouse )
|
||||||
|
objectInitPacket->data().u1 = 2; // 2 = actrl 0x400 will hide the fc door, otherwise it will stay there
|
||||||
|
else
|
||||||
objectInitPacket->data().u1 = 0;
|
objectInitPacket->data().u1 = 0;
|
||||||
|
|
||||||
objectInitPacket->data().u2 = 100;
|
objectInitPacket->data().u2 = 100;
|
||||||
objectInitPacket->data().packetNum = yardPacketNum;
|
objectInitPacket->data().packetNum = yardPacketNum;
|
||||||
objectInitPacket->data().packetTotal = yardPacketTotal;
|
objectInitPacket->data().packetTotal = yardPacketTotal;
|
||||||
|
@ -92,6 +99,8 @@ void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onPlayerZone
|
||||||
player.queuePacket( objectInitPacket );
|
player.queuePacket( objectInitPacket );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( isFcHouse )
|
||||||
|
player.queuePacket( Server::makeActorControl143( player.getId(), Network::ActorControl::HideAdditionalChambersDoor ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onUpdate( uint32_t currTime )
|
void Sapphire::World::Territory::Housing::HousingInteriorTerritory::onUpdate( uint32_t currTime )
|
||||||
|
|
|
@ -220,7 +220,7 @@ void Sapphire::HousingZone::sendLandSet( Entity::Player& player )
|
||||||
auto& landData = landsetInitializePacket->data().land[ count ];
|
auto& landData = landsetInitializePacket->data().land[ count ];
|
||||||
|
|
||||||
landData.plotSize = pLand->getSize();
|
landData.plotSize = pLand->getSize();
|
||||||
landData.houseState = pLand->getState();
|
landData.houseState = pLand->getStatus();
|
||||||
landData.iconAddIcon = pLand->getSharing();
|
landData.iconAddIcon = pLand->getSharing();
|
||||||
landData.fcId = pLand->getFcId();
|
landData.fcId = pLand->getFcId();
|
||||||
landData.fcIcon = pLand->getFcIcon();
|
landData.fcIcon = pLand->getFcIcon();
|
||||||
|
@ -256,7 +256,7 @@ void Sapphire::HousingZone::sendLandUpdate( uint8_t landId )
|
||||||
auto& landData = landUpdatePacket->data().land;
|
auto& landData = landUpdatePacket->data().land;
|
||||||
|
|
||||||
landData.plotSize = pLand->getSize();
|
landData.plotSize = pLand->getSize();
|
||||||
landData.houseState = pLand->getState();
|
landData.houseState = pLand->getStatus();
|
||||||
landData.iconAddIcon = pLand->getSharing();
|
landData.iconAddIcon = pLand->getSharing();
|
||||||
landData.fcId = pLand->getFcId();
|
landData.fcId = pLand->getFcId();
|
||||||
landData.fcIcon = pLand->getFcIcon();
|
landData.fcIcon = pLand->getFcIcon();
|
||||||
|
|
|
@ -54,7 +54,7 @@ Sapphire::Land::Land( uint16_t territoryTypeId, uint8_t wardNum, uint8_t landId,
|
||||||
|
|
||||||
Sapphire::Land::~Land() = default;
|
Sapphire::Land::~Land() = default;
|
||||||
|
|
||||||
void Sapphire::Land::init( Common::LandType type, uint8_t size, uint8_t state, uint32_t currentPrice,
|
void Sapphire::Land::init( Common::LandType type, Common::HouseSize size, Common::HouseStatus state, uint32_t currentPrice,
|
||||||
uint64_t ownerId, uint64_t houseId )
|
uint64_t ownerId, uint64_t houseId )
|
||||||
{
|
{
|
||||||
m_type = type;
|
m_type = type;
|
||||||
|
@ -84,12 +84,12 @@ uint32_t Sapphire::Land::getMaxPrice() const
|
||||||
}
|
}
|
||||||
|
|
||||||
//Primary State
|
//Primary State
|
||||||
void Sapphire::Land::setSize( uint8_t size )
|
void Sapphire::Land::setSize( Common::HouseSize size )
|
||||||
{
|
{
|
||||||
m_size = size;
|
m_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Land::setState( uint8_t state )
|
void Sapphire::Land::setStatus( Common::HouseStatus state )
|
||||||
{
|
{
|
||||||
m_state = state;
|
m_state = state;
|
||||||
}
|
}
|
||||||
|
@ -104,12 +104,12 @@ void Sapphire::Land::setLandType( Common::LandType type )
|
||||||
m_type = type;
|
m_type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Sapphire::Land::getSize() const
|
Sapphire::Common::HouseSize Sapphire::Land::getSize() const
|
||||||
{
|
{
|
||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Sapphire::Land::getState() const
|
Sapphire::Common::HouseStatus Sapphire::Land::getStatus() const
|
||||||
{
|
{
|
||||||
return m_state;
|
return m_state;
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ void Sapphire::Land::updateLandDb()
|
||||||
|
|
||||||
void Sapphire::Land::update( uint32_t currTime )
|
void Sapphire::Land::update( uint32_t currTime )
|
||||||
{
|
{
|
||||||
if( getState() == HouseState::forSale )
|
if( getStatus() == HouseStatus::ForSale )
|
||||||
{
|
{
|
||||||
if( m_nextDrop < currTime && m_minPrice < m_currentPrice )
|
if( m_nextDrop < currTime && m_minPrice < m_currentPrice )
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,20 +18,20 @@ namespace Sapphire
|
||||||
Land( uint16_t zoneId, uint8_t wardNum, uint8_t landId, uint32_t landSetId,
|
Land( uint16_t zoneId, uint8_t wardNum, uint8_t landId, uint32_t landSetId,
|
||||||
Sapphire::Data::HousingLandSetPtr info, FrameworkPtr pFw );
|
Sapphire::Data::HousingLandSetPtr info, FrameworkPtr pFw );
|
||||||
virtual ~Land();
|
virtual ~Land();
|
||||||
void init( Common::LandType type, uint8_t size, uint8_t state, uint32_t currentPrice, uint64_t ownerId, uint64_t houseId );
|
void init( Common::LandType type, Common::HouseSize size, Common::HouseStatus state, uint32_t currentPrice, uint64_t ownerId, uint64_t houseId );
|
||||||
|
|
||||||
using LandInventoryMap = std::unordered_map< uint16_t, ItemContainerPtr >;
|
using LandInventoryMap = std::unordered_map< uint16_t, ItemContainerPtr >;
|
||||||
using InvMaxItemsPair = std::pair< uint16_t, uint16_t >;
|
using InvMaxItemsPair = std::pair< uint16_t, uint16_t >;
|
||||||
|
|
||||||
//Primary state
|
//Primary state
|
||||||
void setSize( uint8_t size );
|
void setSize( Common::HouseSize size );
|
||||||
void setState( uint8_t state );
|
void setStatus( Common::HouseStatus state );
|
||||||
void setSharing( uint8_t state );
|
void setSharing( uint8_t state );
|
||||||
void setLandType( Common::LandType type );
|
void setLandType( Common::LandType type );
|
||||||
|
|
||||||
//Gerneral
|
//Gerneral
|
||||||
uint8_t getSize() const;
|
Common::HouseSize getSize() const;
|
||||||
uint8_t getState() const;
|
Common::HouseStatus getStatus() const;
|
||||||
uint8_t getSharing() const;
|
uint8_t getSharing() const;
|
||||||
uint32_t getLandSetId() const;
|
uint32_t getLandSetId() const;
|
||||||
Common::LandType getLandType() const;
|
Common::LandType getLandType() const;
|
||||||
|
@ -71,8 +71,8 @@ namespace Sapphire
|
||||||
Common::LandIdent m_landIdent;
|
Common::LandIdent m_landIdent;
|
||||||
|
|
||||||
uint32_t m_landSetId;
|
uint32_t m_landSetId;
|
||||||
uint8_t m_size;
|
Common::HouseSize m_size;
|
||||||
uint8_t m_state;
|
Common::HouseStatus m_state;
|
||||||
Common::LandType m_type;
|
Common::LandType m_type;
|
||||||
uint8_t m_iconAddIcon;
|
uint8_t m_iconAddIcon;
|
||||||
uint32_t m_fcId; // unclear, may be wrong
|
uint32_t m_fcId; // unclear, may be wrong
|
||||||
|
|
|
@ -715,7 +715,6 @@ void Sapphire::Zone::registerEObj( Entity::EventObjectPtr object )
|
||||||
if( !object )
|
if( !object )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
object->setId( getNextEObjId() );
|
|
||||||
pushActor( object );
|
pushActor( object );
|
||||||
|
|
||||||
m_eventObjects[ object->getId() ] = object;
|
m_eventObjects[ object->getId() ] = object;
|
||||||
|
|
Loading…
Add table
Reference in a new issue