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

Merge pull request #446 from NotAdam/housing

more housing
This commit is contained in:
Mordred 2018-12-02 18:27:50 +01:00 committed by GitHub
commit 23b5d4ce21
28 changed files with 391 additions and 74 deletions

View file

@ -1,4 +1,5 @@
ALTER TABLE `land` ADD `Type` SMALLINT(6) NOT NULL DEFAULT '0' AFTER `LandId`;
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`;
ALTER TABLE `house` ADD `HousePartColours` BINARY(8) DEFAULT "" AFTER `HousePartModels`;
ALTER TABLE `house` ADD `HouseInteriorModels` BINARY(40) DEFAULT "" AFTER `HousePartColours`;

View file

@ -751,6 +751,20 @@ namespace Sapphire::Common
YardSign
};
enum HousingInteriorSlot
{
InteriorWall,
InteriorFloor,
InteriorLight,
InteriorWall_Attic,
InteriorFloor_Attic,
InteriorLight_Attic,
InteriorWall_Basement,
InteriorFloor_Basement,
InteriorLight_Basement,
InteriorLight_Mansion
};
enum HouseTagSlot
{
MainTag,

View file

@ -197,7 +197,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
CONNECTION_BOTH );
prepareStatement( HOUSING_HOUSE_UP,
"UPDATE house SET BuildTime = ?, Aetheryte = ?, Comment = ?, HouseName = ?, Endorsements = ?, HousePartModels = ?, HousePartColours = ? WHERE HouseId = ?;",
"UPDATE house SET BuildTime = ?, Aetheryte = ?, Comment = ?, HouseName = ?, Endorsements = ?, HousePartModels = ?, HousePartColours = ?, HouseInteriorModels = ? WHERE HouseId = ?;",
CONNECTION_BOTH );
/*prepareStatement( LAND_INS,

View file

@ -207,23 +207,38 @@ enum ActorControlType : uint16_t
Dismount = 0x3A0,
// Duty Recorder
BeginReplayAck = 0x3A1,
BeginReplayAck = 0x3A1,
EndReplayAck = 0x3A2,
// Housing
ShowHousingItemUI = 0x3F7,
ShowHousingItemUI = 0x3F7,
ShowBuildPresetUI = 0x3E9,
BuildPresetResponse = 0x3ED,
/*!
* param1 = outdoor furnishings
* u8 0 - relocation available, 1 = available
* u8 1 - outoor furnishings placed
* u8 2 - outdoor furnishings in storeroom
* u8 3 - outdoor funishings limit
* param2 = indoor furnishings
* u16 0 - relocation available, 1 = available
* u16 1 - furnishings placed
* param3 = indoor furnishings
* u16 0 - in storeroom
* u16 1 - indoor furnishings limit
*/
HousingStoreroomStatus = 0x419,
// PvP Duel
SetPvPState = 0x5E0, // param3 must be 6 to engage a duel (hardcoded in the client)
SetPvPState = 0x5E0, // param3 must be 6 to engage a duel (hardcoded in the client)
EndDuelSession = 0x5E1, // because someone went oob?
StartDuelCountdown = 0x5E2, // begins a countdown; also does some duel bgm thing.
StartDuel = 0x5E3, // actually all it does is set the challenger actor id;
DuelResultScreen = 0x5E4, // win/lose thing, also reset a target id just like what EndDuelSession does.
// Duty Action
SetDutyActionId = 0x5E8, // ContentExAction
SetDutyActionId = 0x5E8, // ContentExAction
SetDutyActionHud = 0x5E9, // disable/enable
SetDutyActionActive = 0x5EA,
SetDutyActionRemaining = 0x5EB,
@ -304,6 +319,7 @@ enum ActorControlType : uint16_t
RequestHousingItemUI = 0x463,
RequestSharedEstateSettings = 0x46F,
UpdateEstateLightingLevel = 0x471,
CompanionAction = 0x6A4,
CompanionSetBarding = 0x6A5,

View file

@ -97,10 +97,15 @@ namespace Sapphire::Network::Packets
ReqMoogleMailLetter = 0x011A, // updated 4.4
MailLetterNotification = 0x011B, // updated 4.4
ExamineFreeCompanyInfo = 0x013A, // updated 4.1
MarketBoardItemListingCount = 0x011C, // updated 4.4
MarketBoardItemListing = 0x011D, // updated 4.4
MarketBoardItemListingHistory = 0x0121, // updated 4.4
MarketBoardSearchResult = 0x0125, // updated 4.4
CharaFreeCompanyTag = 0x0127, // updated 4.4
FreeCompanyBoardMsg = 0x0128, // updated 4.4
FreeCompanyInfo = 0x0129, // updated 4.4
ExamineFreeCompanyInfo = 0x013A, // updated 4.1
StatusEffectList = 0x0149, // updated 4.4
Effect = 0x014C, // updated 4.4
@ -186,7 +191,7 @@ namespace Sapphire::Network::Packets
LandSetInitialize = 0x0220, // updated 4.4
LandUpdate = 0x0221, // updated 4.4
YardObjectSpawn = 0x0222, // updated 4.4
HousingIndoorInitialize = 0x0223,
LandPriceUpdate = 0x0224, // updated 4.4
LandInfoSign = 0x0225, // updated 4.4
LandRename = 0x0226, // updated 4.4
@ -195,7 +200,7 @@ namespace Sapphire::Network::Packets
HousingLandFlags = 0x0229, // updated 4.4
HousingShowEstateGuestAccess = 0x022A, // updated 4.4
LandSetYardInitialize = 0x022C, // updated 4.4
HousingObjectInitialize = 0x022C, // updated 4.4
HousingWardInfo = 0x022F, // updated 4.4
YardObjectMove = 0x0230, // updated 4.4
@ -258,6 +263,9 @@ namespace Sapphire::Network::Packets
LinkshellListHandler = 0x00F4, // updated 4.3
MarketBoardRequestItemInformation = 0x00FE, // updated 4.4
MarketBoardRequestItemListings = 0x00FF, // updated 4.4
SearchMarketboard = 0x0103, // updated 4.3
ReqExamineFcInfo = 0x010F, // updated 4.1

View file

@ -233,6 +233,13 @@ struct FFXIVIpcSetSharedEstateSettings :
/* 0029 */ char padding3[0x7];
};
struct FFXIVIpcMarketBoardRequestItemListings :
FFXIVIpcBasePacket< MarketBoardRequestItemListings >
{
/* 0000 */ uint32_t itemCatalogId;
/* 0004 */ uint32_t padding;
};
}
}
}

View file

@ -1704,17 +1704,27 @@ struct FFXIVIpcYardObjectMove : FFXIVIpcBasePacket<YardObjectMove>
uint16_t unknown3;
};
struct FFXIVIpcLandSetYardInitialize : FFXIVIpcBasePacket< LandSetYardInitialize >
struct FFXIVIpcHousingObjectInitialize : FFXIVIpcBasePacket< HousingObjectInitialize >
{
uint32_t unknown1; //always 0xFFFFFFFF
uint32_t unknown2; //always 0xFFFFFFFF
uint8_t unknown3; //always 0xFF
Common::LandIdent landIdent;
int8_t u1; //Outdoor -1 / Indoor 0 - probably indicator
uint8_t packetNum;
uint16_t packetTotal;
uint8_t packetTotal;
uint8_t u2; //Outdoor 0 / Indoor 100(?)
Common::YardObject object[100];
uint32_t unknown4; //unused
};
struct FFXIVIpcHousingIndoorInitialize : FFXIVIpcBasePacket< HousingIndoorInitialize >
{
uint16_t u1;
uint16_t u2;
uint16_t u3;
uint16_t u4;
uint32_t indoorItems[10];
};
struct FFXIVIpcHousingWardInfo : FFXIVIpcBasePacket< HousingWardInfo >
{
Common::LandIdent landIdent;
@ -1820,6 +1830,52 @@ struct FFXIVIpcDuelChallenge :
char otherName[32];
};
struct FFXIVIpcMarketBoardSearchResult :
FFXIVIpcBasePacket< MarketBoardSearchResult >
{
struct MarketBoardItem
{
uint32_t itemCatalogId;
uint32_t quantity;
} items[20];
uint32_t itemIndexEnd;
uint32_t padding1;
uint32_t itemIndexStart;
uint32_t padding2;
};
struct FFFXIVIpcMarketBoardItemListingCount :
FFXIVIpcBasePacket< MarketBoardItemListingCount >
{
uint32_t itemCatalogId;
uint32_t unknown1; // does some shit if nonzero
uint16_t unknown2;
uint16_t quantity; // high/low u8s read separately?
uint32_t padding3;
};
struct FFXIVIpcMarketBoardItemListingHistory :
FFXIVIpcBasePacket< MarketBoardItemListingHistory >
{
uint32_t itemCatalogId;
uint32_t itemCatalogId2;
struct MarketListing
{
uint32_t salePrice;
time_t purchaseTime;
uint32_t quantity;
uint16_t unknown1;
uint8_t unknown2;
char sellerName[32];
uint8_t unknown3;
uint32_t itemCatalogId;
} listing[20];
};
} /* Server */
} /* Packets */

View file

@ -23,6 +23,10 @@ public:
player.playScene( eventId, 0, 0, [this, eobj]( Entity::Player& player, const Event::SceneResult& result )
{
// param2 == 1 when player wants to enter house
if( result.param2 != 1 )
return;
auto terriMgr = getFramework()->get< Sapphire::World::Manager::TerritoryMgr >();
if( !terriMgr )
return;
@ -35,6 +39,7 @@ public:
ident.landId = eobj.getHousingLink() >> 8;
ident.territoryTypeId = zone->getTerritoryTypeId();
ident.wardNum = zone->getWardNum();
ident.worldId = 67;
auto internalZone = terriMgr->findOrCreateHousingInterior( ident );
if( internalZone )
@ -42,10 +47,10 @@ public:
player.sendDebug( "created zone with guid: " + std::to_string( internalZone->getGuId() ) + "\nname: " + internalZone->getName() );
}
if( result.param2 != 1 )
return;
player.eventFinish( result.eventId, 1 );
// param2 == 1, zone into instance
player.setPos( { 0.f, 0.f, 0.f } );
player.setInstance( internalZone );
} );
}
};

View file

@ -0,0 +1,21 @@
#include <ScriptObject.h>
#include <Actor/Player.h>
using namespace Sapphire;
class CmnDefHousingPersonalRoomEntrance : public Sapphire::ScriptAPI::EventScript
{
public:
CmnDefHousingPersonalRoomEntrance() :
Sapphire::ScriptAPI::EventScript( 0x000b00b2 )
{
}
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
player.playScene( eventId, 0, 0, []( Entity::Player& player, const Event::SceneResult& result )
{
} );
}
};

View file

@ -5,6 +5,7 @@
#include <Manager/HousingMgr.h>
#include <Network/PacketWrappers/ActorControlPacket143.h>
#include <Network/CommonActorControl.h>
#include <Exd/ExdDataGenerated.h>
#include "Framework.h"
@ -47,37 +48,32 @@ public:
{
auto screenMsgPkt = makeActorControl143( player.getId(), ActorControl::DutyQuestScreenMsg, m_id, 0x98 );
player.queuePacket( screenMsgPkt );
auto screenMsgPkt2 = makeActorControl143( player.getId(), ActorControl::LogMsg, 0x0D16, 0x1AA,
activeLand.ward + 1, activeLand.plot + 1 );
player.queuePacket( screenMsgPkt2 );
player.sendLogMessage( 0x0D16, pTerritory->getTerritoryTypeInfo()->placeName, activeLand.ward + 1, activeLand.plot + 1 );
break;
}
case LandPurchaseResult::ERR_NOT_ENOUGH_GIL:
{
auto errorMsg = makeActorControl143( player.getId(), ActorControl::LogMsg, 3314 );
player.queuePacket( errorMsg );
player.sendLogMessage( 3314 );
break;
}
case LandPurchaseResult::ERR_NOT_AVAILABLE:
{
auto errorMsg = makeActorControl143( player.getId(), ActorControl::LogMsg, 3312 );
player.queuePacket( errorMsg );
player.sendLogMessage( 3312 );
break;
}
case LandPurchaseResult::ERR_NO_MORE_LANDS_FOR_CHAR:
{
auto errorMsg = makeActorControl143( player.getId(), ActorControl::LogMsg, 3313 );
player.queuePacket( errorMsg );
player.sendLogMessage( 3313 );
break;
}
case LandPurchaseResult::ERR_INTERNAL:
{
auto errorMsg = makeActorControl143( player.getId(), ActorControl::LogMsg, 1995 );
player.queuePacket( errorMsg );
player.sendLogMessage( 1995 );
break;
}
}

View file

@ -0,0 +1,25 @@
#include <ScriptObject.h>
#include <Actor/Player.h>
using namespace Sapphire;
class HousingWarpTaxiExitEstate : public Sapphire::ScriptAPI::EventScript
{
public:
HousingWarpTaxiExitEstate() :
Sapphire::ScriptAPI::EventScript( 0x0002004d )
{
}
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
player.playScene( eventId, 0, 0, []( Entity::Player& player, const Event::SceneResult& result )
{
if( result.param2 == 1 )
{
player.eventFinish( result.eventId, 1 );
player.exitInstance();
}
} );
}
};

View file

@ -64,7 +64,7 @@ void PlayerMinimal::load( uint32_t charId )
m_guardianDeity = res->getUInt8( "GuardianDeity" );
m_class = res->getUInt8( "Class" );
m_contentId = res->getUInt64( "ContentId" );
m_zoneId = res->getUInt16( "TerritoryType" );
m_territoryTypeId = res->getUInt16( "TerritoryType" );
res.reset();

View file

@ -131,7 +131,7 @@ namespace Sapphire
uint32_t getZoneId() const
{
return m_zoneId;
return m_territoryTypeId;
}
uint32_t getTribe() const
@ -185,7 +185,7 @@ namespace Sapphire
uint8_t m_tribe;
uint16_t m_zoneId;
uint16_t m_territoryTypeId;
uint64_t m_modelMainWeapon;
uint64_t m_modelSubWeapon;

View file

@ -30,7 +30,7 @@ namespace Sapphire::Entity
/*! Type of the actor */
Common::ObjKind m_objKind;
/*! Id of the zone the actor currently is in */
uint32_t m_zoneId;
uint32_t m_territoryTypeId;
/*! Ptr to the ZoneObj the actor belongs to */
ZonePtr m_pCurrentZone;

View file

@ -128,7 +128,7 @@ uint32_t Sapphire::Entity::Player::getMaxMp()
uint16_t Sapphire::Entity::Player::getZoneId() const
{
return m_zoneId;
return m_territoryTypeId;
}
uint32_t Sapphire::Entity::Player::getTerritoryId() const
@ -414,9 +414,9 @@ void Sapphire::Entity::Player::setZone( uint32_t zoneId )
// todo: this will require proper handling, for now just return the player to their previous area
m_pos = m_prevPos;
m_rot = m_prevRot;
m_zoneId = m_prevZoneId;
m_territoryTypeId = m_prevTerritoryTypeId;
if( !pTeriMgr->movePlayer( m_zoneId, getAsPlayer() ) )
if( !pTeriMgr->movePlayer( m_territoryTypeId, getAsPlayer() ) )
return;
}
@ -442,12 +442,15 @@ bool Sapphire::Entity::Player::setInstance( ZonePtr instance )
auto pTeriMgr = g_fw.get< TerritoryMgr >();
auto currentZone = getCurrentZone();
// zoning within the same zone won't cause the prev data to be overwritten
if( instance->getTerritoryTypeId() != m_zoneId )
if( instance->getTerritoryTypeId() != m_territoryTypeId )
{
m_prevPos = m_pos;
m_prevRot = m_rot;
m_prevZoneId = m_zoneId;
m_prevTerritoryTypeId = currentZone->getTerritoryTypeId();
m_prevTerritoryId = getTerritoryId();
}
if( !pTeriMgr->movePlayer( instance, getAsPlayer() ) )
@ -461,12 +464,23 @@ bool Sapphire::Entity::Player::setInstance( ZonePtr instance )
bool Sapphire::Entity::Player::exitInstance()
{
auto pTeriMgr = g_fw.get< TerritoryMgr >();
if( !pTeriMgr->movePlayer( m_prevZoneId, getAsPlayer() ) )
return false;
// check if housing zone
if( pTeriMgr->isHousingTerritory( m_prevTerritoryTypeId ) )
{
if( !pTeriMgr->movePlayer( pTeriMgr->getZoneByLandSetId( m_prevTerritoryId ), getAsPlayer() ) )
return false;
}
else
{
if( !pTeriMgr->movePlayer( m_prevTerritoryTypeId, getAsPlayer() ) )
return false;
}
m_pos = m_prevPos;
m_rot = m_prevRot;
m_zoneId = m_prevZoneId;
m_territoryTypeId = m_prevTerritoryTypeId;
m_territoryId = m_prevTerritoryId;
sendZonePackets();
@ -1232,7 +1246,7 @@ void Sapphire::Entity::Player::setLoadingComplete( bool bComplete )
void Sapphire::Entity::Player::performZoning( uint16_t zoneId, const Common::FFXIVARR_POSITION3& pos, float rotation )
{
m_pos = pos;
m_zoneId = zoneId;
m_territoryTypeId = zoneId;
m_bMarkedForZoning = true;
setRot( rotation );
setZone( zoneId );
@ -1530,12 +1544,12 @@ void Sapphire::Entity::Player::setEorzeaTimeOffset( uint64_t timestamp )
void Sapphire::Entity::Player::setTerritoryTypeId( uint32_t territoryTypeId )
{
m_zoneId = territoryTypeId;
m_territoryTypeId = territoryTypeId;
}
uint32_t Sapphire::Entity::Player::getTerritoryTypeId() const
{
return m_zoneId;
return m_territoryTypeId;
}
void Sapphire::Entity::Player::sendZonePackets()

View file

@ -945,8 +945,8 @@ namespace Sapphire::Entity
InventoryMap m_storageMap;
Common::FFXIVARR_POSITION3 m_prevPos;
uint32_t m_prevZoneType;
uint32_t m_prevZoneId;
uint32_t m_prevTerritoryTypeId;
uint32_t m_prevTerritoryId;
float m_prevRot;
uint8_t m_voice;

View file

@ -52,7 +52,8 @@ bool Sapphire::Entity::Player::load( uint32_t charId, SessionPtr pSession )
auto zoneId = res->getUInt( "TerritoryType" );
m_territoryId = res->getUInt( "TerritoryId" );
m_prevZoneId = res->getUInt( "OTerritoryType" );
m_prevTerritoryTypeId = res->getUInt( "OTerritoryType" );
m_prevTerritoryId = res->getUInt( "OTerritoryId" );
// Position
m_pos.x = res->getFloat( "PosX" );
@ -75,7 +76,7 @@ bool Sapphire::Entity::Player::load( uint32_t charId, SessionPtr pSession )
// if none found, revert to previous zone and position
if( !pCurrZone )
{
zoneId = m_prevZoneId;
zoneId = m_prevTerritoryTypeId;
m_pos.x = m_prevPos.x;
m_pos.y = m_prevPos.y;
m_pos.z = m_prevPos.z;
@ -92,7 +93,7 @@ bool Sapphire::Entity::Player::load( uint32_t charId, SessionPtr pSession )
pCurrZone = pTeriMgr->getZoneByTerritoryTypeId( zoneId );
}
m_zoneId = zoneId;
m_territoryTypeId = zoneId;
// TODO: logic for instances needs to be added here
// see if a valid zone could be found for the character
@ -370,15 +371,15 @@ void Sapphire::Entity::Player::updateSql()
stmt->setInt( 16, static_cast< uint32_t >( m_bNewGame ) );
stmt->setInt( 17, static_cast< uint32_t >( m_bNewAdventurer ) );
stmt->setInt( 18, m_zoneId ); // TerritoryType
stmt->setInt( 18, m_territoryTypeId ); // TerritoryType
stmt->setInt( 19, m_territoryId ); // TerritoryId
stmt->setDouble( 20, m_pos.x );
stmt->setDouble( 21, m_pos.y );
stmt->setDouble( 22, m_pos.z );
stmt->setDouble( 23, getRot() );
stmt->setInt( 24, m_prevZoneId ); // OTerritoryType
stmt->setInt( 25, m_prevZoneType ); // OTerritoryId
stmt->setInt( 24, m_prevTerritoryTypeId ); // OTerritoryType
stmt->setInt( 25, m_prevTerritoryId ); // OTerritoryId
stmt->setDouble( 26, m_prevPos.x );
stmt->setDouble( 27, m_prevPos.y );
stmt->setDouble( 28, m_prevPos.z );

View file

@ -342,7 +342,7 @@ Sapphire::ZonePtr Sapphire::World::Manager::TerritoryMgr::findOrCreateHousingInt
if( !terriInfo )
return nullptr;
auto zone = World::Territory::Housing::make_HousingInteriorTerritory( ident, territoryTypeId, getNextInstanceId(),
auto zone = World::Territory::Housing::make_HousingInteriorTerritory( landIdent, territoryTypeId, getNextInstanceId(),
terriInfo->name, house->getHouseName() );
zone->init();
@ -446,6 +446,29 @@ void Sapphire::World::Manager::TerritoryMgr::updateTerritoryInstances( uint32_t
{
zone->update( currentTime );
}
auto pLog = g_fw.get< Logger >();
// remove internal house zones with nobody in them
for( auto it = m_landIdentToZonePtrMap.begin(); it != m_landIdentToZonePtrMap.end(); )
{
auto zone = std::dynamic_pointer_cast< Territory::Housing::HousingInteriorTerritory >( it->second );
assert( zone ); // wtf??
auto diff = std::difftime( currentTime, zone->getLastActivityTime() );
// todo: make this timeout configurable, though should be pretty relaxed in any case
if( diff > 60 )
{
pLog->info( "Removing HousingInteriorTerritory#" + std::to_string( zone->getGuId() ) + " - has been inactive for 60 seconds" );
// remove zone from maps
m_zoneSet.erase( zone );
it = m_landIdentToZonePtrMap.erase( it );
}
else
it++;
}
}
Sapphire::World::Manager::TerritoryMgr::InstanceIdList Sapphire::World::Manager::TerritoryMgr::getInstanceContentIdList( uint16_t instanceContentId ) const

View file

@ -411,7 +411,13 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX
}
case ClientTriggerType::RequestHousingItemUI:
{
uint8_t ward = ( param12 & 0xFF00 ) >> 8;
// close ui
if( param11 == 1 )
break;
// param12 is 0 when inside a house
uint8_t ward = ( param12 >> 16 ) & 0xFF;
uint8_t plot = ( param12 & 0xFF );
auto pShowHousingItemUIPacket = makeActorControl142( player.getId(), ShowHousingItemUI, 0, plot );

View file

@ -48,11 +48,18 @@ Sapphire::House::House( uint32_t houseId, uint32_t landSetId, uint8_t landId, ui
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 ];
}
}
}
@ -67,7 +74,7 @@ void Sapphire::House::updateHouseDb()
// 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->setUInt( 9, m_houseId );
stmt->setInt64( 1, m_buildTime );
stmt->setInt( 2, 0 );
@ -94,6 +101,18 @@ void Sapphire::House::updateHouseDb()
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 );
}
@ -127,6 +146,11 @@ uint8_t Sapphire::House::getHousePartColor( Common::HousePartSlot slot ) const
return m_houseParts[ slot ].second;
}
uint32_t Sapphire::House::getHouseInteriorPart( Common::HousingInteriorSlot slot ) const
{
return m_houseInteriorParts[ slot ];
}
void Sapphire::House::setHousePart( Common::HousePartSlot slot, uint32_t id )
{
m_houseParts[ slot ].first = id;
@ -137,6 +161,11 @@ void Sapphire::House::setHousePartColor( Common::HousePartSlot slot, uint32_t id
m_houseParts[ slot ].second = id;
}
void Sapphire::House::setHouseInteriorPart( Common::HousingInteriorSlot slot, uint32_t id )
{
m_houseInteriorParts[ slot ] = id;
}
uint32_t Sapphire::House::getHousePart( Common::HousePartSlot slot ) const
{
return m_houseParts[ slot ].first;

View file

@ -34,8 +34,10 @@ namespace Sapphire
//functions
void setHousePart( Common::HousePartSlot slot, uint32_t id );
void setHousePartColor( Common::HousePartSlot slot, uint32_t id );
void setHouseInteriorPart( Common::HousingInteriorSlot slot, uint32_t id );
uint32_t getHousePart( Common::HousePartSlot slot ) const;
uint8_t getHousePartColor( Common::HousePartSlot slot ) const;
uint32_t getHouseInteriorPart( Common::HousingInteriorSlot slot ) const;
HousePartsArray const& getHouseParts() const;
@ -51,6 +53,7 @@ namespace Sapphire
uint64_t m_buildTime;
HousePartsArray m_houseParts;
uint32_t m_houseInteriorParts[10];
std::string m_estateMessage;
std::string m_houseName;

View file

@ -1,17 +1,41 @@
#include <Common.h>
#include <Logging/Logger.h>
#include <Util/Util.h>
#include <Util/UtilMath.h>
#include <Database/DatabaseDef.h>
#include <Exd/ExdDataGenerated.h>
#include <Network/GamePacketNew.h>
#include <Network/PacketDef/Zone/ServerZoneDef.h>
#include "Actor/Player.h"
#include "Actor/Actor.h"
#include "Actor/EventObject.h"
#include "Manager/HousingMgr.h"
#include "Territory/Land.h"
#include "Territory/House.h"
#include "Forwards.h"
#include "HousingInteriorTerritory.h"
#include "Common.h"
#include "Framework.h"
extern Sapphire::Framework g_fw;
using namespace Sapphire::Common;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::Server;
using namespace Sapphire::World::Manager;
using namespace Sapphire;
using namespace Sapphire::World::Territory;
Housing::HousingInteriorTerritory::HousingInteriorTerritory( uint64_t ident, uint16_t territoryTypeId,
Housing::HousingInteriorTerritory::HousingInteriorTerritory( Common::LandIdent ident, uint16_t territoryTypeId,
uint32_t guId,
const std::string& internalName,
const std::string& contentName ) :
Zone( territoryTypeId, guId, internalName, contentName ),
m_landIdent( ident )
{
m_lastActivityTime = static_cast< uint32_t >( Util::getTimeSeconds() );
}
Housing::HousingInteriorTerritory::~HousingInteriorTerritory()
@ -26,10 +50,56 @@ bool Housing::HousingInteriorTerritory::init()
void Housing::HousingInteriorTerritory::onPlayerZoneIn( Entity::Player& player )
{
auto pHousingMgr = g_fw.get< HousingMgr >();
auto pLog = g_fw.get< Logger >();
pLog->debug(
"HousingInteriorTerritory::onPlayerZoneIn: Zone#" + std::to_string( getGuId() ) + "|" + std::to_string( getTerritoryTypeId() ) +
", Entity#" + std::to_string( player.getId() ) );
auto indoorInitPacket = makeZonePacket< FFXIVIpcHousingIndoorInitialize >( player.getId() );
indoorInitPacket->data().u1 = 0;
indoorInitPacket->data().u2 = 0;
indoorInitPacket->data().u3 = 0;
indoorInitPacket->data().u4 = 0;
auto landSetId = pHousingMgr->toLandSetId( m_landIdent.territoryTypeId, m_landIdent.wardNum );
auto pLand = pHousingMgr->getHousingZoneByLandSetId( landSetId )->getLand( m_landIdent.landId );
auto pHouse = pLand->getHouse();
for( auto i = 0; i < 10; i++ )
{
indoorInitPacket->data().indoorItems[ i ] = pHouse->getHouseInteriorPart( (Common::HousingInteriorSlot)i );
}
uint32_t yardPacketNum;
uint32_t yardPacketTotal = 2 + pLand->getSize();
player.queuePacket( indoorInitPacket );
for( yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ )
{
auto objectInitPacket = makeZonePacket< FFXIVIpcHousingObjectInitialize >( player.getId() );
memcpy( &objectInitPacket->data().landIdent, &m_landIdent, sizeof( Common::LandIdent ) );
objectInitPacket->data().u1 = 0;
objectInitPacket->data().u2 = 100;
objectInitPacket->data().packetNum = yardPacketNum;
objectInitPacket->data().packetTotal = yardPacketTotal;
//TODO: Add Objects here
player.queuePacket( objectInitPacket );
}
}
void Housing::HousingInteriorTerritory::onUpdate( uint32_t currTime )
{
if( m_playerMap.size() > 0 )
m_lastActivityTime = currTime;
}
uint32_t Housing::HousingInteriorTerritory::getLastActivityTime() const
{
return m_lastActivityTime;
}

View file

@ -6,7 +6,7 @@ namespace Sapphire::World::Territory::Housing
class HousingInteriorTerritory : public Zone
{
public:
HousingInteriorTerritory( uint64_t ident, uint16_t territoryTypeId,
HousingInteriorTerritory( Common::LandIdent ident, uint16_t territoryTypeId,
uint32_t guId,
const std::string& internalName,
const std::string& contentName );
@ -18,7 +18,10 @@ namespace Sapphire::World::Territory::Housing
void onPlayerZoneIn( Entity::Player& player ) override;
void onUpdate( uint32_t currTime ) override;
uint32_t getLastActivityTime() const;
private:
uint64_t m_landIdent;
Common::LandIdent m_landIdent;
uint32_t m_lastActivityTime;
};
}

View file

@ -32,7 +32,7 @@ Sapphire::HousingZone::HousingZone( uint8_t wardNum,
const std::string& contentName ) :
Zone( territoryTypeId, guId, internalName, contentName ),
m_wardNum( wardNum ),
m_zoneId( territoryTypeId ),
m_territoryTypeId( territoryTypeId ),
m_landSetId( ( static_cast< uint32_t >( territoryTypeId ) << 16 ) | wardNum )
{
@ -49,13 +49,13 @@ bool Sapphire::HousingZone::init()
}
int housingIndex;
if( m_zoneId == 339 )
if( m_territoryTypeId == 339 )
housingIndex = 0;
else if( m_zoneId == 340 )
else if( m_territoryTypeId == 340 )
housingIndex = 1;
else if( m_zoneId == 341 )
else if( m_territoryTypeId == 341 )
housingIndex = 2;
else if( m_zoneId == 641 )
else if( m_territoryTypeId == 641 )
housingIndex = 3;
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
@ -96,16 +96,15 @@ void Sapphire::HousingZone::onPlayerZoneIn( Entity::Player& player )
for( yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ )
{
auto landsetYardInitializePacket = makeZonePacket< FFXIVIpcLandSetYardInitialize >( player.getId() );
landsetYardInitializePacket->data().unknown1 = 0xFFFFFFFF;
landsetYardInitializePacket->data().unknown2 = 0xFFFFFFFF;
landsetYardInitializePacket->data().unknown3 = 0xFF;
landsetYardInitializePacket->data().packetNum = yardPacketNum;
landsetYardInitializePacket->data().packetTotal = yardPacketTotal;
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;
//TODO: Add Objects here
player.queuePacket( landsetYardInitializePacket );
player.queuePacket( housingObjectInitializPacket );
}
auto landSetMap = makeZonePacket< FFXIVIpcLandSetMap >( player.getId() );

View file

@ -56,7 +56,7 @@ namespace Sapphire
LandPtrMap m_landPtrMap;
uint8_t m_wardNum;
uint32_t m_landSetId;
uint32_t m_zoneId;
uint32_t m_territoryTypeId;
};
}

View file

@ -332,10 +332,23 @@ bool Sapphire::Land::setPreset( uint32_t itemId )
m_pHouse = make_House( newId, getLandSetId(), getLandId(), getWardNum(), getTerritoryTypeId() );
}
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 ) );
getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorWall, convertItemIdToHousingItemId( housingPreset->interiorWall ) );
getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorFloor, convertItemIdToHousingItemId( housingPreset->interiorFlooring ) );
getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorLight, convertItemIdToHousingItemId( housingPreset->interiorLighting ) );
getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorWall_Attic, convertItemIdToHousingItemId( housingPreset->otherFloorWall ) );
getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorFloor_Attic, convertItemIdToHousingItemId( housingPreset->otherFloorFlooring ) );
getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorLight_Attic, convertItemIdToHousingItemId( housingPreset->otherFloorLighting ) );
getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorWall_Basement, convertItemIdToHousingItemId( housingPreset->basementWall ) );
getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorFloor_Basement, convertItemIdToHousingItemId( housingPreset->basementFlooring ) );
getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorLight_Basement, convertItemIdToHousingItemId( housingPreset->basementLighting ) );
getHouse()->setHouseInteriorPart( Common::HousingInteriorSlot::InteriorLight_Mansion, convertItemIdToHousingItemId( housingPreset->mansionLighting ) );
return true;
}

View file

@ -756,3 +756,8 @@ Sapphire::Entity::EventObjectPtr Sapphire::Zone::registerEObj( const std::string
return eObj;
}
Sapphire::Data::TerritoryTypePtr Sapphire::Zone::getTerritoryTypeInfo() const
{
return m_territoryTypeInfo;
}

View file

@ -16,7 +16,7 @@
#include <stdio.h>
#include <string.h>
namespace Sapphire
namespace Sapphire
{
class Session;
@ -76,6 +76,8 @@ namespace Sapphire
void setCurrentFestival( uint16_t festivalId, uint16_t additionalFestivalId = 0 );
std::shared_ptr< Data::TerritoryType > getTerritoryTypeInfo() const;
virtual bool init();
virtual void loadCellCache();