mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-26 14:37:44 +00:00
commit
23b5d4ce21
28 changed files with 391 additions and 74 deletions
|
@ -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`;
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -233,6 +233,13 @@ struct FFXIVIpcSetSharedEstateSettings :
|
|||
/* 0029 */ char padding3[0x7];
|
||||
};
|
||||
|
||||
struct FFXIVIpcMarketBoardRequestItemListings :
|
||||
FFXIVIpcBasePacket< MarketBoardRequestItemListings >
|
||||
{
|
||||
/* 0000 */ uint32_t itemCatalogId;
|
||||
/* 0004 */ uint32_t padding;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 );
|
||||
} );
|
||||
}
|
||||
};
|
|
@ -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 )
|
||||
{
|
||||
|
||||
} );
|
||||
}
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
} );
|
||||
}
|
||||
};
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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() );
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue