1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-30 08:07:46 +00:00

Merge pull request #6 from SapphireMordred/housing

Housing
This commit is contained in:
XeAri 2018-11-16 12:14:53 +01:00 committed by GitHub
commit 218febd2fe
15 changed files with 141 additions and 85 deletions

Binary file not shown.

View file

@ -292,6 +292,7 @@ enum ActorControlType : uint16_t
RequestHousingBuildPreset = 0x44C, RequestHousingBuildPreset = 0x44C,
RequestLandSignFree = 0x451, RequestLandSignFree = 0x451,
RequestLandSignOwned = 0x452, RequestLandSignOwned = 0x452,
RequestLandRelinquish = 0x454,
RequestEstateRename = 0x45A, RequestEstateRename = 0x45A,
RequestHousingItemUI = 0x463, RequestHousingItemUI = 0x463,
RequestSharedEstateSettings = 0x46F, RequestSharedEstateSettings = 0x46F,

View file

@ -2,8 +2,10 @@
#include <Actor/Player.h> #include <Actor/Player.h>
#include <Zone/Zone.h> #include <Zone/Zone.h>
#include <Zone/HousingZone.h> #include <Zone/HousingZone.h>
#include <Zone/HousingMgr.h>
#include <Network/PacketWrappers/ActorControlPacket143.h> #include <Network/PacketWrappers/ActorControlPacket143.h>
#include <Network/CommonActorControl.h> #include <Network/CommonActorControl.h>
#include "Framework.h"
using namespace Core; using namespace Core;
@ -22,6 +24,9 @@ public:
{ {
auto callback = [ this ]( Entity::Player& player, const Event::SceneResult& result ) auto callback = [ this ]( Entity::Player& player, const Event::SceneResult& result )
{ {
auto pFw = getFramework();
if( !pFw )
return LandPurchaseResult::ERR_INTERNAL;
// Purchase Land // Purchase Land
if( result.param2 == 2 ) if( result.param2 == 2 )
{ {
@ -30,8 +35,9 @@ public:
auto pTerritory = player.getCurrentZone(); auto pTerritory = player.getCurrentZone();
auto pHousing = std::dynamic_pointer_cast< HousingZone >( pTerritory ); auto pHousing = std::dynamic_pointer_cast< HousingZone >( pTerritory );
auto pHouMgr = pFw->get< Core::HousingMgr >();
LandPurchaseResult res = pHousing->purchseLand( player, activeLand.plot, LandPurchaseResult res = pHouMgr->purchseLand( player, activeLand.plot,
static_cast< uint8_t >( result.param2 ) ); static_cast< uint8_t >( result.param2 ) );
switch( res ) switch( res )
@ -87,4 +93,4 @@ public:
{ {
Scene00000( player ); Scene00000( player );
} }
}; };

View file

@ -1792,3 +1792,16 @@ void Core::Entity::Player::sendLandPermissions()
queuePacket( landPermissions ); queuePacket( landPermissions );
} }
void Core::Entity::Player::sendLandPermissionSlot( uint8_t slotId, uint8_t landId, uint8_t wardId, uint16_t zoneId )
{
auto landPermissions = makeZonePacket< FFXIVIpcLandPermissionSlot >( getId() );
landPermissions->data().type = slotId;
landPermissions->data().permissionSet.landId = landId;
landPermissions->data().permissionSet.wardNum = wardId;
landPermissions->data().permissionSet.zoneId = zoneId;
landPermissions->data().permissionSet.worldId = 67;
landPermissions->data().permissionSet.permissionMask = 0;
queuePacket( landPermissions );
}

View file

@ -766,6 +766,7 @@ namespace Core::Entity
void setLandPermissions( uint8_t permissionSet, uint32_t permissionMask, int16_t landId, int16_t wardNum, int16_t zoneId ); void setLandPermissions( uint8_t permissionSet, uint32_t permissionMask, int16_t landId, int16_t wardNum, int16_t zoneId );
void sendLandPermissions(); void sendLandPermissions();
void sendLandPermissionSlot( uint8_t slotId, uint8_t landId, uint8_t wardId, uint16_t zoneId );
// Player Battle Handling // Player Battle Handling
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -312,17 +312,14 @@ void Core::Network::GameConnection::clientTriggerHandler( const Packets::FFXIVAR
} }
case ClientTriggerType::RequestHousingBuildPreset: case ClientTriggerType::RequestHousingBuildPreset:
{ {
auto pShowBuildPresetUIPacket = makeActorControl142( player.getId(), ShowBuildPresetUI, param11 );
auto zone = player.getCurrentZone(); auto zone = player.getCurrentZone();
auto hZone = std::dynamic_pointer_cast< HousingZone >( zone ); auto hZone = std::dynamic_pointer_cast< HousingZone >( zone );
if (!hZone) if (!hZone)
return; return;
player.setActiveLand( param11, hZone->getWardNum() ); player.setActiveLand( param11, hZone->getWardNum() );
auto pShowBuildPresetUIPacket = makeActorControl142( player.getId(), ShowBuildPresetUI, param11 );
player.queuePacket( pShowBuildPresetUIPacket ); player.queuePacket( pShowBuildPresetUIPacket );
break; break;
@ -343,6 +340,15 @@ void Core::Network::GameConnection::clientTriggerHandler( const Packets::FFXIVAR
pHousingMgr->sendLandSignOwned( player, ward, plot ); pHousingMgr->sendLandSignOwned( player, ward, plot );
break; break;
} }
case ClientTriggerType::RequestLandRelinquish:
{
auto ward = static_cast< uint8_t >( ( param12 & 0xFF00 ) >> 8 );
auto plot = static_cast< uint8_t >( param12 & 0xFF );
auto pHousingMgr = g_fw.get< HousingMgr >();
pLog->debug( "Request to relinquish plot " + std::to_string( plot ) );
// TODO: do stuff!
break;
}
case ClientTriggerType::RequestEstateRename: case ClientTriggerType::RequestEstateRename:
{ {
// removed temporarly, there is no such thing as a LandName // removed temporarly, there is no such thing as a LandName

View file

@ -549,7 +549,7 @@ void Core::Network::GameConnection::chatHandler( const Core::Network::Packets::F
if( player.isActingAsGm() ) if( player.isActingAsGm() )
chatPacket->data().chatType = ChatType::GMSay; chatPacket->data().chatType = ChatType::GMSay;
player.getCurrentZone()->queueOutPacketForRange( player, 50, chatPacket ); player.getCurrentZone()->queuePacketForRange( player, 50, chatPacket );
break; break;
} }
case ChatType::Yell: case ChatType::Yell:
@ -557,7 +557,7 @@ void Core::Network::GameConnection::chatHandler( const Core::Network::Packets::F
if( player.isActingAsGm() ) if( player.isActingAsGm() )
chatPacket->data().chatType = ChatType::GMYell; chatPacket->data().chatType = ChatType::GMYell;
player.getCurrentZone()->queueOutPacketForRange( player, 6000, chatPacket ); player.getCurrentZone()->queuePacketForRange( player, 6000, chatPacket );
break; break;
} }
case ChatType::Shout: case ChatType::Shout:
@ -565,12 +565,12 @@ void Core::Network::GameConnection::chatHandler( const Core::Network::Packets::F
if( player.isActingAsGm() ) if( player.isActingAsGm() )
chatPacket->data().chatType = ChatType::GMShout; chatPacket->data().chatType = ChatType::GMShout;
player.getCurrentZone()->queueOutPacketForRange( player, 6000, chatPacket ); player.getCurrentZone()->queuePacketForRange( player, 6000, chatPacket );
break; break;
} }
default: default:
{ {
player.getCurrentZone()->queueOutPacketForRange( player, 50, chatPacket ); player.getCurrentZone()->queuePacketForRange( player, 50, chatPacket );
break; break;
} }
} }

View file

@ -1,5 +1,4 @@
#include "HousingMgr.h" #include "HousingMgr.h"
#include "HousingMgr.h"
#include <Logging/Logger.h> #include <Logging/Logger.h>
#include <Database/DatabaseDef.h> #include <Database/DatabaseDef.h>
#include <Exd/ExdDataGenerated.h> #include <Exd/ExdDataGenerated.h>
@ -145,3 +144,60 @@ void Core::HousingMgr::sendLandSignFree( Entity::Player& player, uint8_t ward, u
plotPricePacket->data().timeLeft = land->getDevaluationTime(); plotPricePacket->data().timeLeft = land->getDevaluationTime();
player.queuePacket( plotPricePacket ); player.queuePacket( plotPricePacket );
} }
Core::LandPurchaseResult Core::HousingMgr::purchseLand( Entity::Player& player, uint8_t plot, uint8_t state )
{
auto pHousing = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() );
auto plotPrice = pHousing->getLand( plot )->getCurrentPrice();
auto gilAvailable = player.getCurrency( CurrencyType::Gil );
auto pLand = pHousing->getLand( plot );
if( !pLand )
return LandPurchaseResult::ERR_INTERNAL;
if( pLand->getState() != HouseState::forSale )
return LandPurchaseResult::ERR_NOT_AVAILABLE;
if( gilAvailable < plotPrice )
return LandPurchaseResult::ERR_NOT_ENOUGH_GIL;
switch( static_cast< LandPurchaseMode >( state ) )
{
case LandPurchaseMode::FC:
player.sendDebug( "Free company house purchase aren't supported at this time." );
return LandPurchaseResult::ERR_INTERNAL;
case LandPurchaseMode::PRIVATE:
{
auto pOldLand = getLandByOwnerId( player.getId() );
if( pOldLand )
return LandPurchaseResult::ERR_NO_MORE_LANDS_FOR_CHAR;
player.removeCurrency( CurrencyType::Gil, plotPrice );
pLand->setPlayerOwner( player.getId() );
pLand->setState( HouseState::sold );
pLand->setLandType( Common::LandType::Private );
player.setLandPermissions( LandPermissionSlot::Private, 0x00, plot,
pHousing->getWardNum(), pHousing->getTerritoryTypeId() );
player.sendLandPermissionSlot( static_cast< uint8_t >( LandType::Private ), plot, pHousing->getWardNum(),
pHousing->getTerritoryTypeId() );
//pLand->setLandName( "Private Estate" + std::to_string( pHousing->getWardNum() ) + "-" + std::to_string( plot ) );
pLand->updateLandDb();
pHousing->sendLandUpdate( plot );
return LandPurchaseResult::SUCCESS;
}
default:
return LandPurchaseResult::ERR_INTERNAL;
}
}

View file

@ -30,6 +30,7 @@ namespace Core
void sendLandSignOwned( Entity::Player& player, uint8_t ward, uint8_t plot ); void sendLandSignOwned( Entity::Player& player, uint8_t ward, uint8_t plot );
void sendLandSignFree( Entity::Player& player, uint8_t ward, uint8_t plot ); void sendLandSignFree( Entity::Player& player, uint8_t ward, uint8_t plot );
LandPurchaseResult purchseLand( Entity::Player& player, uint8_t plot, uint8_t state );
private: private:
using HousingZonePtrMap = std::unordered_map< uint16_t, Core::Data::HousingZonePtr >; using HousingZonePtrMap = std::unordered_map< uint16_t, Core::Data::HousingZonePtr >;

View file

@ -129,13 +129,14 @@ void Core::HousingZone::sendLandSet( Entity::Player& player )
for( uint8_t i = startIndex, count = 0; i < ( startIndex + 30 ); ++i, ++count ) for( uint8_t i = startIndex, count = 0; i < ( startIndex + 30 ); ++i, ++count )
{ {
landsetInitializePacket->data().land[ count ].plotSize = getLand( i )->getSize(); auto pLand = getLand( i );
landsetInitializePacket->data().land[ count ].houseState = getLand( i )->getState(); landsetInitializePacket->data().land[ count ].plotSize = pLand->getSize();
landsetInitializePacket->data().land[ count ].type = static_cast< uint8_t >( getLand( i )->getLandType() ); landsetInitializePacket->data().land[ count ].houseState = pLand->getState();
landsetInitializePacket->data().land[ count ].iconAddIcon = getLand( i )->getSharing(); landsetInitializePacket->data().land[ count ].type = static_cast< uint8_t >( pLand->getLandType() );
landsetInitializePacket->data().land[ count ].fcId = getLand( i )->getFcId(); landsetInitializePacket->data().land[ count ].iconAddIcon = pLand->getSharing();
landsetInitializePacket->data().land[ count ].fcIcon = getLand( i )->getFcIcon(); landsetInitializePacket->data().land[ count ].fcId = pLand->getFcId();
landsetInitializePacket->data().land[ count ].fcIconColor = getLand( i )->getFcColor(); landsetInitializePacket->data().land[ count ].fcIcon = pLand->getFcIcon();
landsetInitializePacket->data().land[ count ].fcIconColor = pLand->getFcColor();
} }
player.queuePacket( landsetInitializePacket ); player.queuePacket( landsetInitializePacket );
@ -143,10 +144,10 @@ void Core::HousingZone::sendLandSet( Entity::Player& player )
void Core::HousingZone::sendLandUpdate( uint8_t landId ) void Core::HousingZone::sendLandUpdate( uint8_t landId )
{ {
auto pLand = getLand( landId );
for( const auto& playerIt : m_playerMap ) for( const auto& playerIt : m_playerMap )
{ {
auto pPlayer = playerIt.second; auto pPlayer = playerIt.second;
auto pLand = getLand( landId );
auto landUpdatePacket = makeZonePacket< FFXIVIpcLandUpdate >( pPlayer->getId() ); auto landUpdatePacket = makeZonePacket< FFXIVIpcLandUpdate >( pPlayer->getId() );
landUpdatePacket->data().landId = landId; landUpdatePacket->data().landId = landId;
@ -167,63 +168,11 @@ bool Core::HousingZone::isPlayerSubInstance( Entity::Player& player )
return player.getPos().x < -15000.0f; //ToDo: get correct pos return player.getPos().x < -15000.0f; //ToDo: get correct pos
} }
Core::LandPurchaseResult Core::HousingZone::purchseLand( Entity::Player& player, uint8_t plot, uint8_t state )
{
auto plotPrice = getLand( plot )->getCurrentPrice();
auto gilAvailable = player.getCurrency( CurrencyType::Gil );
auto pLand = getLand( plot );
if( !pLand )
return LandPurchaseResult::ERR_INTERNAL;
if( pLand->getState() != HouseState::forSale )
return LandPurchaseResult::ERR_NOT_AVAILABLE;
if( gilAvailable < plotPrice )
return LandPurchaseResult::ERR_NOT_ENOUGH_GIL;
auto pHousing = std::dynamic_pointer_cast< HousingZone >( player.getCurrentZone() );
switch( static_cast< LandPurchaseMode >( state ) )
{
case LandPurchaseMode::FC:
player.sendDebug( "Free company house purchase aren't supported at this time." );
return LandPurchaseResult::ERR_INTERNAL;
case LandPurchaseMode::PRIVATE:
{
auto pHousingMgr = g_fw.get< HousingMgr >();
auto pOldLand = pHousingMgr->getLandByOwnerId( player.getId() );
if( pOldLand )
return LandPurchaseResult::ERR_NO_MORE_LANDS_FOR_CHAR;
player.removeCurrency( CurrencyType::Gil, plotPrice );
pLand->setPlayerOwner( player.getId() );
pLand->setState( HouseState::sold );
pLand->setLandType( Common::LandType::Private );
player.setLandPermissions( LandPermissionSlot::Private, 0x00, plot,
pHousing->getWardNum(), pHousing->getTerritoryTypeId() );
player.sendLandPermissions();
//pLand->setLandName( "Private Estate" + std::to_string( pHousing->getWardNum() ) + "-" + std::to_string( plot ) );
pLand->UpdateLandDb();
sendLandUpdate( plot );
return LandPurchaseResult::SUCCESS;
}
default:
return LandPurchaseResult::ERR_INTERNAL;
}
}
void Core::HousingZone::onUpdate( uint32_t currTime ) void Core::HousingZone::onUpdate( uint32_t currTime )
{ {
for( uint8_t i = 0; i < 60; i++ ) for( auto pLandItr : m_landPtrMap )
{ {
getLand( i )->Update( currTime ); pLandItr.second->update( currTime );
} }
} }

View file

@ -42,8 +42,6 @@ namespace Core
void sendLandUpdate( uint8_t landId ); void sendLandUpdate( uint8_t landId );
bool isPlayerSubInstance( Entity::Player& player ); bool isPlayerSubInstance( Entity::Player& player );
LandPurchaseResult purchseLand( Entity::Player& player, uint8_t plot, uint8_t state );
/* returns current ward number for this zone */ /* returns current ward number for this zone */
uint8_t getWardNum() const; uint8_t getWardNum() const;
@ -60,4 +58,4 @@ namespace Core
}; };
} }
#endif //SAPPHIRE_HOUSINGZONE_H #endif //SAPPHIRE_HOUSINGZONE_H

View file

@ -224,7 +224,7 @@ void Core::Land::init()
} }
} }
void Core::Land::UpdateLandDb() void Core::Land::updateLandDb()
{ {
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >(); auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
pDb->directExecute( "UPDATE land SET status = " + std::to_string( m_state ) pDb->directExecute( "UPDATE land SET status = " + std::to_string( m_state )
@ -237,7 +237,7 @@ void Core::Land::UpdateLandDb()
+ " AND LandId = " + std::to_string( m_landId ) + ";" ); + " AND LandId = " + std::to_string( m_landId ) + ";" );
} }
void Core::Land::Update( uint32_t currTime ) void Core::Land::update( uint32_t currTime )
{ {
if( getState() == HouseState::forSale ) if( getState() == HouseState::forSale )
{ {
@ -245,7 +245,7 @@ void Core::Land::Update( uint32_t currTime )
{ {
m_nextDrop = currTime + 21600; m_nextDrop = currTime + 21600;
m_currentPrice = ( m_currentPrice / 100 ) * 99.58; m_currentPrice = ( m_currentPrice / 100 ) * 99.58;
UpdateLandDb(); updateLandDb();
} }
} }
} }

View file

@ -47,8 +47,8 @@ namespace Core
uint32_t getPlayerOwner(); uint32_t getPlayerOwner();
//Housing Functions //Housing Functions
void setPreset( uint32_t itemId ); void setPreset( uint32_t itemId );
void UpdateLandDb(); void updateLandDb();
void Update( uint32_t currTime ); void update( uint32_t currTime );
uint32_t getMaxItems(); uint32_t getMaxItems();
uint32_t getCurrentPrice() const; uint32_t getCurrentPrice() const;

View file

@ -277,8 +277,8 @@ void Core::Zone::removeActor( Entity::ActorPtr pActor )
} }
void Core::Zone::queueOutPacketForRange( Entity::Player& sourcePlayer, uint32_t range, void Core::Zone::queuePacketForRange( Entity::Player& sourcePlayer, uint32_t range,
Network::Packets::FFXIVPacketBasePtr pPacketEntry ) Network::Packets::FFXIVPacketBasePtr pPacketEntry )
{ {
auto pTeriMgr = g_fw.get< TerritoryMgr >(); auto pTeriMgr = g_fw.get< TerritoryMgr >();
if( pTeriMgr->isPrivateTerritory( getTerritoryTypeId() ) ) if( pTeriMgr->isPrivateTerritory( getTerritoryTypeId() ) )
@ -306,6 +306,28 @@ void Core::Zone::queueOutPacketForRange( Entity::Player& sourcePlayer, uint32_t
} }
} }
void Core::Zone::queuePacketForZone( Entity::Player& sourcePlayer,
Network::Packets::FFXIVPacketBasePtr pPacketEntry,
bool forSelf )
{
auto pTeriMgr = g_fw.get< TerritoryMgr >();
if( pTeriMgr->isPrivateTerritory( getTerritoryTypeId() ) )
return;
auto pServerZone = g_fw.get< ServerZone >();
for( auto entry : m_playerMap )
{
auto player = entry.second;
if( ( sourcePlayer.getId() != player->getId() ) ||
( ( sourcePlayer.getId() == player->getId() ) && forSelf ) )
{
auto pSession = pServerZone->getSession( player->getId() );
if( pSession )
pSession->getZoneConnection()->queueOutPacket( pPacketEntry );
}
}
}
uint32_t Core::Zone::getTerritoryTypeId() const uint32_t Core::Zone::getTerritoryTypeId() const
{ {
return m_territoryTypeId; return m_territoryTypeId;

View file

@ -114,8 +114,11 @@ public:
void updateInRangeSet( Entity::ActorPtr pActor, Cell* pCell ); void updateInRangeSet( Entity::ActorPtr pActor, Cell* pCell );
void queueOutPacketForRange( Entity::Player& sourcePlayer, uint32_t range, void queuePacketForRange( Entity::Player& sourcePlayer, uint32_t range,
Network::Packets::FFXIVPacketBasePtr pPacketEntry ); Network::Packets::FFXIVPacketBasePtr pPacketEntry );
void queuePacketForZone( Entity::Player& sourcePlayer, Network::Packets::FFXIVPacketBasePtr pPacketEntry,
bool forSelf = false );
uint32_t getGuId() const; uint32_t getGuId() const;