diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index deaea6a2..d8010c37 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -169,6 +169,10 @@ namespace Packets { EquipDisplayFlags = 0x0210, // updated 4.3 + WardInfo = 0x0224, // updated 4.3 + WardHousingPermission = 0x022D, // updated 4.3 + WardYardInfo = 0x022F, // updated 4.3 + DuelChallenge = 0x0277, // 4.2; this is responsible for opening the ui PerformNote = 0x0286, // updated 4.3 diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 58aad6ec..d213cd28 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1298,6 +1298,58 @@ struct FFXIVIpcPerformNote : FFXIVIpcBasePacket uint8_t data[32]; }; +struct FFXIVIpcWardInfo : FFXIVIpcBasePacket +{ + uint16_t unknown0; + uint16_t wardNum; // set 1 for "Mist, Ward 2" + uint16_t zoneId; + uint16_t worldId; + uint8_t unknown1; + uint8_t subInstance; // (default : 1/2) + uint8_t unknown3; + uint8_t unknown4; + uint8_t unknown5; + uint8_t unknown6; + uint8_t unknown7; + uint8_t unknown8; + struct { + uint8_t houseSize; //1 = small, 2 = middle, 3 = big; 1 + uint8_t houseState; //1 = for sell, 2 = sold, 3 = hasOwner, 0x0A = House sharing; 2 + uint8_t iconColor; //HouseState has to be 3; 1 = Private, 2 = FC House; 4 + uint8_t iconAddIcon; //Heart Icon = 2; 6 + uint32_t unknown9; //can be 0 (default) maybe fcId; 8 + uint32_t fcIcon; //can be 0 (default); 12 + uint32_t fcIconColor; //can be 0 (default); 16 + uint16_t houseRoofId; //18 + uint16_t houseFacadeId;//20 + uint16_t houseWindowId;//22 + uint16_t houseDoorId;//24 + uint8_t gardenData[4];//28 + uint16_t gardenSignId; //For fcIcon; 30 + uint16_t gardenFenceId; //32 + uint8_t color[8]; //40 + } landSet[30]; +}; + +struct FFXIVIpcWardYardInfo : FFXIVIpcBasePacket +{ + /* consistency check? */ + uint32_t unknown1; //always 0xFFFFFFFF + uint32_t unknown2; //always 0xFFFFFFFF + uint8_t unknown3; //always 0xFF + /* --- */ + uint8_t packetNum; + uint16_t packetTotal; + struct + { + uint32_t itemId; + uint16_t itemRotation; + uint16_t pos_x; + uint16_t pos_y; + uint16_t pos_z; + } object[100]; +}; + struct FFXIVIpcMSQTrackerProgress : FFXIVIpcBasePacket { uint32_t id; diff --git a/src/servers/sapphire_zone/Forwards.h b/src/servers/sapphire_zone/Forwards.h index 6335aeb7..b81d6dee 100644 --- a/src/servers/sapphire_zone/Forwards.h +++ b/src/servers/sapphire_zone/Forwards.h @@ -20,6 +20,7 @@ namespace Core { TYPE_FORWARD( Cell ); TYPE_FORWARD( Zone ); + TYPE_FORWARD( HousingZone ); TYPE_FORWARD( InstanceContent ); TYPE_FORWARD( Item ); TYPE_FORWARD( ItemContainer ); diff --git a/src/servers/sapphire_zone/Zone/HousingZone.cpp b/src/servers/sapphire_zone/Zone/HousingZone.cpp new file mode 100644 index 00000000..db6dc972 --- /dev/null +++ b/src/servers/sapphire_zone/Zone/HousingZone.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +#include +#include + +#include "Actor/Player.h" + +#include "Forwards.h" +#include "HousingZone.h" +#include "Framework.h" + +extern Core::Framework g_fw; + +using namespace Core::Common; +using namespace Core::Network::Packets; +using namespace Core::Network::Packets::Server; + +Core::HousingZone::HousingZone( uint8_t wardNum, + uint16_t territoryId, + uint32_t guId, + const std::string& internalName, + const std::string& contentName ) : + Zone( territoryId, guId, internalName, contentName ), + m_wardNum( wardNum ) +{ + +} + +bool Core::HousingZone::init() +{ + uint32_t landSetId; + + for( landSetId = 0; landSetId < 60; landSetId++ ) + { + //TODO: load house information here + } + + return true; +} + +Core::HousingZone::~HousingZone() +{ + +} + +void Core::HousingZone::onPlayerZoneIn( Entity::Player& player ) +{ + auto pLog = g_fw.get< Logger >(); + pLog->debug( "HousingZone::onPlayerZoneIn: Zone#" + std::to_string( getGuId() ) + "|" + + + ", Entity#" + std::to_string( player.getId() ) ); + + uint32_t landSetId; + uint32_t yardPacketNum; + uint32_t yardPacketTotal = 8; + + auto wardInfoPacket = makeZonePacket< FFXIVIpcWardInfo >( player.getId() ); + + wardInfoPacket->data().wardNum = m_wardNum; + wardInfoPacket->data().zoneId = player.getZoneId(); + //TODO: get current WorldId + wardInfoPacket->data().worldId = 67; + //TODO: handle Subdivision + wardInfoPacket->data().subInstance = 1; + + for( landSetId = 0; landSetId < 30 ; landSetId++ ) + { + wardInfoPacket->data().landSet[landSetId].houseSize = 1; + wardInfoPacket->data().landSet[landSetId].houseState = 1; + } + + player.queuePacket( wardInfoPacket ); + + for( yardPacketNum = 0; yardPacketNum < yardPacketTotal; yardPacketNum++ ) + { + auto wardYardInfoPacket = makeZonePacket< FFXIVIpcWardYardInfo >( player.getId() ); + wardYardInfoPacket->data().unknown1 = 0xFFFFFFFF; + wardYardInfoPacket->data().unknown2 = 0xFFFFFFFF; + wardYardInfoPacket->data().unknown3 = 0xFF; + wardYardInfoPacket->data().packetNum = yardPacketNum; + wardYardInfoPacket->data().packetTotal = yardPacketTotal; + + //TODO: Add Objects here + + player.queuePacket( wardYardInfoPacket ); + } + +} + +uint8_t Core::HousingZone::getWardNum() const +{ + return m_wardNum; +} diff --git a/src/servers/sapphire_zone/Zone/HousingZone.h b/src/servers/sapphire_zone/Zone/HousingZone.h new file mode 100644 index 00000000..428c50c9 --- /dev/null +++ b/src/servers/sapphire_zone/Zone/HousingZone.h @@ -0,0 +1,31 @@ +#ifndef SAPPHIRE_HOUSINGZONE_H +#define SAPPHIRE_HOUSINGZONE_H + +#include "Zone.h" +#include "Forwards.h" + +namespace Core +{ +class HousingZone : public Zone + { + public: + HousingZone( uint8_t wardNum, + uint16_t territoryId, + uint32_t guId, + const std::string& internalName, + const std::string& contentName ); + virtual ~HousingZone(); + + bool init() override; + void onPlayerZoneIn( Entity::Player& player ) override; + + /* returns current ward number for this zone */ + uint8_t getWardNum() const; + + const uint32_t m_wardMaxNum = 18; + private: + uint8_t m_wardNum; + }; + +} +#endif //SAPPHIRE_HOUSINGZONE_H diff --git a/src/servers/sapphire_zone/Zone/TerritoryMgr.cpp b/src/servers/sapphire_zone/Zone/TerritoryMgr.cpp index 6ec35837..a24033fa 100644 --- a/src/servers/sapphire_zone/Zone/TerritoryMgr.cpp +++ b/src/servers/sapphire_zone/Zone/TerritoryMgr.cpp @@ -7,6 +7,7 @@ #include "Actor/Player.h" #include "Zone.h" +#include "HousingZone.h" #include "ZonePosition.h" #include "InstanceContent.h" #include "TerritoryMgr.h" @@ -45,6 +46,7 @@ bool Core::TerritoryMgr::init() loadTerritoryPositionMap(); createDefaultTerritories(); + createHousingTerritories(); return true; } @@ -140,6 +142,53 @@ bool Core::TerritoryMgr::createDefaultTerritories() return true; } +bool Core::TerritoryMgr::createHousingTerritories() +{ + //separate housing zones from default + auto pExdData = g_fw.get< Data::ExdDataGenerated >(); + auto pLog = g_fw.get< Logger >(); + for( const auto& territory : m_territoryTypeDetailCacheMap ) + { + auto territoryId = territory.first; + auto territoryInfo = territory.second; + uint32_t wardNum; + uint32_t wardMaxNum = 1; + + if( territoryInfo->name.empty() ) + continue; + + auto pPlaceName = pExdData->get< Core::Data::PlaceName >( territoryInfo->placeName ); + + if( !pPlaceName || pPlaceName->name.empty() || !isHousingTerritory( territoryId ) ) + continue; + + for( wardNum = 0; wardNum < wardMaxNum; wardNum++ ) + { + uint32_t guid = getNextInstanceId(); + pLog->info( std::to_string( territoryId ) + + "\t" + std::to_string( guid ) + + "\t" + std::to_string( territoryInfo->territoryIntendedUse ) + + "\t" + ( territoryInfo->name.length() <= 4 ? territoryInfo->name + "\t" : territoryInfo->name ) + + "\t" + "HOUSING" + + "\t" + pPlaceName->name + + "#" + std::to_string( wardNum ) ); + + auto pHousingZone = make_HousingZone( wardNum, territoryId, guid, territoryInfo->name, pPlaceName->name ); + pHousingZone->init(); + wardMaxNum = pHousingZone->m_wardMaxNum; + + InstanceIdToZonePtrMap instanceMap; + instanceMap[guid] = pHousingZone; + m_instanceIdToZonePtrMap[guid] = pHousingZone; + m_territoryIdToInstanceGuidMap[territoryId][guid] = pHousingZone; + m_zoneSet.insert( { pHousingZone } ); + } + + } + + return true; +} + Core::ZonePtr Core::TerritoryMgr::createTerritoryInstance( uint32_t territoryTypeId ) { if( !isValidTerritory( territoryTypeId ) ) @@ -264,6 +313,16 @@ bool Core::TerritoryMgr::isDefaultTerritory( uint32_t territoryTypeId ) const } +bool Core::TerritoryMgr::isHousingTerritory(uint32_t territoryTypeId) const +{ + auto pTeri = getTerritoryDetail( territoryTypeId ); + + if( !pTeri ) + return false; + + return pTeri->territoryIntendedUse == TerritoryIntendedUse::HousingArea; +} + Core::ZonePositionPtr Core::TerritoryMgr::getTerritoryPosition( uint32_t territoryPositionId ) const { auto it = m_territoryPositionMap.find( territoryPositionId ); diff --git a/src/servers/sapphire_zone/Zone/TerritoryMgr.h b/src/servers/sapphire_zone/Zone/TerritoryMgr.h index 32d5532d..adafa145 100644 --- a/src/servers/sapphire_zone/Zone/TerritoryMgr.h +++ b/src/servers/sapphire_zone/Zone/TerritoryMgr.h @@ -66,6 +66,8 @@ namespace Core bool createDefaultTerritories(); + bool createHousingTerritories(); + /*! caches TerritoryType details into m_territoryTypeMap */ void loadTerritoryTypeDetailCache(); @@ -88,6 +90,9 @@ namespace Core /*! returns true if the territoryType is a default non-instanced zone */ bool isDefaultTerritory( uint32_t territoryTypeId ) const; + /*! returns true if the territoryType is a housing zone */ + bool isHousingTerritory( uint32_t territoryTypeId ) const; + /*! creates a new instance for a given territoryTypeId */ ZonePtr createTerritoryInstance( uint32_t territoryTypeId );