1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-27 14:57:44 +00:00

Merge pull request #458 from NotAdam/housing

housing appearance is now loaded from inventory, startup query optimisations again
This commit is contained in:
Mordred 2018-12-22 10:46:40 +01:00 committed by GitHub
commit 18fd18ebe0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 387 additions and 243 deletions

View file

@ -55,4 +55,8 @@ 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/zone.ini
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

View file

@ -197,11 +197,14 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
CONNECTION_BOTH );
prepareStatement( HOUSING_HOUSE_UP,
"UPDATE house SET BuildTime = ?, Aetheryte = ?, Comment = ?, HouseName = ?, Endorsements = ?, HousePartModels = ?, HousePartColours = ?, HouseInteriorModels = ? WHERE HouseId = ?;",
"UPDATE house SET BuildTime = ?, Aetheryte = ?, Comment = ?, HouseName = ?, Endorsements = ? WHERE HouseId = ?;",
CONNECTION_BOTH );
prepareStatement( LAND_INV_SEL_ALL,
"SELECT LandIdent, ContainerId, ItemId, SlotId FROM houseiteminventory;",
"SELECT houseiteminventory.*, charaglobalitem.catalogId, charaglobalitem.stain, charaglobalitem.CharacterId "
"FROM houseiteminventory "
"LEFT JOIN charaglobalitem "
"ON houseiteminventory.ItemId = charaglobalitem.itemId;",
CONNECTION_BOTH );
prepareStatement( LAND_INV_SEL_HOUSE,
@ -212,6 +215,13 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"SELECT * FROM land WHERE LandSetId = ?;",
CONNECTION_SYNC );
prepareStatement( LAND_SEL_ALL,
"SELECT land.*, house.Welcome, house.Aetheryte, house.Comment, house.HouseName, house.BuildTime, house.Endorsements "
"FROM land "
"LEFT JOIN house "
"ON land.HouseId = house.HouseId;",
CONNECTION_SYNC );
/*prepareStatement( LAND_INS,
"INSERT INTO land ( LandSetId ) VALUES ( ? );",
CONNECTION_BOTH );

View file

@ -80,6 +80,7 @@ namespace Sapphire::Db
LAND_INS,
LAND_SEL,
LAND_SEL_ALL,
LAND_UP,
LANDSET_SEL,
HOUSING_HOUSE_INS,

View file

@ -25,6 +25,8 @@
#include "ServerMgr.h"
#include "Territory/House.h"
#include "InventoryMgr.h"
#include "Inventory/Item.h"
#include "Inventory/ItemContainer.h"
using namespace Sapphire::Common;
using namespace Sapphire::Network;
@ -33,22 +35,133 @@ using namespace Sapphire::Network::Packets::Server;
extern Sapphire::Framework g_fw;
Sapphire::World::Manager::HousingMgr::HousingMgr()
{
}
Sapphire::World::Manager::HousingMgr::~HousingMgr()
{
}
Sapphire::World::Manager::HousingMgr::HousingMgr() = default;
Sapphire::World::Manager::HousingMgr::~HousingMgr() = default;
bool Sapphire::World::Manager::HousingMgr::init()
{
auto log = g_fw.get< Sapphire::Logger >();
log->info( "HousingMgr: Caching housing land init data" );
//LAND_SEL_ALL
// 18 wards per territory, 4 territories
m_landCache.reserve( 18 * 4 );
loadLandCache();
log->debug( "HousingMgr: Checking land counts" );
uint32_t houseCount = 0;
for( auto& landSet : m_landCache )
{
auto count = landSet.second.size();
houseCount += count;
if( landSet.second.size() != 60 )
{
log->fatal( "LandSet " + std::to_string( landSet.first ) + " is missing land entries. Only have " + std::to_string( count ) + " land entries." );
return false;
}
}
log->info( "HousingMgr: Cached " + std::to_string( houseCount ) + " houses" );
/////
if( !loadEstateInventories() )
return false;
return true;
}
bool Sapphire::World::Manager::HousingMgr::loadEstateInventories()
{
auto log = g_fw.get< Sapphire::Logger >();
log->info( "HousingMgr: Loading inventories for estates" );
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
auto stmt = pDb->getPreparedStatement( Db::LAND_INV_SEL_ALL );
auto res = pDb->query( stmt );
uint32_t itemCount = 0;
while( res->next() )
{
//uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t model2, bool isHq
uint64_t ident = res->getUInt64( "LandIdent" );
uint16_t containerId = res->getUInt16( "ContainerId" );
uint64_t itemId = res->getUInt64( "ItemId" );
uint16_t slot = res->getUInt16( "SlotId" );
uint32_t catalogId = res->getUInt( "catalogId" );
uint8_t stain = res->getUInt8( "stain" );
uint64_t characterId = res->getUInt64( "CharacterId" );
auto item = make_Item( itemId, catalogId, 0, 0, 0 );
item->setStain( stain );
// todo: need to set the owner character id on the item
ContainerIdToContainerMap& estateInv = m_estateInventories[ ident ];
// check if containerId exists
auto container = estateInv.find( containerId );
if( container == estateInv.end() )
{
// create container
// todo: how to handle this max slot stuff? override it on land init?
auto ic = make_ItemContainer( containerId, 400, "houseiteminventory", true );
ic->setItem( slot, item );
estateInv[ containerId ] = ic;
}
else
container->second->setItem( slot, item );
itemCount++;
}
log->debug( "HousingMgr: Loaded " + std::to_string( itemCount ) + " inventory items" );
return true;
}
void Sapphire::World::Manager::HousingMgr::loadLandCache()
{
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
auto stmt = pDb->getPreparedStatement( Db::LAND_SEL_ALL );
auto res = pDb->query( stmt );
while( res->next() )
{
LandCacheEntry entry;
// land stuff
entry.m_landSetId = res->getUInt64( "LandSetId" );
entry.m_landId = res->getUInt64( "LandId" );
entry.m_type = static_cast< Common::LandType >( res->getUInt( "Type" ) );
entry.m_size = res->getUInt8( "Size" );
entry.m_status = res->getUInt8( "Status" );
entry.m_currentPrice = res->getUInt64( "LandPrice" );
entry.m_updateTime = res->getUInt64( "UpdateTime" );
entry.m_ownerId = res->getUInt64( "OwnerId" );
entry.m_houseId = res->getUInt64( "HouseId" );
// house stuff
entry.m_estateWelcome = res->getString( "Welcome" );
entry.m_estateComment = res->getString( "Comment" );
entry.m_estateName = res->getString( "HouseName" );
entry.m_buildTime = res->getUInt64( "BuildTime" );
entry.m_endorsements = res->getUInt64( "Endorsements" );
m_landCache[ entry.m_landSetId ].push_back( entry );
}
}
uint32_t Sapphire::World::Manager::HousingMgr::toLandSetId( uint16_t territoryTypeId, uint8_t wardId ) const
{
return ( static_cast< uint32_t >( territoryTypeId ) << 16 ) | wardId;
@ -472,7 +585,8 @@ Sapphire::Common::LandIdent Sapphire::World::Manager::HousingMgr::clientTriggerP
return ident;
}
void Sapphire::World::Manager::HousingMgr::sendHousingInventory( Entity::Player& player, uint16_t inventoryType, uint8_t plotNum )
void Sapphire::World::Manager::HousingMgr::sendEstateInventory( Entity::Player& player, uint16_t inventoryType,
uint8_t plotNum )
{
Sapphire::LandPtr targetLand;
@ -510,10 +624,72 @@ void Sapphire::World::Manager::HousingMgr::sendHousingInventory( Entity::Player&
if( targetLand->getOwnerId() != player.getId() )
return;
auto container = targetLand->getItemContainer( inventoryType );
auto container = getEstateInventory( targetLand->getLandIdent() )[ inventoryType ];
if( !container )
return;
auto invMgr = g_fw.get< Manager::InventoryMgr >();
invMgr->sendInventoryContainer( player, container );
}
}
const Sapphire::World::Manager::HousingMgr::LandSetLandCacheMap&
Sapphire::World::Manager::HousingMgr::getLandCacheMap()
{
return m_landCache;
}
Sapphire::World::Manager::HousingMgr::LandIdentToInventoryContainerMap&
Sapphire::World::Manager::HousingMgr::getEstateInventories()
{
return m_estateInventories;
}
Sapphire::World::Manager::HousingMgr::ContainerIdToContainerMap&
Sapphire::World::Manager::HousingMgr::getEstateInventory( uint64_t ident )
{
auto map = m_estateInventories.find( ident );
assert( map != m_estateInventories.end() );
return map->second;
}
Sapphire::World::Manager::HousingMgr::ContainerIdToContainerMap&
Sapphire::World::Manager::HousingMgr::getEstateInventory( Sapphire::Common::LandIdent ident )
{
auto u64ident = *reinterpret_cast< uint64_t* >( &ident );
return getEstateInventory( u64ident );
}
void Sapphire::World::Manager::HousingMgr::updateHouseModels( Sapphire::HousePtr house )
{
assert( house );
auto getItemData = []( uint32_t itemId )
{
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
auto info = pExdData->get< Sapphire::Data::Item >( itemId );
return info->additionalData;
};
auto containers = getEstateInventory( house->getLandIdent() );
auto extContainer = containers.find( static_cast< uint16_t >( InventoryType::HousingOutdoorAppearance ) );
if( extContainer != containers.end() )
{
for( auto& item : extContainer->second->getItemMap() )
{
house->setHousePart( static_cast< Common::HousePartSlot >( item.first ), getItemData( item.second->getId() ) );
}
}
auto intContainer = containers.find( static_cast< uint16_t >( InventoryType::HousingInteriorAppearance ) );
if( intContainer != containers.end() )
{
for( auto& item : intContainer->second->getItemMap() )
{
house->setHouseInteriorPart( static_cast< Common::HousingInteriorSlot >( item.first ), getItemData( item.second->getId() ) );
}
}
}

View file

@ -17,6 +17,47 @@ namespace Sapphire::World::Manager
{
public:
struct LandCacheEntry
{
// land table
uint64_t m_landSetId;
uint64_t m_landId;
Common::LandType m_type;
uint8_t m_size;
uint8_t m_status;
uint64_t m_currentPrice;
uint64_t m_updateTime;
uint64_t m_ownerId;
uint64_t m_houseId;
// house table
std::string m_estateWelcome;
std::string m_estateComment;
std::string m_estateName;
uint64_t m_buildTime;
uint64_t m_endorsements;
};
/*!
* @brief Maps land id to a list of cached entries
*/
using LandSetLandCacheMap = std::unordered_map< uint64_t, std::vector< LandCacheEntry > >;
/*!
* @brief Maps container IDs to their relevant ItemContainerPtr
*/
using ContainerIdToContainerMap = std::unordered_map< uint16_t, ItemContainerPtr >;
/*!
* @brief Maps land idents to a container containing ItemContainerPtrs
*/
using LandIdentToInventoryContainerMap = std::unordered_map< uint64_t, ContainerIdToContainerMap >;
HousingMgr();
virtual ~HousingMgr();
@ -50,12 +91,52 @@ namespace Sapphire::World::Manager
void sendEstateGreeting( Entity::Player& player, const Common::LandIdent ident );
/*!
* @brief Updates the cached models on a house from the relevant apperance inventories.
* Does not send the subsequent update to clients.
*
* @param house The house to update the models for
*/
void updateHouseModels( HousePtr house );
/*!
* @brief Sends the house inventory for the specified type to a player.
*
* This enforces permissions on the inventory too so random players can't request a houses items
* This enforces permissions on the inventory too so random players can't request an estates items
*/
void sendHousingInventory( Entity::Player& player, uint16_t inventoryType, uint8_t plotNum );
void sendEstateInventory( Entity::Player& player, uint16_t inventoryType, uint8_t plotNum );
/*!
* @brief Get the land & house data that was cached on world startup.
* @return
*/
const LandSetLandCacheMap& getLandCacheMap();
/*!
* @brief Get all loaded inventories for housing estates
* @return
*/
LandIdentToInventoryContainerMap& getEstateInventories();
/*!
* @brief Get an estate inventory for a specific estate
* @param ident LandIdent for the specified estate
* @return A map containing container ids to ItemContainerPtr
*/
ContainerIdToContainerMap& getEstateInventory( uint64_t ident );
/*!
* @brief Get an estate inventory for a specific estate
* @param ident LandIdent for the specified estate
* @return A map containing container ids to ItemContainerPtr
*/
ContainerIdToContainerMap& getEstateInventory( Common::LandIdent ident );
private:
void loadLandCache();
bool loadEstateInventories();
LandSetLandCacheMap m_landCache;
LandIdentToInventoryContainerMap m_estateInventories;
};

View file

@ -434,7 +434,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX
if( param2 == 1 )
inventoryType = Common::InventoryType::HousingOutdoorStoreroom;
housingMgr->sendHousingInventory( player, inventoryType, plot );
housingMgr->sendEstateInventory( player, inventoryType, plot );
break;
}

View file

@ -151,6 +151,12 @@ void Sapphire::ServerMgr::run( int32_t argc, char* argv[] )
auto pTeriMgr = std::make_shared< Manager::TerritoryMgr >();
auto pHousingMgr = std::make_shared< Manager::HousingMgr >();
g_fw.set< Manager::HousingMgr >( pHousingMgr );
if( !pHousingMgr->init() )
{
pLog->fatal( "Failed to setup housing!" );
return;
}
g_fw.set< Manager::TerritoryMgr >( pTeriMgr );
if( !pTeriMgr->init() )
{

View file

@ -13,104 +13,35 @@
extern Sapphire::Framework g_fw;
Sapphire::House::House( uint32_t houseId, uint32_t landSetId, Common::LandIdent ident ) :
Sapphire::House::House( uint32_t houseId, uint32_t landSetId, Common::LandIdent ident, const std::string& estateName,
const std::string& estateComment ) :
m_houseId( houseId ),
m_landSetId( landSetId ),
m_landIdent( ident )
m_landIdent( ident ),
m_estateName( estateName ),
m_estateComment( estateComment )
{
auto pDB = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
// todo: convert to prepared statement
auto res = pDB->query( "SELECT * FROM house WHERE HouseId = " + std::to_string( houseId ) );
if( !res->next() )
{
g_fw.get< Sapphire::Logger >()->info( "Creating house House#" + std::to_string( houseId ) + " in LandSet#" + std::to_string( landSetId ) );
auto stmt = pDB->getPreparedStatement( Db::HOUSING_HOUSE_INS );
stmt->setUInt( 1, m_landSetId );
stmt->setUInt( 2, m_houseId );
pDB->execute( stmt );
// todo: make this nicer/configurable?
m_houseName = "Estate #" + std::to_string( m_landIdent.landId + 1 );
}
else
{
m_estateMessage = res->getString( "Comment" );
m_houseName = res->getString( "HouseName" );
auto housePartModels = res->getBlobVector( "HousePartModels" );
auto housePartColours = res->getBlobVector( "HousePartColours" );
auto models = reinterpret_cast< uint32_t* >( &housePartModels[ 0 ] );
for( auto i = 0; i < 8; i++ )
{
m_houseParts[ i ] = { models[ i ], housePartColours[ i ] };
}
auto houseInteriorModels = res->getBlobVector( "HouseInteriorModels" );
auto interiorModels = reinterpret_cast< uint32_t* >( &houseInteriorModels[ 0 ] );
for( auto i = 0; i < 10; i++ )
{
m_houseInteriorParts[ i ] = interiorModels[ i ];
}
}
}
Sapphire::House::~House()
{
}
Sapphire::House::~House() = default;
void Sapphire::House::updateHouseDb()
{
auto pDB = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
// BuildTime = 1, Aetheryte = 2, Comment = 3, HouseName = 4, Endorsements = 5,
// HousePartModels = 6, HousePartColours = 7, HouseId = 8
// BuildTime = 1, Aetheryte = 2, Comment = 3, HouseName = 4, Endorsements = 5, HouseId = 6
auto stmt = pDB->getPreparedStatement( Db::HOUSING_HOUSE_UP );
stmt->setUInt( 9, m_houseId );
stmt->setUInt( 6, m_houseId );
stmt->setInt64( 1, m_buildTime );
stmt->setInt( 2, 0 );
stmt->setString( 3, m_estateMessage );
stmt->setString( 4, m_houseName );
stmt->setString( 3, m_estateComment );
stmt->setString( 4, m_estateName );
stmt->setUInt64( 5, 0 );
std::vector< uint32_t > models;
std::vector< uint8_t > colours;
for( auto i = 0; i < 8; i++ )
{
auto& part = m_houseParts[ i ];
models.push_back( part.first );
colours.push_back( part.second );
}
// todo: this is shit
std::vector< uint8_t > tmpModels( models.size() * 4 );
memcpy( tmpModels.data(), models.data(), tmpModels.size() );
stmt->setBinary( 6, tmpModels );
stmt->setBinary( 7, colours );
models.clear();
for( auto i = 0; i < 10; i++ )
{
models.push_back( m_houseInteriorParts[ i ] );
}
std::vector< uint8_t > tmp2Models( models.size() * 4 );
memcpy( tmp2Models.data(), models.data(), tmp2Models.size() );
stmt->setBinary( 8, tmp2Models );
pDB->execute( stmt );
}
@ -131,59 +62,59 @@ uint32_t Sapphire::House::getHouseId() const
uint8_t Sapphire::House::getHousePartColor( Common::HousePartSlot slot ) const
{
return m_houseParts[ slot ].second;
return m_houseModelsCache[ slot ].second;
}
uint32_t Sapphire::House::getHouseInteriorPart( Common::HousingInteriorSlot slot ) const
{
return m_houseInteriorParts[ slot ];
return m_houseInteriorModels[ slot ];
}
void Sapphire::House::setHousePart( Common::HousePartSlot slot, uint32_t id )
{
m_houseParts[ slot ].first = id;
m_houseModelsCache[ slot ].first = id;
}
void Sapphire::House::setHousePartColor( Common::HousePartSlot slot, uint32_t id )
{
m_houseParts[ slot ].second = id;
m_houseModelsCache[ slot ].second = id;
}
void Sapphire::House::setHouseInteriorPart( Common::HousingInteriorSlot slot, uint32_t id )
{
m_houseInteriorParts[ slot ] = id;
m_houseInteriorModels[ slot ] = id;
}
uint32_t Sapphire::House::getHousePart( Common::HousePartSlot slot ) const
{
return m_houseParts[ slot ].first;
return m_houseModelsCache[ slot ].first;
}
Sapphire::House::HousePartsArray const& Sapphire::House::getHouseParts() const
Sapphire::House::HouseModelsArray const& Sapphire::House::getHouseModels() const
{
return m_houseParts;
return m_houseModelsCache;
}
const std::string& Sapphire::House::getHouseName() const
{
return m_houseName;
return m_estateName;
}
const std::string& Sapphire::House::getHouseGreeting() const
{
return m_estateMessage;
return m_estateComment;
}
void Sapphire::House::setHouseGreeting( const std::string& greeting )
{
m_estateMessage = greeting;
m_estateComment = greeting;
updateHouseDb();
}
void Sapphire::House::setHouseName( const std::string& name )
{
m_houseName = name;
m_estateName = name;
updateHouseDb();
}

View file

@ -12,11 +12,12 @@ namespace Sapphire
class House
{
public:
House( uint32_t houseId, uint32_t landSetId, Common::LandIdent ident );
House( uint32_t houseId, uint32_t landSetId, Common::LandIdent ident, const std::string& estateName,
const std::string& estateComment );
virtual ~House();
using HousePart = std::pair< uint32_t, uint8_t >;
using HousePartsArray = std::array< HousePart, 8 >;
using HouseModelsArray = std::array< HousePart, 8 >;
//gerneral
uint32_t getLandSetId() const;
@ -37,7 +38,7 @@ namespace Sapphire
uint8_t getHousePartColor( Common::HousePartSlot slot ) const;
uint32_t getHouseInteriorPart( Common::HousingInteriorSlot slot ) const;
HousePartsArray const& getHouseParts() const;
HouseModelsArray const& getHouseModels() const;
void updateHouseDb();
@ -48,11 +49,11 @@ namespace Sapphire
uint64_t m_buildTime;
HousePartsArray m_houseParts;
uint32_t m_houseInteriorParts[10];
HouseModelsArray m_houseModelsCache;
uint32_t m_houseInteriorModels[10];
std::string m_estateMessage;
std::string m_houseName;
std::string m_estateComment;
std::string m_estateName;
};
}

View file

@ -64,40 +64,37 @@ bool Sapphire::HousingZone::init()
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
auto info = pExdData->get< Sapphire::Data::HousingLandSet >( housingIndex );
auto stmt = pDb->getPreparedStatement( Db::LANDSET_SEL );
stmt->setUInt64( 1, m_landSetId );
auto res = pDb->query( stmt );
auto housingMgr = g_fw.get< World::Manager::HousingMgr >();
auto landCache = housingMgr->getLandCacheMap();
std::vector< QueuedLandInit > landInit;
while( res->next() )
// make sure the landset exists
auto landSetCache = landCache.find( m_landSetId );
if( landSetCache == landCache.end() )
{
QueuedLandInit init;
init.m_landId = res->getUInt64( "LandId" );
init.m_type = static_cast< Common::LandType >( res->getUInt( "Type" ) );
init.m_size = res->getUInt( "Size" );
init.m_status = res->getUInt( "Status" );
init.m_currentPrice = res->getUInt( "LandPrice" );
init.m_ownerId = res->getUInt64( "OwnerId" );
init.m_houseId = res->getUInt64( "HouseId" );
landInit.push_back( init );
g_fw.get< Sapphire::Logger >()->fatal( "LandSet " + std::to_string( m_landSetId ) + " is missing from the land cache." );
return false;
}
// nuke current query connection so the queries still in land don't fail
res.reset();
// spawn land
for( auto& init : landInit )
// init the lands
for( HousingMgr::LandCacheEntry& entry : landSetCache->second )
{
auto land = make_Land( m_territoryTypeId, getWardNum(), init.m_landId, m_landSetId, info );
land->init( init.m_type, init.m_size, init.m_status, init.m_currentPrice, init.m_ownerId, init.m_houseId );
auto land = make_Land( m_territoryTypeId, getWardNum(), entry.m_landId, m_landSetId, info );
m_landPtrMap[ init.m_landId ] = land;
// setup house
if( entry.m_houseId )
{
auto house = make_House( entry.m_houseId, m_landSetId, land->getLandIdent(), entry.m_estateName, entry.m_estateComment );
if( init.m_houseId > 0 )
registerHouseEntranceEObj( init.m_landId );
housingMgr->updateHouseModels( house );
land->setHouse( house );
}
land->init( entry.m_type, entry.m_size, entry.m_status, entry.m_currentPrice, entry.m_ownerId, entry.m_houseId );
m_landPtrMap[ entry.m_landId ] = land;
if( entry.m_houseId > 0 )
registerHouseEntranceEObj( entry.m_landId );
}
return true;
@ -119,20 +116,20 @@ void Sapphire::HousingZone::onPlayerZoneIn( Entity::Player& player )
for( yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ )
{
auto housingObjectInitializPacket = makeZonePacket< FFXIVIpcHousingObjectInitialize >( player.getId() );
memset( &housingObjectInitializPacket->data().landIdent, 0xFF, sizeof( Common::LandIdent ) );
housingObjectInitializPacket->data().u1 = 0xFF;
housingObjectInitializPacket->data().packetNum = yardPacketNum;
housingObjectInitializPacket->data().packetTotal = yardPacketTotal;
auto housingObjectInit = makeZonePacket< FFXIVIpcHousingObjectInitialize >( player.getId() );
memset( &housingObjectInit->data().landIdent, 0xFF, sizeof( Common::LandIdent ) );
housingObjectInit->data().u1 = 0xFF;
housingObjectInit->data().packetNum = yardPacketNum;
housingObjectInit->data().packetTotal = yardPacketTotal;
//TODO: Add Objects here
player.queuePacket( housingObjectInitializPacket );
player.queuePacket( housingObjectInit );
}
auto landSetMap = makeZonePacket< FFXIVIpcLandSetMap >( player.getId() );
landSetMap->data().subdivision = isPlayerSubInstance( player ) == false ? 2 : 1;
uint8_t startIndex = isPlayerSubInstance( player ) == false ? 0 : 30;
landSetMap->data().subdivision = !isPlayerSubInstance( player ) ? 2 : 1;
uint8_t startIndex = !isPlayerSubInstance( player ) ? 0 : 30;
for( uint8_t i = startIndex, count = 0; i < ( startIndex + 30 ); i++, count++ )
{
landSetMap->data().landInfo[ count ].status = 1;
@ -151,9 +148,9 @@ void Sapphire::HousingZone::sendLandSet( Entity::Player& player )
landsetInitializePacket->data().landIdent.territoryTypeId = m_territoryTypeId;
//TODO: get current WorldId
landsetInitializePacket->data().landIdent.worldId = 67;
landsetInitializePacket->data().subInstance = isPlayerSubInstance( player ) == false ? 1 : 2;
landsetInitializePacket->data().subInstance = !isPlayerSubInstance( player ) ? 1 : 2;
uint8_t startIndex = isPlayerSubInstance( player ) == false ? 0 : 30;
uint8_t startIndex = !isPlayerSubInstance( player ) ? 0 : 30;
for( uint8_t i = startIndex, count = 0; i < ( startIndex + 30 ); ++i, ++count )
{
@ -173,7 +170,7 @@ void Sapphire::HousingZone::sendLandSet( Entity::Player& player )
{
landData.flags = 1;
auto& parts = house->getHouseParts();
auto& parts = house->getHouseModels();
for( auto i = 0; i != parts.size(); i++ )
{
@ -210,7 +207,7 @@ void Sapphire::HousingZone::sendLandUpdate( uint8_t landId )
{
landData.flags = 1;
auto& parts = house->getHouseParts();
auto& parts = house->getHouseModels();
for( auto i = 0; i != parts.size(); i++ )
{

View file

@ -53,17 +53,6 @@ namespace Sapphire
Entity::EventObjectPtr registerHouseEntranceEObj( uint8_t plotId );
private:
struct QueuedLandInit
{
uint64_t m_landId;
Common::LandType m_type;
uint8_t m_size;
uint8_t m_status;
uint32_t m_currentPrice;
uint64_t m_ownerId;
uint64_t m_houseId;
};
using LandPtrMap = std::unordered_map< uint8_t, Sapphire::LandPtr >;
const uint32_t m_landSetMax = 18;
LandPtrMap m_landPtrMap;

View file

@ -62,10 +62,6 @@ void Sapphire::Land::init( Common::LandType type, uint8_t size, uint8_t state, u
m_currentPrice = currentPrice;
m_ownerId = ownerId;
// fetch the house if we have one for this land
if( houseId > 0 )
m_pHouse = make_House( houseId, m_landSetId, getLandIdent() );
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
auto info = pExdData->get< Sapphire::Data::HousingMapMarkerInfo >( m_landIdent.territoryTypeId, m_landIdent.landId );
if( info )
@ -94,65 +90,23 @@ void Sapphire::Land::init( Common::LandType type, uint8_t size, uint8_t state, u
}
// init item containers
auto setupContainer = [ this ]( InventoryType type, uint16_t maxSize )
{
m_landInventoryMap[ type ] = make_ItemContainer( type, maxSize, "houseiteminventory", true, true );
};
setupContainer( InventoryType::HousingOutdoorAppearance, 8 );
setupContainer( InventoryType::HousingOutdoorPlacedItems, m_maxPlacedExternalItems );
setupContainer( InventoryType::HousingOutdoorStoreroom, m_maxPlacedExternalItems );
setupContainer( InventoryType::HousingInteriorAppearance, 9 );
// nb: so we're going to store these internally in one container because SE is fucked in the head
// but when an inventory is requested, we will split them into groups of 50
setupContainer( InventoryType::HousingInteriorPlacedItems1, m_maxPlacedInternalItems );
setupContainer( InventoryType::HousingInteriorStoreroom1, m_maxPlacedInternalItems );
loadItemContainerContents();
}
void Sapphire::Land::loadItemContainerContents()
{
if( !m_pHouse )
return;
auto ident = *reinterpret_cast< uint64_t* >( &m_landIdent );
g_fw.get< Sapphire::Logger >()->debug( "Loading housing inventory for ident: " + std::to_string( ident ) );
auto pDB = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
auto stmt = pDB->getPreparedStatement( Db::LAND_INV_SEL_HOUSE );
stmt->setUInt64( 1, ident );
auto res = pDB->query( stmt );
std::unordered_map< uint16_t, std::vector< std::pair< uint16_t, uint32_t > > > items;
while( res->next() )
{
auto containerId = res->getUInt( "ContainerId" );
auto itemId = res->getUInt64( "ItemId" );
auto slotId = res->getUInt( "SlotId" );
items[ containerId ].push_back( std::make_pair( slotId, itemId ) );
}
res.reset();
for( auto it = items.begin(); it != items.end(); it++ )
{
auto container = m_landInventoryMap[ it->first ];
// todo: delet this
for( auto fuck = it->second.begin(); fuck != it->second.end(); fuck++ )
{
auto item = Sapphire::Items::Util::loadItem( fuck->second );
if( item )
container->setItem( fuck->first, item );
}
}
// auto setupContainer = [ this ]( InventoryType type, uint16_t maxSize )
// {
// m_landInventoryMap[ type ] = make_ItemContainer( type, maxSize, "houseiteminventory", true, true );
// };
//
// setupContainer( InventoryType::HousingOutdoorAppearance, 8 );
// setupContainer( InventoryType::HousingOutdoorPlacedItems, m_maxPlacedExternalItems );
// setupContainer( InventoryType::HousingOutdoorStoreroom, m_maxPlacedExternalItems );
//
// setupContainer( InventoryType::HousingInteriorAppearance, 9 );
//
// // nb: so we're going to store these internally in one container because SE is fucked in the head
// // but when an inventory is requested, we will split them into groups of 50
// setupContainer( InventoryType::HousingInteriorPlacedItems1, m_maxPlacedInternalItems );
// setupContainer( InventoryType::HousingInteriorStoreroom1, m_maxPlacedInternalItems );
//
// loadItemContainerContents();
}
uint32_t Sapphire::Land::convertItemIdToHousingItemId( uint32_t itemId )
@ -223,6 +177,11 @@ Sapphire::HousePtr Sapphire::Land::getHouse() const
return m_pHouse;
}
void Sapphire::Land::setHouse( Sapphire::HousePtr house )
{
m_pHouse = house;
}
FFXIVARR_POSITION3 Sapphire::Land::getMapMarkerPosition()
{
return m_mapMarkerPosition;
@ -349,7 +308,8 @@ bool Sapphire::Land::setPreset( uint32_t itemId )
{
// todo: i guess we'd create a house here?
auto newId = getNextHouseId();
m_pHouse = make_House( newId, getLandSetId(), getLandIdent() );
m_pHouse = make_House( newId, getLandSetId(), getLandIdent(), "Estate #" + std::to_string( m_landIdent.landId + 1 ), "" );
}
@ -371,13 +331,4 @@ bool Sapphire::Land::setPreset( uint32_t itemId )
return true;
}
Sapphire::ItemContainerPtr Sapphire::Land::getItemContainer( uint16_t inventoryType ) const
{
auto container = m_landInventoryMap.find( inventoryType );
if( container == m_landInventoryMap.end() )
return nullptr;
return container->second;
}

View file

@ -33,6 +33,7 @@ namespace Sapphire
uint8_t getSharing() const;
uint32_t getLandSetId() const;
Common::LandType getLandType() const;
void setHouse( Sapphire::HousePtr );
Sapphire::HousePtr getHouse() const;
Common::FFXIVARR_POSITION3 getMapMarkerPosition();
Common::LandIdent getLandIdent() const;
@ -60,9 +61,6 @@ namespace Sapphire
void setLandTag( uint8_t slot, uint8_t tag );
uint8_t getLandTag( uint8_t slot );
ItemContainerPtr getItemContainer( uint16_t inventoryType ) const;
void loadItemContainerContents();
private:
uint32_t convertItemIdToHousingItemId( uint32_t itemId );
uint32_t getNextHouseId();
@ -86,7 +84,6 @@ namespace Sapphire
Sapphire::HousePtr m_pHouse;
//item storage
LandInventoryMap m_landInventoryMap;
uint16_t m_maxPlacedExternalItems;
uint16_t m_maxPlacedInternalItems;