From d578e68b79566f1bb333f51b8a96bec8238d2ec2 Mon Sep 17 00:00:00 2001 From: Houmgaor Date: Tue, 17 Mar 2026 19:11:59 +0100 Subject: [PATCH] docs(gacha): clarify G1-GG vs ZZ configuration to prevent client crashes (#175) The G1-GG gacha code path (PR #150) included example data in comments that used non-zero item_type/item_number/item_quantity on entry_type=100 rows. Users copying these values for ZZ servers caused client crashes because the ZZ client interprets those fields as material requirements. - Replace unclear PR #150 comment with explicit WARNING against using G1-GG example values for ZZ servers - Add gacha configuration guide header to GachaDemo.sql explaining the 3-table system, entry types, and item type codes - Add Mega Potion example showing correct way to add custom items - Reference Enumerations.md for the full item type list --- server/channelserver/handlers_shop.go | 27 ++++++++++++--------- server/migrations/seed/GachaDemo.sql | 35 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/server/channelserver/handlers_shop.go b/server/channelserver/handlers_shop.go index a1747de5e..ce255aa71 100644 --- a/server/channelserver/handlers_shop.go +++ b/server/channelserver/handlers_shop.go @@ -144,18 +144,21 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) { for _, ge := range entries { var items []GachaItem if s.server.erupeConfig.RealClientMode <= cfg.GG { - // If you need to configure the optional material list among the three options,Configure directly in gacha_detries,The same Entry Type can be merged and displayed in GG,In addition, the prizes are also directly configured in the gacha-entries table, - // MHFG1~GG does not use the gacha_items table throughout the entire process, which meets the lottery function of MHFG with a more single function - // In addition, the MHFG function itself is relatively simple,Example of lottery configuration for G1~GG: - // eg: gachaname:test - // entry: itemgroup: group1:(choose one of the two) ITEM_1_ID:7 COUNT:1 ITEM_1_ID:8 COUNT:2group2:ITEM_1_ID:9 COUNT:3 ; reward:reward1: ITEM_ID:1 COUNT:4 weight:10% reward1: ITEM_ID:2 COUNT:5 weight:90% - // table:gacha_shop |1|0|0|test|null|null|null|f|f|3|f| - // table:gacha_entries - // |1|1|0|7|7|1|0|0|0|0|0|null| - // |4|1|0|7|8|2|0|0|0|0|0|null| - // |5|1|1|7|9|3|0|0|0|0|0|null| - // |8|1|100|7|1|4|1000|0|0|0|0|null| - // |9|1|100|7|2|5|9000|0|0|0|0|null| + // G1–GG gacha format: rewards are defined directly in gacha_entries + // (item_type/item_number/item_quantity), NOT in gacha_items. + // This is a completely different format from G10+/ZZ. + // + // WARNING: Do NOT use these example values for ZZ servers. + // For ZZ, entry_type=100 rows must have item_type=0, item_number=0, + // item_quantity=0; actual rewards go in the gacha_items table only. + // + // G1–GG example gacha_entries: + // |id|gacha_id|entry_type|item_type|item_number|item_qty|weight| + // |1 |1 |0 |7 |7 |1 |0 | + // |4 |1 |0 |7 |8 |2 |0 | + // |5 |1 |1 |7 |9 |3 |0 | + // |8 |1 |100 |7 |1 |4 |1000 | + // |9 |1 |100 |7 |2 |5 |9000 | bf.WriteUint8(ge.EntryType) bf.WriteUint32(ge.ID) bf.WriteUint8(ge.ItemType) diff --git a/server/migrations/seed/GachaDemo.sql b/server/migrations/seed/GachaDemo.sql index b32c1c3ac..29a6d5e6c 100644 --- a/server/migrations/seed/GachaDemo.sql +++ b/server/migrations/seed/GachaDemo.sql @@ -1,5 +1,32 @@ BEGIN; +-- ============================================================================= +-- Gacha Configuration Guide (G10+ / ZZ clients) +-- ============================================================================= +-- +-- Gacha uses THREE tables: +-- gacha_shop — defines the gacha lottery (name, banners, type) +-- gacha_entries — defines roll costs (entry_type 0/1/...) and reward pool (entry_type 100) +-- gacha_items — defines the actual items awarded for each reward entry +-- +-- Entry types: +-- 0, 1, 2, ... = Roll cost tiers. item_type/item_number/item_quantity define the currency +-- and amount to deduct. "rolls" = how many random draws this tier gives. +-- 100 = Reward pool entry. The client draws from these when rolling. +-- For G10+/ZZ: item_type, item_number, item_quantity MUST be 0. +-- The actual reward items are defined in gacha_items (linked by entry ID). +-- "weight" controls draw probability; "rarity" sets the display star rating. +-- +-- Item types in gacha_items (see Enumerations.md for the full list): +-- 0 = Legs, 1 = Head, 2 = Chest, 3 = Arms, 4 = Waist, +-- 5 = Melee weapon, 6 = Ranged weapon, 7 = Consumable item, +-- 8 = Furniture, 10 = Zenny, 17 = N Points, 19 = Gacha Koban, ... +-- +-- WARNING: For G1–GG clients, gacha works differently — rewards are defined +-- directly in gacha_entries and gacha_items is NOT used. Do not mix the two +-- formats. See handlers_shop.go for the G1–GG code path. +-- ============================================================================= + -- Start Normal Demo INSERT INTO gacha_shop (min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden) VALUES (0, 0, 'Normal Demo', @@ -31,6 +58,14 @@ INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_qu VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 10, 2, 0, 0, 0); INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 3, 0); + +-- Example: adding a consumable item (Mega Potion, item_id=8) as a gacha reward. +-- Note: for entry_type=100, item_type/item_number/item_quantity in gacha_entries +-- MUST remain 0 for G10+/ZZ clients. The reward is defined only in gacha_items. +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 50, 1, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 7, 8, 1); -- End Normal Demo -- Start Step-Up Demo