diff --git a/sql/update_land.sql b/sql/update_land.sql index 6baa174e..87f14e23 100644 --- a/sql/update_land.sql +++ b/sql/update_land.sql @@ -1,2 +1,4 @@ ALTER TABLE `land` ADD `Type` SMALLINT(6) NOT NULL DEFAULT '0' AFTER `LandId`; -ALTER TABLE `house` ADD `HouseName` binary(23) DEFAULT "" AFTER `Comment`; \ No newline at end of file +ALTER TABLE `house` ADD `HouseName` binary(23) DEFAULT "" AFTER `Comment`; +ALTER TABLE `house` ADD `HousePartModels` BINARY(32) DEFAULT "" AFTER `Endorsements`; +ALTER TABLE `house` ADD `HousePartColours` BINARY(8) DEFAULT "" AFTER `HousePartModels`; \ No newline at end of file diff --git a/src/common/Database/ZoneDbConnection.cpp b/src/common/Database/ZoneDbConnection.cpp index cf76f4f0..bb92489c 100644 --- a/src/common/Database/ZoneDbConnection.cpp +++ b/src/common/Database/ZoneDbConnection.cpp @@ -181,8 +181,8 @@ void Core::Db::ZoneDbConnection::doPrepareStatements() "secWeaponModel, aggressionMode, enemyType, pose, " "modelChara, displayFlags, Look, Models " "FROM bnpctemplate WHERE 1;", - CONNECTION_BOTH); - + CONNECTION_BOTH ); + prepareStatement( CHARA_ITEMGLOBAL_UP, "UPDATE charaglobalitem SET stack = ?, durability = ?, stain = ? WHERE ItemId = ?;", CONNECTION_BOTH ); @@ -191,6 +191,15 @@ void Core::Db::ZoneDbConnection::doPrepareStatements() "UPDATE charaglobalitem SET IS_DELETE = 1 WHERE ItemId = ?;", CONNECTION_BOTH ); + /// HOUSING + prepareStatement( HOUSING_HOUSE_INS, + "INSERT INTO house ( LandSetId, HouseId ) VALUES ( ?, ? );", + CONNECTION_BOTH ); + + prepareStatement( HOUSING_HOUSE_UP, + "UPDATE house SET BuildTime = ?, Aetheryte = ?, Comment = ?, HouseName = ?, Endorsements = ?, HousePartModels = ?, HousePartColours = ? WHERE HouseId = ?;", + CONNECTION_BOTH ); + /*prepareStatement( LAND_INS, "INSERT INTO land ( LandSetId ) VALUES ( ? );", CONNECTION_BOTH ); diff --git a/src/common/Database/ZoneDbConnection.h b/src/common/Database/ZoneDbConnection.h index 0a106cd3..aa3cdf0f 100644 --- a/src/common/Database/ZoneDbConnection.h +++ b/src/common/Database/ZoneDbConnection.h @@ -81,6 +81,9 @@ namespace Core::Db LAND_INS, LAND_SEL, LAND_UP, + HOUSING_HOUSE_INS, + HOUSING_HOUSE_UP, + HOUSING_HOUSE_DEL, MAX_STATEMENTS diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 5d126c49..496ed69e 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -297,7 +297,11 @@ enum ActorControlType : uint16_t RequestWardLandInfo = 0x453, RequestLandRelinquish = 0x454, RequestEstateRename = 0x45A, + RequestEstateEditGreeting = 0x45B, RequestEstateGreeting = 0x45C, // sends FFXIVIpcHousingEstateGreeting in return + RequestEstateEditGuestAccessSettings = 0x45D, + RequestEstateTagSettings = 0x45F, + RequestHousingItemUI = 0x463, RequestSharedEstateSettings = 0x46F, diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 22c07e60..44247c6d 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1607,7 +1607,7 @@ struct LandStruct uint32_t fcIcon;// 12 uint32_t fcIconColor; // 16 uint16_t housePart[ 8 ]; // 34 - uint8_t color[ 8 ]; // 36 + uint8_t houseColour[ 8 ]; // 36 }; struct FFXIVIpcLandUpdate : FFXIVIpcBasePacket< LandUpdate > diff --git a/src/servers/sapphire_zone/Zone/House.cpp b/src/servers/sapphire_zone/Zone/House.cpp index 55ca5b1d..333bfec4 100644 --- a/src/servers/sapphire_zone/Zone/House.cpp +++ b/src/servers/sapphire_zone/Zone/House.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "House.h" @@ -19,25 +20,79 @@ Core::House::House( uint32_t houseId, uint32_t landSetId, uint8_t landId, uint8_ m_wardNum( wardNum ), m_territoryTypeId( territoryTypeId ) { - memset( &m_houseParts, 0x00, sizeof( m_houseParts ) ); - memset( &m_commentMsg, 0x00, sizeof( m_commentMsg ) ); - auto pDB = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); - auto res = pDB->query("SELECT * FROM house WHERE HouseId = " + std::to_string( houseId ) ); + + // todo: convert to prepared statement + auto res = pDB->query( "SELECT * FROM house WHERE HouseId = " + std::to_string( houseId ) ); if( !res->next() ) { - pDB->directExecute("INSERT INTO house ( LandSetId, HouseId ) VALUES ( " + std::to_string( m_landSetId ) + ", " + std::to_string( m_houseId ) + " )" ); + g_fw.get< Core::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 ); } else { - // todo + 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 ] ); + auto colours = &housePartColours[ 0 ]; + + for( auto i = 0; i < 8; i++ ) + { + m_houseParts[ i ] = { models[ i ], colours[ i ] }; + } } } Core::House::~House() { +} +void Core::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 + auto stmt = pDB->getPreparedStatement( Db::HOUSING_HOUSE_UP ); + stmt->setUInt( 8, m_houseId ); + + stmt->setInt64( 1, m_buildTime ); + stmt->setInt( 2, 0 ); + + stmt->setString( 3, m_estateMessage ); + stmt->setString( 4, m_houseName ); + + 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 ); + + pDB->execute( stmt ); } uint32_t Core::House::getLandSetId() const @@ -67,20 +122,25 @@ uint32_t Core::House::getHouseId() const uint8_t Core::House::getHousePartColor( Common::HousePartSlot slot ) const { - return m_housePartsColor[ slot ]; + return m_houseParts[ slot ].second; } void Core::House::setHousePart( Common::HousePartSlot slot, uint32_t id ) { - m_houseParts[ slot ] = id; + m_houseParts[ slot ].first = id; } void Core::House::setHousePartColor( Common::HousePartSlot slot, uint32_t id ) { - m_housePartsColor[ slot ] = id; + m_houseParts[ slot ].second = id; } uint32_t Core::House::getHousePart( Common::HousePartSlot slot ) const { - return m_houseParts[ slot ]; + return m_houseParts[ slot ].first; +} + +Core::House::HousePartsArray const& Core::House::getHouseParts() const +{ + return m_houseParts; } \ No newline at end of file diff --git a/src/servers/sapphire_zone/Zone/House.h b/src/servers/sapphire_zone/Zone/House.h index 080aea2e..17abaaba 100644 --- a/src/servers/sapphire_zone/Zone/House.h +++ b/src/servers/sapphire_zone/Zone/House.h @@ -11,11 +11,13 @@ namespace Core class House { - public: House( uint32_t houseId, uint32_t landSetId, uint8_t landId, uint8_t wardNum, uint16_t territoryTypeId ); virtual ~House(); + using HousePart = std::pair< uint32_t, uint8_t >; + using HousePartsArray = std::array< HousePart, 8 >; + //gerneral uint32_t getLandSetId() const; uint8_t getLandId() const; @@ -29,6 +31,10 @@ namespace Core uint32_t getHousePart( Common::HousePartSlot slot ) const; uint8_t getHousePartColor( Common::HousePartSlot slot ) const; + HousePartsArray const& getHouseParts() const; + + void updateHouseDb(); + private: uint32_t m_landSetId; uint8_t m_landId; @@ -36,10 +42,12 @@ namespace Core uint16_t m_territoryTypeId; uint32_t m_houseId; - uint32_t m_houseParts[ 8 ]; - uint8_t m_housePartsColor[ 8 ]; + uint64_t m_buildTime; - char m_commentMsg[ 193 ]; + HousePartsArray m_houseParts; + + std::string m_estateMessage; + std::string m_houseName; }; } diff --git a/src/servers/sapphire_zone/Zone/HousingMgr.cpp b/src/servers/sapphire_zone/Zone/HousingMgr.cpp index 28c18adf..24b4540e 100644 --- a/src/servers/sapphire_zone/Zone/HousingMgr.cpp +++ b/src/servers/sapphire_zone/Zone/HousingMgr.cpp @@ -295,10 +295,19 @@ void Core::HousingMgr::buildPresetEstate( Entity::Player& player, uint8_t plotNu pLand->setState( HouseState::privateHouse ); pLand->setLandType( LandType::Private ); - pLand->updateLandDb(); hZone->sendLandUpdate( plotNum ); auto pSuccessBuildingPacket = makeActorControl142( player.getId(), ActorControl::BuildPresetResponse, plotNum ); player.queuePacket( pSuccessBuildingPacket ); + + pLand->updateLandDb(); + + // start house built event + // CmnDefHousingBuildHouse_00149 + player.eventStart( player.getId(), 0x000B0095, Event::EventHandler::EventType::Housing, 1, 1 ); + // todo: wtf are these flags + player.playScene( 0x000B0095, 0, 4164955899, 0, 1, plotNum, nullptr ); + + // todo: send perms/flags for house } diff --git a/src/servers/sapphire_zone/Zone/HousingZone.cpp b/src/servers/sapphire_zone/Zone/HousingZone.cpp index 8ca52012..be5434b4 100644 --- a/src/servers/sapphire_zone/Zone/HousingZone.cpp +++ b/src/servers/sapphire_zone/Zone/HousingZone.cpp @@ -127,13 +127,28 @@ void Core::HousingZone::sendLandSet( Entity::Player& player ) for( uint8_t i = startIndex, count = 0; i < ( startIndex + 30 ); ++i, ++count ) { auto pLand = getLand( i ); - landsetInitializePacket->data().land[ count ].plotSize = pLand->getSize(); - landsetInitializePacket->data().land[ count ].houseState = pLand->getState(); - landsetInitializePacket->data().land[ count ].type = static_cast< uint8_t >( pLand->getLandType() ); - landsetInitializePacket->data().land[ count ].iconAddIcon = pLand->getSharing(); - landsetInitializePacket->data().land[ count ].fcId = pLand->getFcId(); - landsetInitializePacket->data().land[ count ].fcIcon = pLand->getFcIcon(); - landsetInitializePacket->data().land[ count ].fcIconColor = pLand->getFcColor(); + + // todo: move this and sendLandUpdate building logic to its own function + auto& landData = landsetInitializePacket->data().land[ count ]; + + landData.plotSize = pLand->getSize(); + landData.houseState = pLand->getState(); + landData.type = static_cast< uint8_t >( pLand->getLandType() ); + landData.iconAddIcon = pLand->getSharing(); + landData.fcId = pLand->getFcId(); + landData.fcIcon = pLand->getFcIcon(); + landData.fcIconColor = pLand->getFcColor(); + + if( auto house = pLand->getHouse() ) + { + auto& parts = house->getHouseParts(); + + for( auto i = 0; i != parts.size(); i++ ) + { + landData.housePart[ i ] = parts[ i ].first; + landData.houseColour[ i ] = parts[ i ].second; + } + } } player.queuePacket( landsetInitializePacket ); @@ -148,23 +163,26 @@ void Core::HousingZone::sendLandUpdate( uint8_t landId ) auto landUpdatePacket = makeZonePacket< FFXIVIpcLandUpdate >( pPlayer->getId() ); landUpdatePacket->data().landId = landId; - landUpdatePacket->data().land.plotSize = pLand->getSize(); - landUpdatePacket->data().land.houseState = pLand->getState(); - landUpdatePacket->data().land.type = 0; - landUpdatePacket->data().land.iconAddIcon = pLand->getSharing(); - landUpdatePacket->data().land.fcId = pLand->getFcId(); - landUpdatePacket->data().land.fcIcon = pLand->getFcIcon(); - landUpdatePacket->data().land.fcIconColor = pLand->getFcColor(); + + auto& landData = landUpdatePacket->data().land; + + landData.plotSize = pLand->getSize(); + landData.houseState = pLand->getState(); + landData.type = static_cast< uint8_t >( pLand->getLandType() ); + landData.iconAddIcon = pLand->getSharing(); + landData.fcId = pLand->getFcId(); + landData.fcIcon = pLand->getFcIcon(); + landData.fcIconColor = pLand->getFcColor(); + if( auto house = pLand->getHouse() ) { - // todo: this is retarded, need a getter to the internal array - for( int i = 0; i < 8; i++ ) - { - auto slot = static_cast< Common::HousePartSlot >( i ); - auto part = pLand->getHouse()->getHousePart( slot ); + auto& parts = house->getHouseParts(); - landUpdatePacket->data().land.housePart[ slot ] = part; + for( auto i = 0; i != parts.size(); i++ ) + { + landData.housePart[ i ] = parts[ i ].first; + landData.houseColour[ i ] = parts[ i ].second; } } diff --git a/src/servers/sapphire_zone/Zone/Land.cpp b/src/servers/sapphire_zone/Zone/Land.cpp index 26335d5a..4db6c196 100644 --- a/src/servers/sapphire_zone/Zone/Land.cpp +++ b/src/servers/sapphire_zone/Zone/Land.cpp @@ -80,6 +80,13 @@ void Core::Land::load() m_ownerPlayerId = res->getUInt( "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 ); + } init(); } @@ -252,6 +259,7 @@ void Core::Land::updateLandDb() if( getHouse() ) houseId = getHouse()->getHouseId(); + // todo: change to prepared statement auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); pDb->directExecute( "UPDATE land SET status = " + std::to_string( m_state ) + ", LandPrice = " + std::to_string( getCurrentPrice() ) @@ -261,6 +269,9 @@ void Core::Land::updateLandDb() + ", 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 ) + ";" ); + + if( auto house = getHouse() ) + house->updateHouseDb(); } void Core::Land::update( uint32_t currTime ) @@ -306,10 +317,10 @@ bool Core::Land::setPreset( uint32_t itemId ) m_pHouse = make_House( newId, getLandSetId(), getLandId(), getWardNum(), getTerritoryTypeId() ); } - getHouse()->setHousePart( Common::HousePartSlot::ExteriorRoof, housingPreset->exteriorRoof ); - getHouse()->setHousePart( Common::HousePartSlot::ExteriorWall, housingPreset->exteriorWall ); - getHouse()->setHousePart( Common::HousePartSlot::ExteriorWindow, housingPreset->exteriorWindow ); - getHouse()->setHousePart( Common::HousePartSlot::ExteriorDoor, housingPreset->exteriorDoor ); + getHouse()->setHousePart( Common::HousePartSlot::ExteriorRoof, convertItemIdToHousingItemId( housingPreset->exteriorRoof ) ); + getHouse()->setHousePart( Common::HousePartSlot::ExteriorWall, convertItemIdToHousingItemId( housingPreset->exteriorWall ) ); + getHouse()->setHousePart( Common::HousePartSlot::ExteriorWindow, convertItemIdToHousingItemId( housingPreset->exteriorWindow ) ); + getHouse()->setHousePart( Common::HousePartSlot::ExteriorDoor, convertItemIdToHousingItemId( housingPreset->exteriorDoor ) ); return true; }