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:
commit
18fd18ebe0
13 changed files with 387 additions and 243 deletions
|
@ -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
|
|
@ -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 );
|
||||
|
|
|
@ -80,6 +80,7 @@ namespace Sapphire::Db
|
|||
|
||||
LAND_INS,
|
||||
LAND_SEL,
|
||||
LAND_SEL_ALL,
|
||||
LAND_UP,
|
||||
LANDSET_SEL,
|
||||
HOUSING_HOUSE_INS,
|
||||
|
|
|
@ -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() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() )
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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++ )
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue