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

Merge pull request #457 from NotAdam/housing

sapphire, now with 6000% less queries on startup
This commit is contained in:
Mordred 2018-12-21 15:18:48 +01:00 committed by GitHub
commit 5b38ddf0c5
12 changed files with 190 additions and 141 deletions

View file

@ -200,6 +200,18 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"UPDATE house SET BuildTime = ?, Aetheryte = ?, Comment = ?, HouseName = ?, Endorsements = ?, HousePartModels = ?, HousePartColours = ?, HouseInteriorModels = ? WHERE HouseId = ?;",
CONNECTION_BOTH );
prepareStatement( LAND_INV_SEL_ALL,
"SELECT LandIdent, ContainerId, ItemId, SlotId FROM houseiteminventory;",
CONNECTION_BOTH );
prepareStatement( LAND_INV_SEL_HOUSE,
"SELECT LandIdent, ContainerId, ItemId, SlotId FROM houseiteminventory WHERE LandIdent = ?",
CONNECTION_SYNC );
prepareStatement( LANDSET_SEL,
"SELECT * FROM land WHERE LandSetId = ?;",
CONNECTION_SYNC );
/*prepareStatement( LAND_INS,
"INSERT INTO land ( LandSetId ) VALUES ( ? );",
CONNECTION_BOTH );

View file

@ -81,10 +81,16 @@ namespace Sapphire::Db
LAND_INS,
LAND_SEL,
LAND_UP,
LANDSET_SEL,
HOUSING_HOUSE_INS,
HOUSING_HOUSE_UP,
HOUSING_HOUSE_DEL,
LAND_INV_SEL_ALL,
LAND_INV_SEL_HOUSE,
LAND_INV_DEL,
LAND_INV_UP,
MAX_STATEMENTS
};

View file

@ -1618,7 +1618,7 @@ void Sapphire::Entity::Player::sendZonePackets()
state |= HasAetheryte;
}
setLandFlags( LandFlagsSlot::Private, state, pLand->getLandId(), pLand->getWardNum(), pLand->getTerritoryTypeId() );
setLandFlags( LandFlagsSlot::Private, state, pLand->getLandIdent() );
}
sendLandFlags();
@ -1799,12 +1799,10 @@ bool Sapphire::Entity::Player::isOnEnterEventDone() const
return m_onEnterEventDone;
}
void Sapphire::Entity::Player::setLandFlags( uint8_t flagSlot, uint32_t landFlags,
int16_t landId, int16_t wardNum, int16_t zoneId )
void Sapphire::Entity::Player::setLandFlags( uint8_t flagSlot, uint32_t landFlags, Common::LandIdent ident )
{
m_landFlags[ flagSlot ].landIdent.landId = landId;
m_landFlags[ flagSlot ].landIdent.wardNum = wardNum;
m_landFlags[ flagSlot ].landIdent.territoryTypeId = zoneId;
m_landFlags[ flagSlot ].landIdent = ident;
// todo: leave this in for now but we really need to handle this world id shit properly
m_landFlags[ flagSlot ].landIdent.worldId = 67;
m_landFlags[ flagSlot ].landFlags = landFlags;
m_landFlags[ flagSlot ].unkown1 = 0;

View file

@ -765,7 +765,7 @@ namespace Sapphire::Entity
// Housing Handling
//////////////////////////////////////////////////////////////////////////////////////////////////////
void setLandFlags( uint8_t permissionSet, uint32_t landFlags, int16_t landId, int16_t wardNum, int16_t zoneId );
void setLandFlags( uint8_t permissionSet, uint32_t landFlags, Common::LandIdent ident );
void sendLandFlags();
void sendLandFlagsSlot( Common::LandFlagsSlot slot );

View file

@ -1006,29 +1006,34 @@ void Sapphire::DebugCommandHandler::housing( char* data, Entity::Player& player,
subCommand = params;
}
if( subCommand == "permission" || subCommand == "perm" )
{
uint8_t permissionSet;
sscanf( params.c_str(), "%hhu", &permissionSet );
if ( permissionSet < 5 )
{
auto pZone = player.getCurrentZone();
if( pTeriMgr->isHousingTerritory( pZone->getTerritoryTypeId() ) )
{
auto pHousing = std::dynamic_pointer_cast< HousingZone >( pZone );
if( pHousing )
{
player.setLandFlags( permissionSet, 0, pHousing->getLandSetId(), pHousing->getWardNum(), pHousing->getTerritoryTypeId() );
player.sendLandFlags();
}
else
player.sendDebug( "You aren't in a housing Zone." );
}
}
else
player.sendDebug( "PermissionSet out of range." );
}
// if( subCommand == "permission" || subCommand == "perm" )
// {
// uint8_t permissionSet;
// sscanf( params.c_str(), "%hhu", &permissionSet );
//
// if ( permissionSet < 5 )
// {
// auto pZone = player.getCurrentZone();
// if( pTeriMgr->isHousingTerritory( pZone->getTerritoryTypeId() ) )
// {
// auto pHousing = std::dynamic_pointer_cast< HousingZone >( pZone );
// if( pHousing )
// {
// // todo: wat?
// Common::LandIdent ident {};
// ident.wardNum = pHousing->getWardNum();
// ident.territoryTypeId = pHousing->getTerritoryTypeId();
//
// player.setLandFlags( permissionSet, 0, pHousing->getLandSetId(), ident );
// player.sendLandFlags();
// }
// else
// player.sendDebug( "You aren't in a housing Zone." );
// }
// }
// else
// player.sendDebug( "PermissionSet out of range." );
// }
else
{
player.sendDebug( "Unknown sub command." );

View file

@ -165,8 +165,7 @@ Sapphire::LandPurchaseResult Sapphire::World::Manager::HousingMgr::purchaseLand(
pLand->setState( HouseState::sold );
pLand->setLandType( Common::LandType::Private );
player.setLandFlags( LandFlagsSlot::Private, 0x00, plot,
pHousing->getWardNum(), pHousing->getTerritoryTypeId() );
player.setLandFlags( LandFlagsSlot::Private, 0x00, pLand->getLandIdent() );
player.sendLandFlagsSlot( LandFlagsSlot::Private );
@ -217,12 +216,14 @@ bool Sapphire::World::Manager::HousingMgr::relinquishLand( Entity::Player& playe
pLand->setLandType( Common::LandType::none );
pLand->updateLandDb();
player.setLandFlags( LandFlagsSlot::Private, 0x00, 0xFF, 0xFF, 0xFF );
Common::LandIdent ident { 0xFF, 0xFF, 0xFF, 0xFF };
player.setLandFlags( LandFlagsSlot::Private, 0x00, ident );
player.sendLandFlagsSlot( LandFlagsSlot::Private );
auto screenMsgPkt2 = makeActorControl143( player.getId(), ActorControl::LogMsg, 3351, 0x1AA,
pLand->getWardNum() + 1, plot + 1 );
pLand->getLandIdent().wardNum + 1, plot + 1 );
player.queuePacket( screenMsgPkt2 );
pHousing->sendLandUpdate( plot );
@ -351,7 +352,7 @@ void Sapphire::World::Manager::HousingMgr::buildPresetEstate( Entity::Player& pl
player.eventStart( player.getId(), 0x000B0095, Event::EventHandler::EventType::Housing, 1, 1 );
player.playScene( 0x000B0095, 0, SET_BASE | HIDE_HOTBAR , 0, 1, plotNum, nullptr );
player.setLandFlags( LandFlagsSlot::Private, EstateBuilt, pLand->getLandId(), pLand->getWardNum(), pLand->getTerritoryTypeId() );
player.setLandFlags( LandFlagsSlot::Private, EstateBuilt, pLand->getLandIdent() );
player.sendLandFlagsSlot( LandFlagsSlot::Private );
hZone->registerHouseEntranceEObj( plotNum );

View file

@ -13,12 +13,10 @@
extern Sapphire::Framework g_fw;
Sapphire::House::House( uint32_t houseId, uint32_t landSetId, uint8_t landId, uint8_t wardNum, uint16_t territoryTypeId ) :
Sapphire::House::House( uint32_t houseId, uint32_t landSetId, Common::LandIdent ident ) :
m_houseId( houseId ),
m_landSetId( landSetId ),
m_landId( landId ),
m_wardNum( wardNum ),
m_territoryTypeId( territoryTypeId )
m_landIdent( ident )
{
auto pDB = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
@ -37,7 +35,7 @@ Sapphire::House::House( uint32_t houseId, uint32_t landSetId, uint8_t landId, ui
pDB->execute( stmt );
// todo: make this nicer/configurable?
m_houseName = "Estate #" + std::to_string( landId + 1 );
m_houseName = "Estate #" + std::to_string( m_landIdent.landId + 1 );
}
else
{
@ -121,19 +119,9 @@ uint32_t Sapphire::House::getLandSetId() const
return m_landSetId;
}
uint8_t Sapphire::House::getLandId() const
Sapphire::Common::LandIdent Sapphire::House::getLandIdent() const
{
return m_landId;
}
uint8_t Sapphire::House::getWardNum() const
{
return m_wardNum;
}
uint16_t Sapphire::House::getTerritoryTypeId() const
{
return m_territoryTypeId;
return m_landIdent;
}
uint32_t Sapphire::House::getHouseId() const

View file

@ -12,7 +12,7 @@ namespace Sapphire
class House
{
public:
House( uint32_t houseId, uint32_t landSetId, uint8_t landId, uint8_t wardNum, uint16_t territoryTypeId );
House( uint32_t houseId, uint32_t landSetId, Common::LandIdent ident );
virtual ~House();
using HousePart = std::pair< uint32_t, uint8_t >;
@ -20,9 +20,7 @@ namespace Sapphire
//gerneral
uint32_t getLandSetId() const;
uint8_t getLandId() const;
uint8_t getWardNum() const;
uint16_t getTerritoryTypeId() const;
Common::LandIdent getLandIdent() const;
uint32_t getHouseId() const;
const std::string& getHouseName() const;
@ -45,9 +43,7 @@ namespace Sapphire
private:
uint32_t m_landSetId;
uint8_t m_landId;
uint8_t m_wardNum;
uint16_t m_territoryTypeId;
Common::LandIdent m_landIdent;
uint32_t m_houseId;
uint64_t m_buildTime;

View file

@ -42,12 +42,15 @@ bool Sapphire::HousingZone::init()
{
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
auto res = pDb->query( "SELECT * FROM landset WHERE landsetid = " + std::to_string( m_landSetId ) );
if( !res->next() )
{
pDb->directExecute( "INSERT INTO landset ( landsetid ) VALUES ( " + std::to_string( m_landSetId ) + " );" );
auto res = pDb->query( "SELECT * FROM landset WHERE landsetid = " + std::to_string( m_landSetId ) );
if( !res->next() )
{
pDb->directExecute( "INSERT INTO landset ( landsetid ) VALUES ( " + std::to_string( m_landSetId ) + " );" );
}
}
int housingIndex;
if( m_territoryTypeId == 339 )
housingIndex = 0;
@ -61,25 +64,46 @@ bool Sapphire::HousingZone::init()
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
auto info = pExdData->get< Sapphire::Data::HousingLandSet >( housingIndex );
uint32_t landId;
for( landId = 0; landId < 60; landId++ )
{
auto pLand = make_Land( m_territoryTypeId, getWardNum(), landId, m_landSetId, info );
m_landPtrMap[ landId ] = pLand;
auto stmt = pDb->getPreparedStatement( Db::LANDSET_SEL );
stmt->setUInt64( 1, m_landSetId );
auto res = pDb->query( stmt );
if( auto house = pLand->getHouse() )
{
registerHouseEntranceEObj( landId << 8 );
}
std::vector< QueuedLandInit > landInit;
while( res->next() )
{
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 );
}
// nuke current query connection so the queries still in land don't fail
res.reset();
// spawn land
for( auto& init : landInit )
{
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 );
m_landPtrMap[ init.m_landId ] = land;
if( init.m_houseId > 0 )
registerHouseEntranceEObj( init.m_landId );
}
return true;
}
Sapphire::HousingZone::~HousingZone()
{
}
Sapphire::HousingZone::~HousingZone() = default;
void Sapphire::HousingZone::onPlayerZoneIn( Entity::Player& player )
{

View file

@ -53,6 +53,17 @@ 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

@ -16,6 +16,7 @@
#include "Actor/Player.h"
#include "Inventory/ItemContainer.h"
#include "Inventory/Item.h"
#include "Inventory/ItemUtil.h"
#include "Forwards.h"
#include "Land.h"
@ -28,9 +29,6 @@ using namespace Sapphire::Common;
Sapphire::Land::Land( uint16_t territoryTypeId, uint8_t wardNum, uint8_t landId, uint32_t landSetId,
Sapphire::Data::HousingLandSetPtr info ) :
m_territoryTypeId( territoryTypeId ),
m_wardNum( wardNum ),
m_landId( landId ),
m_currentPrice( 0 ),
m_minPrice( 0 ),
m_nextDrop( static_cast< uint32_t >( Util::getTimeSeconds() ) + 21600 ),
@ -45,52 +43,31 @@ Sapphire::Land::Land( uint16_t territoryTypeId, uint8_t wardNum, uint8_t landId,
{
memset( &m_tag, 0x00, 3 );
init();
m_landIdent.landId = landId;
m_landIdent.territoryTypeId = territoryTypeId;
m_landIdent.wardNum = wardNum;
m_landIdent.worldId = 67; // todo: fix this
m_minPrice = m_landInfo->minPrice[ m_landIdent.landId ];
m_maxPrice = m_landInfo->initialPrice[ m_landIdent.landId ];
}
Sapphire::Land::~Land()
Sapphire::Land::~Land() = default;
void Sapphire::Land::init( Common::LandType type, uint8_t size, uint8_t state, uint32_t currentPrice, uint64_t ownerId, uint64_t houseId )
{
m_type = type;
m_size = size;
m_state = state;
m_currentPrice = currentPrice;
m_ownerId = ownerId;
}
void Sapphire::Land::init()
{
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
auto res = pDb->query( "SELECT * FROM land WHERE LandSetId = " + std::to_string( m_landSetId ) + " "
"AND LandId = " + std::to_string( m_landId ) );
if( !res->next() )
{
pDb->directExecute( "INSERT INTO land ( landsetid, landid, type, size, status, landprice, UpdateTime, OwnerId, HouseId ) "
"VALUES ( " + std::to_string( m_landSetId ) + "," + std::to_string( m_landId ) + ","
+ std::to_string( static_cast< uint8_t >( m_type ) ) + ","
+ std::to_string( m_landInfo->plotSize[ m_landId ] ) + ","
+ " 1, " + std::to_string( m_landInfo->initialPrice[ m_landId ] ) + ", 0, 0, 0 );" );
m_currentPrice = m_landInfo->initialPrice[ m_landId ];
m_minPrice = m_landInfo->minPrice[ m_landId ];
m_size = m_landInfo->plotSize[ m_landId ];
m_state = HouseState::forSale;
}
else
{
m_type = static_cast< Common::LandType >( res->getUInt( "Type" ) );
m_size = res->getUInt( "Size" );
m_state = res->getUInt( "Status" );
m_currentPrice = res->getUInt( "LandPrice" );
m_ownerId = res->getUInt64( "OwnerId" );
m_minPrice = m_landInfo->minPrice[ m_landId ];
m_maxPrice = m_landInfo->initialPrice[ m_landId ];
auto houseId = res->getUInt( "HouseId" );
// fetch the house if we have one for this land
if( houseId > 0 )
m_pHouse = make_House( houseId, m_landSetId, m_landId, m_wardNum, m_territoryTypeId );
}
// 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 >( getTerritoryTypeId(), getLandId() );
auto info = pExdData->get< Sapphire::Data::HousingMapMarkerInfo >( m_landIdent.territoryTypeId, m_landIdent.landId );
if( info )
{
m_mapMarkerPosition.x = info->x;
@ -127,11 +104,55 @@ void Sapphire::Land::init()
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 );
}
}
}
uint32_t Sapphire::Land::convertItemIdToHousingItemId( uint32_t itemId )
@ -192,19 +213,9 @@ uint32_t Sapphire::Land::getLandSetId() const
return m_landSetId;
}
uint8_t Sapphire::Land::getWardNum() const
Sapphire::Common::LandIdent Sapphire::Land::getLandIdent() const
{
return m_wardNum;
}
uint8_t Sapphire::Land::getLandId() const
{
return m_landId;
}
uint16_t Sapphire::Land::getTerritoryTypeId() const
{
return m_territoryTypeId;
return m_landIdent;
}
Sapphire::HousePtr Sapphire::Land::getHouse() const
@ -292,7 +303,7 @@ void Sapphire::Land::updateLandDb()
+ ", HouseId = " + std::to_string( houseId )
+ ", Type = " + std::to_string( static_cast< uint32_t >( m_type ) ) //TODO: add house id
+ " WHERE LandSetId = " + std::to_string( m_landSetId )
+ " AND LandId = " + std::to_string( m_landId ) + ";" );
+ " AND LandId = " + std::to_string( m_landIdent.landId ) + ";" );
if( auto house = getHouse() )
house->updateHouseDb();
@ -338,7 +349,7 @@ 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(), getLandId(), getWardNum(), getTerritoryTypeId() );
m_pHouse = make_House( newId, getLandSetId(), getLandIdent() );
}

View file

@ -17,6 +17,7 @@ namespace Sapphire
Land( uint16_t zoneId, uint8_t wardNum, uint8_t landId, uint32_t landSetId, Sapphire::Data::HousingLandSetPtr info );
virtual ~Land();
void init( Common::LandType type, uint8_t size, uint8_t state, uint32_t currentPrice, uint64_t ownerId, uint64_t houseId );
using LandInventoryMap = std::unordered_map< uint16_t, ItemContainerPtr >;
@ -31,12 +32,10 @@ namespace Sapphire
uint8_t getState() const;
uint8_t getSharing() const;
uint32_t getLandSetId() const;
uint8_t getWardNum() const;
uint8_t getLandId() const;
uint16_t getTerritoryTypeId() const;
Common::LandType getLandType() const;
Sapphire::HousePtr getHouse() const;
Common::FFXIVARR_POSITION3 getMapMarkerPosition();
Common::LandIdent getLandIdent() const;
//Free Comapny
void setFreeCompany( uint32_t id, uint32_t icon, uint32_t color );
@ -66,13 +65,11 @@ namespace Sapphire
private:
uint32_t convertItemIdToHousingItemId( uint32_t itemId );
void init();
uint32_t getNextHouseId();
uint8_t m_wardNum;
uint8_t m_landId;
Common::LandIdent m_landIdent;
uint32_t m_landSetId;
uint16_t m_territoryTypeId;
uint8_t m_size;
uint8_t m_state;
Common::LandType m_type;
@ -90,8 +87,8 @@ namespace Sapphire
//item storage
LandInventoryMap m_landInventoryMap;
uint32_t m_maxPlacedExternalItems;
uint32_t m_maxPlacedInternalItems;
uint16_t m_maxPlacedExternalItems;
uint16_t m_maxPlacedInternalItems;
//price
uint32_t m_initPrice;