Core/PacketIO: Replace static_asserts with concepts and add them to PacketUtilities as well

This commit is contained in:
Shauren
2025-05-23 15:20:57 +02:00
parent 85e621f01a
commit 1027c42352
15 changed files with 492 additions and 412 deletions
+1 -3
View File
@@ -5542,7 +5542,7 @@ void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* info)
data.SpellID = aura->GetId();
data.LogData.Initialize(this);
WorldPackets::CombatLog::SpellPeriodicAuraLog::SpellLogEffect spellLogEffect;
WorldPackets::CombatLog::PeriodicAuraLogEffect& spellLogEffect = data.Effects.emplace_back();
spellLogEffect.Effect = aura->GetAuraType();
spellLogEffect.Amount = info->damage;
spellLogEffect.OriginalDamage = info->originalDamage;
@@ -5558,8 +5558,6 @@ void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* info)
if (contentTuningParams.GenerateDataForUnits(caster, this))
spellLogEffect.ContentTuning = contentTuningParams;
data.Effects.push_back(spellLogEffect);
SendCombatLogMessage(&data);
}
@@ -86,6 +86,103 @@ void AuthSession::Read()
}
}
ByteBuffer& operator<<(ByteBuffer& data, GameTime const& gameTime)
{
data << uint32(gameTime.BillingType);
data << uint32(gameTime.MinutesRemaining);
data << uint32(gameTime.RealBillingType);
data << Bits<1>(gameTime.IsInIGR);
data << Bits<1>(gameTime.IsPaidForByIGR);
data << Bits<1>(gameTime.IsCAISEnabled);
data.FlushBits();
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, BaseBuildKey const& buildKey)
{
for (std::size_t i = 0; i < 16; ++i)
{
data << buildKey.BuildKey[i];
data << buildKey.ConfigKey[i];
}
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, AuthSuccessInfo const& successInfo)
{
data << uint32(successInfo.VirtualRealmAddress);
data << Size<uint32>(successInfo.VirtualRealms);
data << uint32(successInfo.TimeRested);
data << uint8(successInfo.ActiveExpansionLevel);
data << uint8(successInfo.AccountExpansionLevel);
data << uint32(successInfo.TimeSecondsUntilPCKick);
data << Size<uint32>(*successInfo.AvailableClasses);
data << Size<uint32>(successInfo.Templates);
data << uint32(successInfo.CurrencyID);
data << successInfo.Time;
for (RaceClassAvailability const& raceClassAvailability : *successInfo.AvailableClasses)
{
data << uint8(raceClassAvailability.RaceID);
data << Size<uint32>(raceClassAvailability.Classes);
for (ClassAvailability const& classAvailability : raceClassAvailability.Classes)
{
data << uint8(classAvailability.ClassID);
data << uint8(classAvailability.ActiveExpansionLevel);
data << uint8(classAvailability.AccountExpansionLevel);
data << uint8(classAvailability.MinActiveExpansionLevel);
}
}
data << Bits<1>(successInfo.IsExpansionTrial);
data << Bits<1>(successInfo.ForceCharacterTemplate);
data << OptionalInit(successInfo.NumPlayersHorde);
data << OptionalInit(successInfo.NumPlayersAlliance);
data << OptionalInit(successInfo.ExpansionTrialExpiration);
data << OptionalInit(successInfo.CurrentBuild);
data.FlushBits();
data << successInfo.GameTimeInfo;
if (successInfo.NumPlayersHorde)
data << uint16(*successInfo.NumPlayersHorde);
if (successInfo.NumPlayersAlliance)
data << uint16(*successInfo.NumPlayersAlliance);
if (successInfo.ExpansionTrialExpiration)
data << *successInfo.ExpansionTrialExpiration;
if (successInfo.CurrentBuild)
data << *successInfo.CurrentBuild;
for (VirtualRealmInfo const& virtualRealm : successInfo.VirtualRealms)
data << virtualRealm;
for (CharacterTemplate const* characterTemplate : successInfo.Templates)
{
data << uint32(characterTemplate->TemplateSetId);
data << Size<uint32>(characterTemplate->Classes);
for (CharacterTemplateClass const& templateClass : characterTemplate->Classes)
{
data << uint8(templateClass.ClassID);
data << uint8(templateClass.FactionGroup);
}
data << SizedString::BitsSize<7>(characterTemplate->Name);
data << SizedString::BitsSize<10>(characterTemplate->Description);
data.FlushBits();
data << SizedString::Data(characterTemplate->Name);
data << SizedString::Data(characterTemplate->Description);
}
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, AuthWaitInfo const& waitInfo)
{
data << uint32(waitInfo.WaitCount);
@@ -106,89 +203,7 @@ WorldPacket const* AuthResponse::Write()
_worldPacket.FlushBits();
if (SuccessInfo)
{
_worldPacket << uint32(SuccessInfo->VirtualRealmAddress);
_worldPacket << Size<uint32>(SuccessInfo->VirtualRealms);
_worldPacket << uint32(SuccessInfo->TimeRested);
_worldPacket << uint8(SuccessInfo->ActiveExpansionLevel);
_worldPacket << uint8(SuccessInfo->AccountExpansionLevel);
_worldPacket << uint32(SuccessInfo->TimeSecondsUntilPCKick);
_worldPacket << Size<uint32>(*SuccessInfo->AvailableClasses);
_worldPacket << Size<uint32>(SuccessInfo->Templates);
_worldPacket << uint32(SuccessInfo->CurrencyID);
_worldPacket << SuccessInfo->Time;
for (RaceClassAvailability const& raceClassAvailability : *SuccessInfo->AvailableClasses)
{
_worldPacket << uint8(raceClassAvailability.RaceID);
_worldPacket << Size<uint32>(raceClassAvailability.Classes);
for (ClassAvailability const& classAvailability : raceClassAvailability.Classes)
{
_worldPacket << uint8(classAvailability.ClassID);
_worldPacket << uint8(classAvailability.ActiveExpansionLevel);
_worldPacket << uint8(classAvailability.AccountExpansionLevel);
_worldPacket << uint8(classAvailability.MinActiveExpansionLevel);
}
}
_worldPacket << Bits<1>(SuccessInfo->IsExpansionTrial);
_worldPacket << Bits<1>(SuccessInfo->ForceCharacterTemplate);
_worldPacket << OptionalInit(SuccessInfo->NumPlayersHorde);
_worldPacket << OptionalInit(SuccessInfo->NumPlayersAlliance);
_worldPacket << OptionalInit(SuccessInfo->ExpansionTrialExpiration);
_worldPacket << OptionalInit(SuccessInfo->NewBuildKeys);
_worldPacket.FlushBits();
{
_worldPacket << uint32(SuccessInfo->GameTimeInfo.BillingType);
_worldPacket << uint32(SuccessInfo->GameTimeInfo.MinutesRemaining);
_worldPacket << uint32(SuccessInfo->GameTimeInfo.RealBillingType);
_worldPacket << Bits<1>(SuccessInfo->GameTimeInfo.IsInIGR); // inGameRoom check in function checking which lua event to fire when remaining time is near end - BILLING_NAG_DIALOG vs IGR_BILLING_NAG_DIALOG
_worldPacket << Bits<1>(SuccessInfo->GameTimeInfo.IsPaidForByIGR); // inGameRoom lua return from Script_GetBillingPlan
_worldPacket << Bits<1>(SuccessInfo->GameTimeInfo.IsCAISEnabled); // not used anywhere in the client
_worldPacket.FlushBits();
}
if (SuccessInfo->NumPlayersHorde)
_worldPacket << uint16(*SuccessInfo->NumPlayersHorde);
if (SuccessInfo->NumPlayersAlliance)
_worldPacket << uint16(*SuccessInfo->NumPlayersAlliance);
if (SuccessInfo->ExpansionTrialExpiration)
_worldPacket << *SuccessInfo->ExpansionTrialExpiration;
if (SuccessInfo->NewBuildKeys)
{
for (std::size_t i = 0; i < 16; ++i)
{
_worldPacket << SuccessInfo->NewBuildKeys->NewBuildKey[i];
_worldPacket << SuccessInfo->NewBuildKeys->SomeKey[i];
}
}
for (VirtualRealmInfo const& virtualRealm : SuccessInfo->VirtualRealms)
_worldPacket << virtualRealm;
for (CharacterTemplate const* characterTemplate : SuccessInfo->Templates)
{
_worldPacket << uint32(characterTemplate->TemplateSetId);
_worldPacket << Size<uint32>(characterTemplate->Classes);
for (CharacterTemplateClass const& templateClass : characterTemplate->Classes)
{
_worldPacket << uint8(templateClass.ClassID);
_worldPacket << uint8(templateClass.FactionGroup);
}
_worldPacket << SizedString::BitsSize<7>(characterTemplate->Name);
_worldPacket << SizedString::BitsSize<10>(characterTemplate->Description);
_worldPacket.FlushBits();
_worldPacket << SizedString::Data(characterTemplate->Name);
_worldPacket << SizedString::Data(characterTemplate->Description);
}
}
_worldPacket << *SuccessInfo;
if (WaitInfo)
_worldPacket << *WaitInfo;
@@ -91,17 +91,13 @@ namespace WorldPackets
public:
static constexpr uint32 DigestLength = 24;
explicit AuthSession(WorldPacket&& packet) : EarlyProcessClientPacket(CMSG_AUTH_SESSION, std::move(packet))
{
LocalChallenge.fill(0);
Digest.fill(0);
}
explicit AuthSession(WorldPacket&& packet) : EarlyProcessClientPacket(CMSG_AUTH_SESSION, std::move(packet)) { }
uint32 RegionID = 0;
uint32 BattlegroupID = 0;
uint32 RealmID = 0;
std::array<uint8, 32> LocalChallenge;
std::array<uint8, DigestLength> Digest;
std::array<uint8, 32> LocalChallenge = { };
std::array<uint8, DigestLength> Digest = { };
uint64 DosResponse = 0;
std::string RealmJoinTicket;
bool UseIPv6 = false;
@@ -142,53 +138,51 @@ namespace WorldPackets
VirtualRealmNameInfo RealmNameInfo;
};
struct GameTime
{
uint32 BillingType = 0;
uint32 MinutesRemaining = 0;
uint32 RealBillingType = 0;
bool IsInIGR = false;
bool IsPaidForByIGR = false;
bool IsCAISEnabled = false;
};
struct BaseBuildKey
{
std::array<uint8, 16> BuildKey = { };
std::array<uint8, 16> ConfigKey = { };
};
struct AuthSuccessInfo
{
uint8 ActiveExpansionLevel = 0; ///< the current server expansion, the possible values are in @ref Expansions
uint8 AccountExpansionLevel = 0; ///< the current expansion of this account, the possible values are in @ref Expansions
uint32 TimeRested = 0; ///< affects the return value of the GetBillingTimeRested() client API call, it is the number of seconds you have left until the experience points and loot you receive from creatures and quests is reduced. It is only used in the Asia region in retail, it's not implemented in TC and will probably never be.
uint32 VirtualRealmAddress = 0; ///< a special identifier made from the Index, BattleGroup and Region.
uint32 TimeSecondsUntilPCKick = 0; ///< @todo research
uint32 CurrencyID = 0; ///< this is probably used for the ingame shop. @todo implement
Timestamp<> Time;
GameTime GameTimeInfo;
std::vector<VirtualRealmInfo> VirtualRealms; ///< list of realms connected to this one (inclusive) @todo implement
std::vector<CharacterTemplate const*> Templates; ///< list of pre-made character templates.
std::vector<RaceClassAvailability> const* AvailableClasses = nullptr; ///< the minimum AccountExpansion required to select race/class combinations
bool IsExpansionTrial = false;
bool ForceCharacterTemplate = false; ///< forces the client to always use a character template when creating a new character. @see Templates. @todo implement
Optional<uint16> NumPlayersHorde; ///< number of horde players in this realm. @todo implement
Optional<uint16> NumPlayersAlliance; ///< number of alliance players in this realm. @todo implement
Optional<Timestamp<>> ExpansionTrialExpiration; ///< expansion trial expiration unix timestamp
Optional<BaseBuildKey> CurrentBuild;
};
class AuthResponse final : public ServerPacket
{
public:
struct AuthSuccessInfo
{
struct GameTime
{
uint32 BillingType = 0;
uint32 MinutesRemaining = 0;
uint32 RealBillingType = 0;
bool IsInIGR = false;
bool IsPaidForByIGR = false;
bool IsCAISEnabled = false;
};
struct NewBuild
{
std::array<uint8, 16> NewBuildKey = { };
std::array<uint8, 16> SomeKey = { };
};
AuthSuccessInfo() { } // work around clang bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101227
uint8 ActiveExpansionLevel = 0; ///< the current server expansion, the possible values are in @ref Expansions
uint8 AccountExpansionLevel = 0; ///< the current expansion of this account, the possible values are in @ref Expansions
uint32 TimeRested = 0; ///< affects the return value of the GetBillingTimeRested() client API call, it is the number of seconds you have left until the experience points and loot you receive from creatures and quests is reduced. It is only used in the Asia region in retail, it's not implemented in TC and will probably never be.
uint32 VirtualRealmAddress = 0; ///< a special identifier made from the Index, BattleGroup and Region.
uint32 TimeSecondsUntilPCKick = 0; ///< @todo research
uint32 CurrencyID = 0; ///< this is probably used for the ingame shop. @todo implement
Timestamp<> Time;
GameTime GameTimeInfo;
std::vector<VirtualRealmInfo> VirtualRealms; ///< list of realms connected to this one (inclusive) @todo implement
std::vector<CharacterTemplate const*> Templates; ///< list of pre-made character templates.
std::vector<RaceClassAvailability> const* AvailableClasses = nullptr; ///< the minimum AccountExpansion required to select race/class combinations
bool IsExpansionTrial = false;
bool ForceCharacterTemplate = false; ///< forces the client to always use a character template when creating a new character. @see Templates. @todo implement
Optional<uint16> NumPlayersHorde; ///< number of horde players in this realm. @todo implement
Optional<uint16> NumPlayersAlliance; ///< number of alliance players in this realm. @todo implement
Optional<Timestamp<>> ExpansionTrialExpiration; ///< expansion trial expiration unix timestamp
Optional<NewBuild> NewBuildKeys;
};
explicit AuthResponse() : ServerPacket(SMSG_AUTH_RESPONSE, 132) { }
WorldPacket const* Write() override;
@@ -274,16 +268,12 @@ namespace WorldPackets
public:
static constexpr uint32 DigestLength = 24;
explicit AuthContinuedSession(WorldPacket&& packet) : EarlyProcessClientPacket(CMSG_AUTH_CONTINUED_SESSION, std::move(packet))
{
LocalChallenge.fill(0);
Digest.fill(0);
}
explicit AuthContinuedSession(WorldPacket&& packet) : EarlyProcessClientPacket(CMSG_AUTH_CONTINUED_SESSION, std::move(packet)) { }
uint64 DosResponse = 0;
uint64 Key = 0;
std::array<uint8, 32> LocalChallenge;
std::array<uint8, DigestLength> Digest;
std::array<uint8, 32> LocalChallenge = { };
std::array<uint8, DigestLength> Digest = { };
private:
friend EarlyProcessClientPacket;
@@ -191,6 +191,42 @@ WorldPacket const* SpellHealLog::Write()
return &_worldPacket;
}
ByteBuffer& operator<<(ByteBuffer& data, PeriodicalAuraLogEffectDebugInfo const& debugInfo)
{
data << float(debugInfo.CritRollMade);
data << float(debugInfo.CritRollNeeded);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, PeriodicAuraLogEffect const& effect)
{
data << int32(effect.Effect);
data << int32(effect.Amount);
data << int32(effect.OriginalDamage);
data << int32(effect.OverHealOrKill);
data << int32(effect.SchoolMaskOrPower);
data << int32(effect.AbsorbedOrAmplitude);
data << int32(effect.Resisted);
data << Size<uint32>(effect.Supporters);
for (Spells::SpellSupportInfo const& supportInfo : effect.Supporters)
data << supportInfo;
data << Bits<1>(effect.Crit);
data << OptionalInit(effect.DebugInfo);
data << OptionalInit(effect.ContentTuning);
data.FlushBits();
if (effect.ContentTuning)
data << *effect.ContentTuning;
if (effect.DebugInfo)
data << *effect.DebugInfo;
return data;
}
WorldPacket const* SpellPeriodicAuraLog::Write()
{
*this << TargetGUID;
@@ -200,34 +236,8 @@ WorldPacket const* SpellPeriodicAuraLog::Write()
WriteLogDataBit();
FlushBits();
for (SpellLogEffect const& effect : Effects)
{
*this << int32(effect.Effect);
*this << int32(effect.Amount);
*this << int32(effect.OriginalDamage);
*this << int32(effect.OverHealOrKill);
*this << int32(effect.SchoolMaskOrPower);
*this << int32(effect.AbsorbedOrAmplitude);
*this << int32(effect.Resisted);
*this << Size<uint32>(effect.Supporters);
for (Spells::SpellSupportInfo const& supportInfo : effect.Supporters)
*this << supportInfo;
*this << Bits<1>(effect.Crit);
*this << OptionalInit(effect.DebugInfo);
*this << OptionalInit(effect.ContentTuning);
FlushBits();
if (effect.ContentTuning)
*this << *effect.ContentTuning;
if (effect.DebugInfo)
{
*this << float(effect.DebugInfo->CritRollMade);
*this << float(effect.DebugInfo->CritRollNeeded);
}
}
for (PeriodicAuraLogEffect const& effect : Effects)
*this << effect;
WriteLogData();
@@ -108,30 +108,30 @@ namespace WorldPackets
std::vector<Spells::SpellSupportInfo> Supporters;
};
struct PeriodicalAuraLogEffectDebugInfo
{
float CritRollMade = 0.0f;
float CritRollNeeded = 0.0f;
};
struct PeriodicAuraLogEffect
{
int32 Effect = 0;
int32 Amount = 0;
int32 OriginalDamage = 0;
int32 OverHealOrKill = 0;
int32 SchoolMaskOrPower = 0;
int32 AbsorbedOrAmplitude = 0;
int32 Resisted = 0;
bool Crit = false;
Optional<PeriodicalAuraLogEffectDebugInfo> DebugInfo;
Optional<Spells::ContentTuningParams> ContentTuning;
std::vector<Spells::SpellSupportInfo> Supporters;
};
class SpellPeriodicAuraLog final : public CombatLogServerPacket
{
public:
struct PeriodicalAuraLogEffectDebugInfo
{
float CritRollMade = 0.0f;
float CritRollNeeded = 0.0f;
};
struct SpellLogEffect
{
int32 Effect = 0;
int32 Amount = 0;
int32 OriginalDamage = 0;
int32 OverHealOrKill = 0;
int32 SchoolMaskOrPower = 0;
int32 AbsorbedOrAmplitude = 0;
int32 Resisted = 0;
bool Crit = false;
Optional<PeriodicalAuraLogEffectDebugInfo> DebugInfo;
Optional<Spells::ContentTuningParams> ContentTuning;
std::vector<Spells::SpellSupportInfo> Supporters;
};
explicit SpellPeriodicAuraLog() : CombatLogServerPacket(SMSG_SPELL_PERIODIC_AURA_LOG, 16 + 16 + 4 + 4 + 1) { }
WorldPacket const* Write() override;
@@ -139,7 +139,7 @@ namespace WorldPackets
ObjectGuid TargetGUID;
ObjectGuid CasterGUID;
int32 SpellID = 0;
std::vector<SpellLogEffect> Effects;
std::vector<PeriodicAuraLogEffect> Effects;
};
class SpellInterruptLog final : public ServerPacket
@@ -120,7 +120,14 @@ namespace WorldPackets
Spells::SpellCastLogData LogData;
protected:
template <typename T>
template <ByteBufferNumeric T>
void operator<<(T val)
{
_worldPacket << val;
_fullLogPacket << val;
}
template <typename T> requires (!ByteBufferNumeric<T>)
void operator<<(T const& val)
{
_worldPacket << val;
@@ -128,17 +128,14 @@ namespace WorldPackets
class InspectResult final : public ServerPacket
{
public:
explicit InspectResult() : ServerPacket(SMSG_INSPECT_RESULT, 4096)
{
PvpTalents.fill(0);
}
explicit InspectResult() : ServerPacket(SMSG_INSPECT_RESULT, 4096) { }
WorldPacket const* Write() override;
PlayerModelDisplayInfo DisplayInfo;
std::vector<uint16> Glyphs;
std::vector<uint16> Talents;
std::array<uint16, MAX_PVP_TALENT_SLOTS> PvpTalents;
std::array<uint16, MAX_PVP_TALENT_SLOTS> PvpTalents = { };
Optional<InspectGuildData> GuildData;
std::array<PVPBracketData, 9> Bracket;
Optional<int32> AzeriteLevel;
@@ -575,7 +575,7 @@ WorldPacket const* LoadCUFProfiles::Write()
// Bool Options
for (uint8 option = 0; option < CUF_BOOL_OPTIONS_COUNT; option++)
_worldPacket << Bits<1>(cufProfile->BoolOptions[option]);
_worldPacket.WriteBit(cufProfile->BoolOptions[option]);
// Other Options
_worldPacket << uint16(cufProfile->FrameHeight);
@@ -1095,7 +1095,33 @@ WorldPacket const* ResumeToken::Write()
return &_worldPacket;
}
ByteBuffer& operator<<(ByteBuffer& data, MoveSetCompoundState::MoveStateChange const& stateChange)
ByteBuffer& operator<<(ByteBuffer& data, CollisionHeightInfo const& collisionHeightInfo)
{
data << float(collisionHeightInfo.Height);
data << float(collisionHeightInfo.Scale);
data << uint8(collisionHeightInfo.Reason);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, StateChangeRangeInfo const& stateChangeRangeInfo)
{
data << float(stateChangeRangeInfo.Min);
data << float(stateChangeRangeInfo.Max);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, KnockBackInfo const& knockBackInfo)
{
data << float(knockBackInfo.HorzSpeed);
data << knockBackInfo.Direction;
data << float(knockBackInfo.InitVertSpeed);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, MoveStateChange const& stateChange)
{
data << uint32(stateChange.MessageID);
data << uint32(stateChange.SequenceIndex);
@@ -1118,27 +1144,16 @@ ByteBuffer& operator<<(ByteBuffer& data, MoveSetCompoundState::MoveStateChange c
data << float(*stateChange.Speed);
if (stateChange.Range)
{
data << float(stateChange.Range->Min);
data << float(stateChange.Range->Max);
}
data << *stateChange.Range;
if (stateChange.KnockBack)
{
data << float(stateChange.KnockBack->HorzSpeed);
data << stateChange.KnockBack->Direction;
data << float(stateChange.KnockBack->InitVertSpeed);
}
data << *stateChange.KnockBack;
if (stateChange.VehicleRecID)
data << int32(*stateChange.VehicleRecID);
if (stateChange.CollisionHeight)
{
data << float(stateChange.CollisionHeight->Height);
data << float(stateChange.CollisionHeight->Scale);
data << uint8(stateChange.CollisionHeight->Reason);
}
data << *stateChange.CollisionHeight;
if (stateChange.MovementForceGUID)
data << *stateChange.MovementForceGUID;
@@ -691,47 +691,47 @@ namespace WorldPackets
uint32 Reason = 1;
};
struct CollisionHeightInfo
{
float Height = 0.0f;
float Scale = 0.0f;
UpdateCollisionHeightReason Reason = UpdateCollisionHeightReason::Scale;
};
struct StateChangeRangeInfo
{
float Min = 0.0f;
float Max = 0.0f;
};
struct KnockBackInfo
{
float HorzSpeed = 0.0f;
TaggedPosition<Position::XY> Direction;
float InitVertSpeed = 0.0f;
};
struct MoveStateChange
{
MoveStateChange(OpcodeServer messageId, uint32 sequenceIndex) : MessageID(messageId), SequenceIndex(sequenceIndex) { }
uint32 MessageID = 0;
uint32 SequenceIndex = 0;
Optional<float> Speed;
Optional<StateChangeRangeInfo> Range;
Optional<KnockBackInfo> KnockBack;
Optional<int32> VehicleRecID;
Optional<CollisionHeightInfo> CollisionHeight;
Optional<MovementForce> MovementForce_;
Optional<ObjectGuid> MovementForceGUID;
Optional<int32> MovementInertiaID;
Optional<uint32> MovementInertiaLifetimeMs;
Optional<int32> DriveCapabilityRecID;
};
class MoveSetCompoundState final : public ServerPacket
{
public:
struct CollisionHeightInfo
{
float Height = 0.0f;
float Scale = 0.0f;
UpdateCollisionHeightReason Reason = UpdateCollisionHeightReason::Scale;
};
struct KnockBackInfo
{
float HorzSpeed = 0.0f;
TaggedPosition<Position::XY> Direction;
float InitVertSpeed = 0.0f;
};
struct StateChangeRangeInfo
{
float Min = 0.0f;
float Max = 0.0f;
};
struct MoveStateChange
{
MoveStateChange(OpcodeServer messageId, uint32 sequenceIndex) : MessageID(messageId), SequenceIndex(sequenceIndex) { }
uint32 MessageID = 0;
uint32 SequenceIndex = 0;
Optional<float> Speed;
Optional<StateChangeRangeInfo> Range;
Optional<KnockBackInfo> KnockBack;
Optional<int32> VehicleRecID;
Optional<CollisionHeightInfo> CollisionHeight;
Optional<MovementForce> MovementForce_;
Optional<ObjectGuid> MovementForceGUID;
Optional<int32> MovementInertiaID;
Optional<uint32> MovementInertiaLifetimeMs;
Optional<int32> DriveCapabilityRecID;
};
explicit MoveSetCompoundState() : ServerPacket(SMSG_MOVE_SET_COMPOUND_STATE, 4 + 1) { }
WorldPacket const* Write() override;
@@ -345,19 +345,26 @@ namespace WorldPackets
ChronoDuration _value = ChronoDuration::zero();
};
template<typename Underlying, typename T>
template<typename T>
concept AsWritable = std::is_default_constructible_v<T> && HasByteBufferShiftOperators<T>;
template<typename T, typename Underlying>
concept AsWritableFor = requires { static_cast<Underlying>(std::declval<T>()); }
&& requires { static_cast<T>(Underlying()); };
template<AsWritable Underlying, AsWritableFor<Underlying> T>
struct AsWriter
{
T const& Value;
friend inline ByteBuffer& operator<<(ByteBuffer& data, AsWriter const& opt)
{
data << Underlying(opt.Value);
data << static_cast<Underlying>(opt.Value);
return data;
}
};
template<typename Underlying, typename T>
template<AsWritable Underlying, AsWritableFor<Underlying> T>
struct AsReaderWriter : AsWriter<Underlying, T>
{
friend inline ByteBuffer& operator>>(ByteBuffer& data, AsReaderWriter const& opt)
@@ -369,13 +376,16 @@ namespace WorldPackets
}
};
template<typename Underlying, typename T>
template<AsWritable Underlying, AsWritableFor<Underlying> T>
inline AsWriter<Underlying, T> As(T const& value) { return { value }; }
template<typename Underlying, typename T>
template<AsWritable Underlying, AsWritableFor<Underlying> T>
inline AsReaderWriter<Underlying, T> As(T& value) { return { value }; }
template<typename T>
concept OptionalWritable = std::is_default_constructible_v<T>;
template<OptionalWritable T>
struct OptionalInitWriter
{
Optional<T> const& Opt;
@@ -387,7 +397,7 @@ namespace WorldPackets
}
};
template<typename T>
template<OptionalWritable T>
struct OptionalInitReaderWriter : OptionalInitWriter<T>
{
friend inline ByteBuffer& operator>>(ByteBuffer& data, OptionalInitReaderWriter const& opt)
@@ -398,13 +408,13 @@ namespace WorldPackets
}
};
template<typename T>
template<OptionalWritable T>
inline OptionalInitWriter<T> OptionalInit(Optional<T> const& value) { return { value }; }
template<typename T>
template<OptionalWritable T>
inline OptionalInitReaderWriter<T> OptionalInit(Optional<T>& value) { return { value }; }
template<typename T>
template<OptionalWritable T>
struct PtrInitWriter
{
std::unique_ptr<T> const& Ptr;
@@ -416,7 +426,7 @@ namespace WorldPackets
}
};
template<typename T>
template<OptionalWritable T>
struct PtrInitReaderWriter : PtrInitWriter<T>
{
friend inline ByteBuffer& operator>>(ByteBuffer& data, PtrInitReaderWriter const& opt)
@@ -427,41 +437,62 @@ namespace WorldPackets
}
};
template<typename T>
template<OptionalWritable T>
inline PtrInitWriter<T> OptionalInit(std::unique_ptr<T> const& value) { return { value }; }
template<typename T>
template<OptionalWritable T>
inline PtrInitReaderWriter<T> OptionalInit(std::unique_ptr<T>& value) { return { value }; }
template<uint32 BitCount, typename T>
template<typename T>
concept BitsWritable = AsWritableFor<T, uint32>;
template<uint32 BitCount, BitsWritable T>
struct BitsWriter
{
T const& Value;
friend inline ByteBuffer& operator<<(ByteBuffer& data, BitsWriter const& bits)
{
data.WriteBits(static_cast<uint32>(bits.Value), BitCount);
if constexpr (BitCount != 1)
data.WriteBits(static_cast<uint32>(bits.Value), BitCount);
else
data.WriteBit(static_cast<uint32>(bits.Value) != 0);
return data;
}
};
template<uint32 BitCount, typename T>
template<uint32 BitCount, BitsWritable T>
struct BitsReaderWriter : BitsWriter<BitCount, T>
{
friend inline ByteBuffer& operator>>(ByteBuffer& data, BitsReaderWriter const& bits)
{
const_cast<T&>(bits.Value) = static_cast<T>(data.ReadBits(BitCount));
if constexpr (BitCount != 1)
const_cast<T&>(bits.Value) = static_cast<T>(data.ReadBits(BitCount));
else
const_cast<T&>(bits.Value) = static_cast<T>(data.ReadBit() ? 1 : 0);
return data;
}
};
template<uint32 BitCount, typename T>
template<uint32 BitCount, BitsWritable T>
inline BitsWriter<BitCount, T> Bits(T const& value) { return { value }; }
template<uint32 BitCount, typename T>
template<uint32 BitCount, BitsWritable T>
inline BitsReaderWriter<BitCount, T> Bits(T& value) { return { value }; }
template<typename Underlying, typename Container>
template<typename T, typename SizeType>
concept ContainerWritable = requires(T const& container) { { container.size() } -> AsWritableFor<SizeType>; }
&& !std::same_as<T, std::string_view>
&& !std::same_as<T, std::string>;
template<typename T, typename SizeType>
concept ContainerReadable = ContainerWritable<T, SizeType>
&& !std::is_const_v<T>
&& requires(T & container) { container.resize(SizeType{}); };
template<AsWritable Underlying, ContainerWritable<Underlying> Container>
struct SizeWriter
{
Container const& Value;
@@ -473,7 +504,7 @@ namespace WorldPackets
}
};
template<typename Underlying, typename Container>
template<AsWritable Underlying, ContainerReadable<Underlying> Container>
struct SizeReaderWriter : SizeWriter<Underlying, Container>
{
friend inline ByteBuffer& operator>>(ByteBuffer& data, SizeReaderWriter const& size)
@@ -485,13 +516,13 @@ namespace WorldPackets
}
};
template<typename Underlying, typename Container>
template<AsWritable Underlying, ContainerWritable<Underlying> Container>
inline SizeWriter<Underlying, Container> Size(Container const& value) { return { value }; }
template<typename Underlying, typename Container>
template<AsWritable Underlying, ContainerReadable<Underlying> Container>
inline SizeReaderWriter<Underlying, Container> Size(Container& value) { return { value }; }
template<uint32 BitCount, typename Container>
template<uint32 BitCount, ContainerWritable<uint32> Container>
struct BitsSizeWriter
{
Container const& Value;
@@ -503,7 +534,7 @@ namespace WorldPackets
}
};
template<uint32 BitCount, typename Container>
template<uint32 BitCount, ContainerReadable<uint32> Container>
struct BitsSizeReaderWriter : BitsSizeWriter<BitCount, Container>
{
friend inline ByteBuffer& operator>>(ByteBuffer& data, BitsSizeReaderWriter const& bits)
@@ -513,15 +544,26 @@ namespace WorldPackets
}
};
template<uint32 BitCount, typename Container>
template<uint32 BitCount, ContainerWritable<uint32> Container>
inline BitsSizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
template<uint32 BitCount, typename Container>
template<uint32 BitCount, ContainerReadable<uint32> Container>
inline BitsSizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
template<typename T>
concept StringWritable = requires(T const& container) { { container.length() } -> AsWritableFor<uint32>; }
&& requires(ByteBuffer& data, T const& string) { data.WriteString(static_cast<std::string_view>(string)); /*TODO: Kill String class and remove the cast*/ };
template<typename T>
concept StringReadable = StringWritable<T>
&& !std::is_const_v<T>
&& !std::same_as<T, std::string_view>
&& requires(T& container) { container.resize(uint32()); }
&& requires(ByteBuffer& data, T& string) { string = data.ReadString(uint32(), bool()); };
namespace SizedString
{
template<uint32 BitCount, typename Container>
template<uint32 BitCount, StringWritable Container>
struct SizeWriter
{
Container const& Value;
@@ -533,7 +575,7 @@ namespace WorldPackets
}
};
template<uint32 BitCount, typename Container>
template<uint32 BitCount, StringReadable Container>
struct SizeReaderWriter : SizeWriter<BitCount, Container>
{
friend inline ByteBuffer& operator>>(ByteBuffer& data, SizeReaderWriter const& bits)
@@ -543,13 +585,13 @@ namespace WorldPackets
}
};
template<uint32 BitCount, typename Container>
template<uint32 BitCount, StringWritable Container>
inline SizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
template<uint32 BitCount, typename Container>
template<uint32 BitCount, StringReadable Container>
inline SizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
template<typename Container>
template<StringWritable Container>
struct DataWriter
{
Container const& Value;
@@ -561,7 +603,7 @@ namespace WorldPackets
}
};
template<typename Container, Strings::Utf8Mode Mode>
template<StringReadable Container, Strings::Utf8Mode Mode>
struct DataReaderWriter : DataWriter<Container>
{
static constexpr bool IsUtf8() { return Mode == Strings::ValidUtf8; }
@@ -573,17 +615,17 @@ namespace WorldPackets
}
};
template<Strings::Utf8Mode = Strings::ValidUtf8, typename Container>
template<Strings::Utf8Mode = Strings::ValidUtf8, StringWritable Container>
inline DataWriter<Container> Data(Container const& value) { return { value }; }
template<Strings::Utf8Mode Mode = Strings::ValidUtf8, typename Container>
template<Strings::Utf8Mode Mode = Strings::ValidUtf8, StringReadable Container>
inline DataReaderWriter<Container, Mode> Data(Container& value) { return { value }; }
}
// SizedCString (sends size + string + null terminator but only if not empty)
namespace SizedCString
{
template<uint32 BitCount, typename Container>
template<uint32 BitCount, StringWritable Container>
struct SizeWriter
{
Container const& Value;
@@ -595,7 +637,7 @@ namespace WorldPackets
}
};
template<uint32 BitCount, typename Container>
template<uint32 BitCount, StringReadable Container>
struct SizeReaderWriter : SizeWriter<BitCount, Container>
{
friend inline ByteBuffer& operator>>(ByteBuffer& data, SizeReaderWriter const& bits)
@@ -606,13 +648,13 @@ namespace WorldPackets
}
};
template<uint32 BitCount, typename Container>
template<uint32 BitCount, StringWritable Container>
inline SizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
template<uint32 BitCount, typename Container>
template<uint32 BitCount, StringReadable Container>
inline SizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
template<typename Container>
template<StringWritable Container>
struct DataWriter
{
Container const& Value;
@@ -628,7 +670,7 @@ namespace WorldPackets
}
};
template<typename Container, Strings::Utf8Mode Mode>
template<StringReadable Container, Strings::Utf8Mode Mode>
struct DataReaderWriter : DataWriter<Container>
{
static constexpr bool IsUtf8() { return Mode == Strings::ValidUtf8; }
@@ -644,10 +686,10 @@ namespace WorldPackets
}
};
template<Strings::Utf8Mode = Strings::ValidUtf8, typename Container>
template<Strings::Utf8Mode = Strings::ValidUtf8, StringWritable Container>
inline DataWriter<Container> Data(Container const& value) { return { value }; }
template<Strings::Utf8Mode Mode = Strings::ValidUtf8, typename Container>
template<Strings::Utf8Mode Mode = Strings::ValidUtf8, StringReadable Container>
inline DataReaderWriter<Container, Mode> Data(Container& value) { return { value }; }
}
}
@@ -19,6 +19,44 @@
namespace WorldPackets::System
{
ByteBuffer& operator<<(ByteBuffer& data, SocialQueueConfig const& socialQueueConfig)
{
data << Bits<1>(socialQueueConfig.ToastsDisabled);
data << float(socialQueueConfig.ToastDuration);
data << float(socialQueueConfig.DelayDuration);
data << float(socialQueueConfig.QueueMultiplier);
data << float(socialQueueConfig.PlayerMultiplier);
data << float(socialQueueConfig.PlayerFriendValue);
data << float(socialQueueConfig.PlayerGuildValue);
data << float(socialQueueConfig.ThrottleInitialThreshold);
data << float(socialQueueConfig.ThrottleDecayTime);
data << float(socialQueueConfig.ThrottlePrioritySpike);
data << float(socialQueueConfig.ThrottleMinThreshold);
data << float(socialQueueConfig.ThrottlePvPPriorityNormal);
data << float(socialQueueConfig.ThrottlePvPPriorityLow);
data << float(socialQueueConfig.ThrottlePvPHonorThreshold);
data << float(socialQueueConfig.ThrottleLfgListPriorityDefault);
data << float(socialQueueConfig.ThrottleLfgListPriorityAbove);
data << float(socialQueueConfig.ThrottleLfgListPriorityBelow);
data << float(socialQueueConfig.ThrottleLfgListIlvlScalingAbove);
data << float(socialQueueConfig.ThrottleLfgListIlvlScalingBelow);
data << float(socialQueueConfig.ThrottleRfPriorityAbove);
data << float(socialQueueConfig.ThrottleRfIlvlScalingAbove);
data << float(socialQueueConfig.ThrottleDfMaxItemLevel);
data << float(socialQueueConfig.ThrottleDfBestPriority);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, SessionAlertConfig const& sessionAlert)
{
data << int32(sessionAlert.Delay);
data << int32(sessionAlert.Period);
data << int32(sessionAlert.DisplayTime);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, SavedThrottleObjectState const& throttleState)
{
data << uint32(throttleState.MaxTries);
@@ -41,6 +79,15 @@ ByteBuffer& operator<<(ByteBuffer& data, EuropaTicketConfig const& europaTicketS
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, SquelchInfo const& squelch)
{
data << Bits<1>(squelch.IsSquelched);
data << squelch.BnetAccountGuid;
data << squelch.GuildGuid;
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, GameRuleValuePair const& gameRuleValue)
{
data << int32(gameRuleValue.Rule);
@@ -167,46 +214,14 @@ WorldPacket const* FeatureSystemStatus::Write()
_worldPacket.FlushBits();
{
_worldPacket << Bits<1>(QuickJoinConfig.ToastsDisabled);
_worldPacket << float(QuickJoinConfig.ToastDuration);
_worldPacket << float(QuickJoinConfig.DelayDuration);
_worldPacket << float(QuickJoinConfig.QueueMultiplier);
_worldPacket << float(QuickJoinConfig.PlayerMultiplier);
_worldPacket << float(QuickJoinConfig.PlayerFriendValue);
_worldPacket << float(QuickJoinConfig.PlayerGuildValue);
_worldPacket << float(QuickJoinConfig.ThrottleInitialThreshold);
_worldPacket << float(QuickJoinConfig.ThrottleDecayTime);
_worldPacket << float(QuickJoinConfig.ThrottlePrioritySpike);
_worldPacket << float(QuickJoinConfig.ThrottleMinThreshold);
_worldPacket << float(QuickJoinConfig.ThrottlePvPPriorityNormal);
_worldPacket << float(QuickJoinConfig.ThrottlePvPPriorityLow);
_worldPacket << float(QuickJoinConfig.ThrottlePvPHonorThreshold);
_worldPacket << float(QuickJoinConfig.ThrottleLfgListPriorityDefault);
_worldPacket << float(QuickJoinConfig.ThrottleLfgListPriorityAbove);
_worldPacket << float(QuickJoinConfig.ThrottleLfgListPriorityBelow);
_worldPacket << float(QuickJoinConfig.ThrottleLfgListIlvlScalingAbove);
_worldPacket << float(QuickJoinConfig.ThrottleLfgListIlvlScalingBelow);
_worldPacket << float(QuickJoinConfig.ThrottleRfPriorityAbove);
_worldPacket << float(QuickJoinConfig.ThrottleRfIlvlScalingAbove);
_worldPacket << float(QuickJoinConfig.ThrottleDfMaxItemLevel);
_worldPacket << float(QuickJoinConfig.ThrottleDfBestPriority);
}
_worldPacket << QuickJoinConfig;
if (SessionAlert)
{
_worldPacket << int32(SessionAlert->Delay);
_worldPacket << int32(SessionAlert->Period);
_worldPacket << int32(SessionAlert->DisplayTime);
}
_worldPacket << *SessionAlert;
_worldPacket << SizedString::Data(Unknown1027);
{
_worldPacket << Bits<1>(Squelch.IsSquelched);
_worldPacket << Squelch.BnetAccountGuid;
_worldPacket << Squelch.GuildGuid;
}
_worldPacket << Squelch;
if (EuropaTicketSystemStatus)
_worldPacket << *EuropaTicketSystemStatus;
+41 -41
View File
@@ -27,6 +27,40 @@ namespace WorldPackets
{
namespace System
{
struct SocialQueueConfig
{
bool ToastsDisabled = false;
float ToastDuration = 0.0f;
float DelayDuration = 0.0f;
float QueueMultiplier = 0.0f;
float PlayerMultiplier = 0.0f;
float PlayerFriendValue = 0.0f;
float PlayerGuildValue = 0.0f;
float ThrottleInitialThreshold = 0.0f;
float ThrottleDecayTime = 0.0f;
float ThrottlePrioritySpike = 0.0f;
float ThrottleMinThreshold = 0.0f;
float ThrottlePvPPriorityNormal = 0.0f;
float ThrottlePvPPriorityLow = 0.0f;
float ThrottlePvPHonorThreshold = 0.0f;
float ThrottleLfgListPriorityDefault = 0.0f;
float ThrottleLfgListPriorityAbove = 0.0f;
float ThrottleLfgListPriorityBelow = 0.0f;
float ThrottleLfgListIlvlScalingAbove = 0.0f;
float ThrottleLfgListIlvlScalingBelow = 0.0f;
float ThrottleRfPriorityAbove = 0.0f;
float ThrottleRfIlvlScalingAbove = 0.0f;
float ThrottleDfMaxItemLevel = 0.0f;
float ThrottleDfBestPriority = 0.0f;
};
struct SessionAlertConfig
{
int32 Delay = 0;
int32 Period = 0;
int32 DisplayTime = 0;
};
struct SavedThrottleObjectState
{
uint32 MaxTries = 0;
@@ -45,6 +79,13 @@ namespace WorldPackets
SavedThrottleObjectState ThrottleState;
};
struct SquelchInfo
{
bool IsSquelched = false;
ObjectGuid BnetAccountGuid;
ObjectGuid GuildGuid;
};
struct GameRuleValuePair
{
int32 Rule = 0;
@@ -55,47 +96,6 @@ namespace WorldPackets
class FeatureSystemStatus final : public ServerPacket
{
public:
struct SessionAlertConfig
{
int32 Delay = 0;
int32 Period = 0;
int32 DisplayTime = 0;
};
struct SocialQueueConfig
{
bool ToastsDisabled = false;
float ToastDuration = 0.0f;
float DelayDuration = 0.0f;
float QueueMultiplier = 0.0f;
float PlayerMultiplier = 0.0f;
float PlayerFriendValue = 0.0f;
float PlayerGuildValue = 0.0f;
float ThrottleInitialThreshold = 0.0f;
float ThrottleDecayTime = 0.0f;
float ThrottlePrioritySpike = 0.0f;
float ThrottleMinThreshold = 0.0f;
float ThrottlePvPPriorityNormal = 0.0f;
float ThrottlePvPPriorityLow = 0.0f;
float ThrottlePvPHonorThreshold = 0.0f;
float ThrottleLfgListPriorityDefault = 0.0f;
float ThrottleLfgListPriorityAbove = 0.0f;
float ThrottleLfgListPriorityBelow = 0.0f;
float ThrottleLfgListIlvlScalingAbove = 0.0f;
float ThrottleLfgListIlvlScalingBelow = 0.0f;
float ThrottleRfPriorityAbove = 0.0f;
float ThrottleRfIlvlScalingAbove = 0.0f;
float ThrottleDfMaxItemLevel = 0.0f;
float ThrottleDfBestPriority = 0.0f;
};
struct SquelchInfo
{
bool IsSquelched = false;
ObjectGuid BnetAccountGuid;
ObjectGuid GuildGuid;
};
struct RafSystemFeatureInfo
{
bool Enabled = false;
+1
View File
@@ -198,6 +198,7 @@ void ByteBuffer::OnInvalidPosition(size_t pos, size_t valueSize) const
throw ByteBufferPositionException(pos, _storage.size(), valueSize);
}
template TC_SHARED_API char ByteBuffer::read<char>();
template TC_SHARED_API uint8 ByteBuffer::read<uint8>();
template TC_SHARED_API uint16 ByteBuffer::read<uint16>();
template TC_SHARED_API uint32 ByteBuffer::read<uint32>();
+30 -40
View File
@@ -18,8 +18,9 @@
#ifndef TRINITYCORE_BYTE_BUFFER_H
#define TRINITYCORE_BYTE_BUFFER_H
#include "Define.h"
#include "ByteConverter.h"
#include "Concepts.h"
#include "Define.h"
#include <array>
#include <string>
#include <vector>
@@ -50,6 +51,14 @@ public:
ByteBufferInvalidValueException(char const* type, std::string_view value);
};
template <typename T>
concept ByteBufferNumeric = std::same_as<T, int8> || std::same_as<T, uint8>
|| std::same_as<T, int16> || std::same_as<T, uint16>
|| std::same_as<T, int32> || std::same_as<T, uint32>
|| std::same_as<T, int64> || std::same_as<T, uint64>
|| std::same_as<T, float> || std::same_as<T, double>
|| std::same_as<T, char> || std::is_enum_v<T>;
class TC_SHARED_API ByteBuffer
{
public:
@@ -117,10 +126,9 @@ class TC_SHARED_API ByteBuffer
_storage.clear();
}
template <typename T>
template <ByteBufferNumeric T>
void append(T value)
{
static_assert(std::is_trivially_copyable_v<T>, "append(T) must be used with trivially copyable types");
EndianConvert(value);
append(reinterpret_cast<uint8 const*>(&value), sizeof(value));
}
@@ -248,10 +256,9 @@ class TC_SHARED_API ByteBuffer
return value;
}
template <typename T>
template <ByteBufferNumeric T>
void put(std::size_t pos, T value)
{
static_assert(std::is_trivially_copyable_v<T>, "put(size_t, T) must be used with trivially copyable types");
EndianConvert(value);
put(pos, reinterpret_cast<uint8 const*>(&value), sizeof(value));
}
@@ -469,7 +476,7 @@ class TC_SHARED_API ByteBuffer
return _wpos * 8 + 8 - _bitpos;
}
template <typename T>
template <ByteBufferNumeric T>
void read_skip() { read_skip(sizeof(T)); }
void read_skip(size_t skip)
@@ -481,7 +488,7 @@ class TC_SHARED_API ByteBuffer
_rpos += skip;
}
template <typename T>
template <ByteBufferNumeric T>
T read()
{
ResetBitPos();
@@ -490,7 +497,7 @@ class TC_SHARED_API ByteBuffer
return r;
}
template <typename T>
template <ByteBufferNumeric T>
T read(size_t pos) const
{
if (pos + sizeof(T) > _storage.size())
@@ -502,7 +509,7 @@ class TC_SHARED_API ByteBuffer
return val;
}
template <typename T>
template <ByteBufferNumeric T>
void read(T* dest, size_t count)
{
static_assert(std::is_trivially_copyable_v<T>, "read(T*, size_t) must be used with trivially copyable types");
@@ -523,8 +530,8 @@ class TC_SHARED_API ByteBuffer
_rpos += len;
}
template <size_t Size>
void read(std::array<uint8, Size>& arr)
template <ByteBufferNumeric T, size_t Size>
void read(std::array<T, Size>& arr)
{
read(arr.data(), Size);
}
@@ -549,6 +556,8 @@ class TC_SHARED_API ByteBuffer
append(str, len);
}
void ReadSkipCString(bool requireValidUtf8 = true) { (void)ReadCString(requireValidUtf8); }
std::string_view ReadCString(bool requireValidUtf8 = true);
std::string_view ReadString(uint32 length, bool requireValidUtf8 = true);
@@ -563,12 +572,12 @@ class TC_SHARED_API ByteBuffer
{
_storage.resize(newsize, 0);
_rpos = 0;
_wpos = size();
_wpos = _storage.size();
}
void reserve(size_t ressize)
{
if (ressize > size())
if (ressize > _storage.size())
_storage.reserve(ressize);
}
@@ -577,7 +586,7 @@ class TC_SHARED_API ByteBuffer
_storage.shrink_to_fit();
}
template <typename T>
template <ByteBufferNumeric T>
void append(T const* src, size_t cnt)
{
#if TRINITY_ENDIAN == TRINITY_LITTLEENDIAN
@@ -596,8 +605,8 @@ class TC_SHARED_API ByteBuffer
append(buffer.data(), buffer.size());
}
template <size_t Size>
void append(std::array<uint8, Size> const& arr)
template <ByteBufferNumeric T, std::size_t Size>
void append(std::array<T, Size> const& arr)
{
append(arr.data(), Size);
}
@@ -619,30 +628,7 @@ class TC_SHARED_API ByteBuffer
std::vector<uint8> _storage;
};
template <>
inline std::string ByteBuffer::read<std::string>()
{
return std::string(ReadCString());
}
template <>
inline void ByteBuffer::read_skip<char*>()
{
(void)ReadCString();
}
template <>
inline void ByteBuffer::read_skip<char const*>()
{
read_skip<char*>();
}
template <>
inline void ByteBuffer::read_skip<std::string>()
{
read_skip<char*>();
}
extern template char ByteBuffer::read<char>();
extern template uint8 ByteBuffer::read<uint8>();
extern template uint16 ByteBuffer::read<uint16>();
extern template uint32 ByteBuffer::read<uint32>();
@@ -654,4 +640,8 @@ extern template int64 ByteBuffer::read<int64>();
extern template float ByteBuffer::read<float>();
extern template double ByteBuffer::read<double>();
template <typename T>
concept HasByteBufferShiftOperators = requires(ByteBuffer& data, T const& value) { { data << value } -> std::convertible_to<ByteBuffer&>; }
&& requires(ByteBuffer& data, T& value) { { data >> value } -> std::convertible_to<ByteBuffer&>; };
#endif