Commit Graph
2706 Commits
Author SHA1 Message Date
luis fc4283fa4a Implement mythic plus data 2026-07-10 13:47:20 -03:00
luis 3af8c5e7a2 remove dup 2026-07-10 13:40:16 -03:00
luis 960581d08d world quest system 2026-07-10 13:38:24 -03:00
luis 8313820765 fix db2 locales load 2026-07-10 12:39:20 -03:00
luis bc20f75bbe SMART_EVENT_QUEST_ABANDON and misc opcodes 2026-07-10 12:31:14 -03:00
luis d276e219cc opcodes 2026-07-10 12:15:55 -03:00
luis d7666986ef hand of guldan 2026-07-10 12:15:38 -03:00
luis 0c03bcace4 misc opcodes 2026-07-10 12:04:28 -03:00
luis 79de9baa3b 68453 2026-07-10 11:27:22 -03:00
luis 9c62e0d744 Updated packets using sniff 2026-07-10 11:25:53 -03:00
luis 294d375ddc scenario packets 2026-07-09 20:49:03 -03:00
luis 3ef990e4d4 SMSG_MULTI_FLOOR_LEAVE_FLOOR , SMSG_MULTI_FLOOR_NEW_FLOOR 2026-07-09 17:38:23 -03:00
luis b4e62d7873 sniffs 2026-07-09 04:07:56 -03:00
luis 726641c5b1 new codestyle 2026-07-09 03:06:16 -03:00
luis f2f3f193fa warlock spell and enable garrison opcodes 2026-07-09 02:01:29 -03:00
luis 8ee2365356 typo 2026-07-09 01:15:25 -03:00
luis 3f2a5188c0 Core/Misc: Update LockType enum and SkillByLockType for 12.0.7 2026-07-08 23:32:31 -03:00
luis d038260358 fix bots and full fix m+ packet with sniff 2026-07-08 23:15:27 -03:00
luis c20846a990 Scripts/FSB: added OpenRouter as preset provider for GenAI 2026-07-08 22:57:35 -03:00
luis 58755332d0 Scripts/FSB: try to fix pipeline issue with includes 2026-07-08 22:54:28 -03:00
luis 709e847b7b Scripts/FSB: test includes 2026-07-08 22:53:51 -03:00
luis db085f1df9 Scripts/FSB: small fixes 2026-07-08 22:52:45 -03:00
luis 426c3ea565 Scripts/FSB: improve movement by looking for closest point in path 2026-07-08 22:51:34 -03:00
luis 854f8d0931 Scripts/FSB: add content tuning to summoned creatures 2026-07-08 22:49:08 -03:00
luis a2a2eaff1d Scripts/FSB: add pet movement speeds from owner and content tuning 2026-07-08 22:47:52 -03:00
luis d7e69fc918 Scripts/FSB: added some distribution for roles for bots. 2026-07-08 22:46:25 -03:00
stevebone c517cc6d54 Scripts/FSB: removed incorrect temp fallback for conversations when GenAI response invalid.
- when GenAI response invalid for starting a bot conversation it should fall back to the static sytem. That was not the case since there was a hardcoded simple fallback. Removed

Signed-off-by: luis <[email protected]>
2026-07-08 22:39:11 -03:00
luis de58769ef4 try fix animal companion 2026-07-08 22:37:54 -03:00
luis f6982381e5 CovenantCallings 2026-07-08 22:19:25 -03:00
luis bd0f7d8fe6 feat(covenant): grant transmog + garrison-follower renown rewards
Completes GrantRenownReward: TransmogID resolves an ItemModifiedAppearance and adds it via CollectionMgr::AddItemAppearance(itemId, appearanceModId); TransmogSetID via AddTransmogSet; GarrFollowerID via Garrison::AddFollower (guarded on the player having a garrison). Only TransmogIllusionID (no add-illusion API) and QuestID (reward-quest semantics) remain documented follow-ups.
2026-07-08 21:43:39 -03:00
luis 751f063936 feat(covenant): P3 - grant RenownRewards on covenant renown level-up
The covenant renown LEVEL is already a renown-reputation handled by TC's
ReputationMgr and synced to the client by the standard reputation packets,
so the only covenant-specific gap was granting the per-level rewards.

- Add the RenownRewards.db2 store (Meta 0x30AFBCF8, ParentIndex=CovenantID)
  and a DB2Manager (covenantId, level) -> rewards map (GetRenownRewards).
- Track the highest renown level whose rewards were granted, per covenant
  (Player::m_renownRewardsGranted), persisted to a new character_covenant_renown
  table and loaded at login, so each level's rewards are granted exactly once.
- Player::ReputationChanged now grants rewards for every renown level crossed
  when a covenant renown reputation increases; a login catch-up
  (UpdateAllRenownRewards, run in-world after SendInitialPacketsAfterAddToMap)
  grants anything earned before this feature existed. UpdateRenownRewards is
  guarded on IsInWorld() so nothing is granted mid-load.
- GrantRenownReward grants item / spell / title / mount via the existing
  Player + CollectionMgr APIs. The cosmetic-collection fields RenownRewards
  also carries (TransmogID/TransmogSetID/TransmogIllusionID, GarrFollowerID,
  QuestID) are documented as follow-ups rather than half-implemented.
2026-07-08 21:41:23 -03:00
luis 36d891cc81 CMSG_GET_RAF_ACCOUNT_INFO 2026-07-08 21:26:26 -03:00
luis f256bade63 handle CMSG_SET_PET_SPECIALIZATION (hunter pet spec selection)
TC already has the full pet-specialization machinery — Pet::SetSpecialization
validates the ChrSpecialization, swaps the spec spells, rebuilds the action
bar and echoes SMSG_SET_PET_SPECIALIZATION — but the client request that lets
a player pick the spec was left as Handle_NULL. Wire the handler in:

- New CMSG packet SetPetSpecializationRequest { uint32 SpecID; ObjectGuid
  PetGUID } (68275 wire).
- HandleSetPetSpecialization validates the pet is the caller's and that SpecID
  is a real pet specialization (ChrSpecialization.ClassID == 0) before applying.
- Opcode registered STATUS_LOGGEDIN / PROCESS_THREADUNSAFE.

The client's SetPetSpecialization binding drives this, so it is a live,
user-triggerable path, not a vestigial opcode.
2026-07-08 21:14:50 -03:00
luis 7e14e75ba5 enable server packets for m+ 2026-07-08 20:52:20 -03:00
luis afe889826b enable server packets for lfg 2026-07-08 20:45:14 -03:00
luis 806ca04ec9 feat(crafting-orders): P4c - customer-provided reagent serialization in LIST_ORDERS_RESPONSE
Emit customer-provided reagents (and a customerPlayer sub-struct) in the crafting-order
list wire, closing the one part of the flagship that the prior pass parked as
"needs full ItemInstance serialization / server data-model gap".

Both of those blockers were a misattribution. Re-decompiling the reader tree shows the
order's reagents (JamCraftingOrder.reagents) are read by sub_7FF72915FF20 as FLAT
JamCraftingOrderItem records (orderItemID, type, itemGUID, ownerGUID, quantity,
qualityID, flags, reagentBase{itemID,currencyID}, optional slot) - NOT ItemInstances.
The ItemInstance readers (sub_7FF7291CBD40) belong to the JamCliCraftingOrder *recraft*
fields, a different sub-struct. The server's existing OrderReagent {ItemID, CurrencyID,
Quantity, Slot} already holds everything a posting carries; ownerGUID = the customer and
flags = 1 are derived at emit time.

Validated byte-exact against the live 12.0.7 sniff
(C:\sniff\ingame-shop_ordersCrafting_professions.pkt): every order in the 2054-byte
(12 orders) and 1875-byte (11 orders) responses re-encodes to the byte, 0 leftover,
including the reagent blocks and the presence-gated customerNpc sub-struct.

- CraftingOrderPackets.h/.cpp: CraftingOrderReagentData + reagent loop in operator<<
  (mirror of sub_7FF72915FF20), presence-byte bit assignment (bit5 customerPlayer,
  bit4 customerNpc, bit3 outputOrderItem, bit2 outputItem), customerPlayer emission.
- CraftingOrderHandler.cpp: BuildCraftingOrderData fills reagents from Order::Reagents
  (ownerGUID = CustomerGUID) and sets customerPlayer for player orders.
2026-07-08 20:40:16 -03:00
luis b0fa0f9401 feat(crafting-orders): P4b - CMSG_CRAFTING_ORDER_FULFILL + tip escrow (close the fulfil gap)
The fulfil wire turned out to be recoverable, not reflection-walled: the client's FULFILL send serializer
(sub_7FF729155000) is BYTE-IDENTICAL to the already-decoded REJECT serializer (sub_7FF7291552B0), so
CraftingOrderFulfill reads the same { u64 OrderID; u8; string note; bit hasContext; [ClientContext] }. No crafted
item rides the wire - the server derives the output from the order's recipe, matching the client's craft-then-fulfil.

Fulfil flow (HandleCraftingOrderFulfill):
- validates the order is Claimed by the sender;
- resolves the recipe output (SkillLineAbility -> spell -> SPELL_EFFECT_CREATE_ITEM) and mails the crafted item
  to the customer;
- transitions Claimed -> Fulfilled and releases the escrowed tip to the crafter;
- replies with SMSG_CRAFTING_ORDER_FULFILL_RESULT and broadcasts UPDATE_STATE.

SMSG_CRAFTING_ORDER_FULFILL_RESULT: recovered byte-exact from the client reader sub_7FF7290B9950 (all plain reads -
the "CompressedUInt32" reader 0x7FF72BE6C410 is ReadUInt32): { u8 Result; u64 OrderID; u64; u8; PackedGUID; u32;
u32; u32 }. Result+OrderID are populated; the trailing fields have no offline-resolvable meaning and are sent
0/empty (structurally exact, honest - fulfilment is also signalled via UPDATE_STATE).

Tip escrow (Blizzlike, mirrors the auction deposit; no gold is created or lost):
- CREATE now requires + deducts the tip up front (escrow), failing with MissingCurrency if the customer is short;
- FULFILL pays the escrowed tip to the crafter;
- CANCEL / REJECT / posting-expiry refund the escrowed tip to the customer.
Each order escrows once at create and releases exactly once at its single terminal transition.
2026-07-08 20:24:00 -03:00
luis 2cfc050e1f feat(crafting-orders): P4 - SMSG_CRAFTING_ORDER_UPDATE_STATE live state broadcast
Adds the order-state-change notification the client uses to refresh open browse windows in real time.

- CraftingOrderUpdateState packet (SMSG_CRAFTING_ORDER_UPDATE_STATE 0x42033D). Wire is sniff-resolved from
  C:\sniff\ingame-shop_ordersCrafting_professions.pkt and cross-checked against the SAME order in the
  LIST_ORDERS_RESPONSE capture - OrderID / OrderState / CrafterGUID / SkillLineAbilityID / OrderType all match
  byte-exact. Layout: { u64 OrderID; u8(0); u8 OrderState; u16(0); PackedGUID CrafterGUID; u32 SkillLineAbilityID;
  u32(0); u8 OrderType; u32 Field30; u32 Field34 }. Field30/Field34 hold small per-order values (~96/~38) that map
  to none of the order's known fields; their semantics are not offline-resolvable, so they are sent 0 (honest).
- BroadcastCraftingOrderState(): pushes the update to the online customer and (once assigned) crafter.
- Wired into the claim / release / reject handlers after a successful state change; the freshly-updated order is
  re-fetched from the mgr and broadcast. Cancel removes an unclaimed order whose only interested party (the customer)
  already receives the CancelResult, so it is intentionally not broadcast.
2026-07-08 20:15:51 -03:00
luis 05758c3abf Character: Handle CMSG_ASSIGN_EQUIPMENT_SET_SPEC 2026-07-08 20:09:07 -03:00
luis b6facc6763 Misc: Handle CMSG_CLOSE_TRAIT_SYSTEM_INTERACTION / CMSG_CLOSE_RUNEFORGE_INTERACTION 2026-07-08 20:04:47 -03:00
luis 0349ab398f send sniff values 2026-07-08 19:52:06 -03:00
luis aafe490078 feat(contribution): P2 - Contribute handler (ContributionMgr, full turn-in flow)
Turns CMSG_CONTRIBUTION_CONTRIBUTE (was Handle_NULL) into the working war-effort turn-in,
closing the loop over the P1a DB2 stores and the P1 ManagedWorldStateMgr.

ContributionMgr:
- Load(): builds the collector-creature -> contribution index from CreatureXContribution.db2.
- Contribute(player, collectorGuid, contributionId):
  1. Validates the collector is an NPC the player can currently interact with
     (GetNPCIfCanInteractWith, no flag requirement) and that its creature entry actually
     offers this contribution (CreatureXContribution authorization).
  2. Resolves Contribution -> ManagedWorldStateInput, gating on the input's
     ValidInputConditionID (PlayerCondition).
  3. Takes the turn-in cost = the input QuestID's item/currency objectives: a first pass
     verifies the player can pay the full cost (nothing is consumed unless everything is
     affordable), a second pass consumes items (DestroyItemCount) and currency
     (RemoveCurrency, QuestTurnin reason).
  4. Feeds the total contributed amount into ManagedWorldStateMgr::AddProgress, which
     advances the realm-wide progress world state (and completes an occurrence/stage at the
     target). A contribution with no consumable objectives counts as one unit.

Wired: HandleContributionContribute routes the opcode (STATUS_LOGGEDIN, THREADUNSAFE);
sContributionMgr->Load() at startup after the managed world states. Builds clean (game.dll).

Progress increment = total quantity turned in (progress bar == resources contributed);
documented as the modelling choice where a state counts resources rather than turn-ins.
The war-effort Contribution system is now end-to-end: DB2 model -> collector turn-in ->
managed world-state progress. SMSG_CONTRIBUTION_LAST_UPDATE_RESPONSE remains deferred
(factory/thunk reader; no guessed wire).
2026-07-08 19:21:30 -03:00
luis 6e81e82ee9 feat(contribution): P1 - ManagedWorldStateMgr runtime (accumulate/deplete world-state ticker)
Adds the realm-wide progress engine TC lacked. For each ManagedWorldState.db2 row the manager
holds a runtime state (progress, stage, occurrences, up/down phase, timers) and:
- Cycles the up/down phase (UpTimeSecs/DownTimeSecs windows); a state with zero windows is
  purely contribution-driven and stays in its Up phase.
- Once per elapsed minute, accumulates AccumulationAmountPerMinute toward
  AccumulationStateTargetValue during the Up phase, or depletes DepletionAmountPerMinute toward
  DepletionStateTargetValue during the Down phase.
- Pushes Progress / CurrentStage / Occurrences through their world states via
  WorldStateMgr::SetValueAndSaveInDb (realm-global, persisted), so the client draws the
  war-effort/building progress bar and it survives restarts (restored on Load via GetValue).
- Reaching the target completes one occurrence and advances the stage.
- AddProgress(managedWorldStateId, amount) is the seam the Contribute path (P2) feeds into,
  clamped to the depletion/target bounds.

Wired into World: Load() after world-state templates load (so persisted progress restores),
Update(diff) in the world tick next to the outdoor-PvP update. Builds clean (game.dll).

Note: values are pushed as realm-global world states, which covers realm-wide managed states;
zone-scoped states would additionally need per-map propagation (documented, future refinement).
2026-07-08 19:00:40 -03:00
luis 265686f773 feat(contribution): P1a - add Contribution/ManagedWorldState DB2 stores
Adds the four DB2 stores the Contribution system is built on (TC had the *Meta hotfix
schemas but never loaded these tables): Contribution, CreatureXContribution,
ManagedWorldState, ManagedWorldStateInput.

Field layouts derived from the authoritative TC *Meta structs (DB2Metadata.h) cross-checked
against the 68275 WoWDBDefs layouts (Contribution 167173C3, ManagedWorldState A4E9EA9F,
ManagedWorldStateInput 16683306, CreatureXContribution 29D9C37F). All four have IndexField=-1
(ID first). ManagedWorldState carries the accumulate/deplete progress driver bound to
Current/Progress/Occurrences WorldState IDs; ManagedWorldStateInput carries the QuestID that
is the contribution turn-in cost.

- DB2Structure.h: 4 entry structs.
- DB2LoadInfo.h: 4 load infos (arrays expanded per element, signedness per Meta).
- DB2Stores.h/.cpp: storage globals + LOAD_DB2 registration.
- HotfixDatabase.h/.cpp: hotfix SELECT statements (+ locale for Contribution's two
  localized strings) and enum entries.
- sql/updates/hotfixes/master/2026_07_07_00_hotfixes.sql: the five hotfix tables.

Builds clean (game.dll). Next: the ManagedWorldStateMgr runtime (P1) that ticks these
states, then Contribute (P2).
2026-07-08 18:52:22 -03:00
luis 2eaf9b5a04 Starts the standalone war-effort Contribution Collector system on its own branch, faithful
to the client DB2 model (Contribution -> ManagedWorldStateInput -> ManagedWorldState), per
the architecture decision to keep it decoupled from the major-factions branch.

- doc/contribution/CONTRIBUTION_IMPLEMENTATION_PLAN_68275.md: full RE + phased plan.
  Wire (CMSG both dirs RE'd byte-exact from client serializers); DB2 model incl. the key
  finding that Contribution.db2 has NO FactionID (it feeds a ManagedWorldStateInput, not a
  faction) and the cost = the input's QuestID turn-in (no separate cost column).
- ContributionPackets.h/.cpp: readers for CMSG_CONTRIBUTION_CONTRIBUTE
  ({ObjectGuid CollectorGUID, uint32 ContributionID}) and CMSG_CONTRIBUTION_LAST_UPDATE_REQUEST
  ({uint32 ContributionID, uint32 Field1}). Included in AllPackets.h.

Opcodes intentionally remain Handle_NULL: routing lands with the real ContributionMgr +
ManagedWorldState runtime (P1/P2) so no stub handler is introduced. SMSG_CONTRIBUTION_LAST_
UPDATE_RESPONSE deferred with a documented reason (reader is a factory/thunk maze; needs a
dispatch decompile or live sniff, no guessed wire).
2026-07-08 18:07:40 -03:00
luis 05260ebe8f clean old method 2026-07-08 15:09:54 -03:00
luis 22f8b82dd7 db 2026-07-08 15:05:03 -03:00
luis cca220d637 feat(recent-allies): greenfield Recent Allies system (track, notes, location toggle)
Implements the full client<->server surface for "Recent Allies" (the players you
recently grouped with, so you can note who they were), turning three Handle_NULL
opcodes into a working, persistent system.

Wire recovered byte-exact by decompiling the client readers/serializers:
- CMSG_SET_ALLOW_RECENT_ALLIES_SEE_LOCATION (sub_7FF72914CCD0) = 1 packed bit.
- CMSG_RECENT_ALLY_REQUEST_DATA (sub_7FF7290805B0) = empty.
- CMSG_RECENT_ALLY_SET_NOTE (sub_7FF7290806C0) = { PackedGuid, bit-length note, bit }.
- SMSG_RECENT_ALLY_DATA_RESPONSE (reader sub_7FF7290BBE20 -> entry sub_7FF729162B00)
  = { u32 count, entry[]{ PackedGuid, u64 wowAccount, u32, activity-vector{u8,u64,u32,u32},
  11-bit note + 3 flag bits, note bytes } }.
- SMSG_RECENT_ALLY_NOTE_UPDATED (reader sub_7FF7290BBF10) = { u32, PackedGuid, u64, note }.
  The note length is an 11-bit bit-length field (2048 = 1<<11 sentinel in the readers);
  the 3 entry flag bits and the 24-byte "shared activity" sub-records have no
  offline-resolvable semantics, so they are sent 0/empty (structure honest, values zeroed).

System:
- RecentAlliesMgr: query-on-demand, DB-backed (no session cache) - RecordGrouping (mutual,
  both directions), GetAllies (most-recent-first, capped 100), SetNote, and the persisted
  Set/GetAllowSeeLocation toggle.
- Tracking hook in Group::AddMember: on joining a (non-BG) party/raid, records the new
  member and every other online member as mutual recent allies.
- Two tables (character_recent_allies + character_recent_ally_settings) with base schema +
  update SQL, and five CharacterDatabase prepared statements.
- RecentAllyHandler: the three CMSG handlers; SET_NOTE echoes SMSG_RECENT_ALLY_NOTE_UPDATED.
2026-07-08 15:04:30 -03:00
luis f109800b85 feat(war-games): P1 - port both groups into the arranged match on accept
On CMSG_ACCEPT_WARGAME_INVITE acceptance, actually start the war game instead of
just echoing the response: create the chosen battleground/arena, queue both premade
groups onto forced opposing teams (challenger ALLIANCE, opponent HORDE), and invite
them in. Players then port via the existing NeedConfirmation -> CMSG_BATTLEFIELD_PORT
-> SendToBattleground handshake, exactly like a normal queue pop.

Built against the rated-arena start path (BattlegroundQueue::Update: CreateNewBattleground
-> AddGroup -> InviteGroupToBG -> StartBattleground), but with no matchmaking since both
groups are known up front. Validates the recorded challenge's BattlemasterListID against
sBattlemasterListStore, resolves the level bracket from the challenger, and derives the
arena team size from the challenging group (0 for battlegrounds).

- BattlegroundQueue: new public AddWargameSide(leader, group, bg, bracketEntry, team) that
  queues a whole premade side onto a forced team, registers each member's queue slot, and
  fires the enter-confirmation (wraps the private InviteGroupToBG; keeps its visibility).
- BattleGroundHandler: HandleAcceptWargameInvite builds the instance and queues both sides.
2026-07-08 14:55:58 -03:00
luis 4e405e2a81 feat(wargames): P0 - war-game challenge/accept round-trip
War Games (arranged PvP practice matches between two premade groups) were entirely unhandled: all four
CMSG were Handle_NULL and TC never constructed the SMSG, despite the queue infrastructure
(BattlegroundQueueIdType::Wargame, Battleground::Wargame type, ERR_WARGAME_* results) already existing.

This builds the full challenge handshake:
- CMSG_START_WAR_GAME: a party leader challenges another group. Validates leadership, resolves the opposing
  group + its leader, records the pending request, and sends SMSG_CHECK_WARGAME_ENTRY to the opposing leader
  plus SMSG_WARGAME_REQUEST_SUCCESSFULLY_SENT_TO_OPPONENT back to the challenger.
- CMSG_ACCEPT_WARGAME_INVITE: the opposing leader answers. Correlates against the recorded challenge and
  replies to the challenger with SMSG_WARGAME_REQUEST_OPPONENT_RESPONSE (accepted/declined).

Wire recovered byte-exact from the 12.0.7 client:
- CMSG_START_WAR_GAME (send serializer sub_7FF72906F9F0): PackedGUID OpposingPartyMember, uint32, uint16,
  uint64 QueueID, trailing bit TournamentRules. (The flat opcode-layout tool under-reported this as guid+u32+bit;
  decompiling the serializer recovered the additional uint16 + uint64.)
- CMSG_ACCEPT_WARGAME_INVITE (sub_7FF72906FC80): PackedGUID OpposingPartyMember, uint64 QueueID, trailing bit.
- SMSG_CHECK_WARGAME_ENTRY (client deserializer sub_7FF729086A80): PackedGUID, uint64 QueueID, uint64 Time,
  bit7-of-a-byte TournamentRules (written as an explicit MSB-first byte, matching the client's >>7 read).

Field48/52 in the challenge (chosen battleground selection) are named by inference from wire position and are
read to consume the packet; only OpposingPartyMember/QueueID/TournamentRules drive P0 logic. The challenge
registry is in-memory and ephemeral (no persistence), keyed by the opposing leader; handlers run on the world
thread so no locking is needed. P1 (queue both groups into a wargame instance on acceptance) is left documented.
2026-07-08 14:51:54 -03:00