Merge pull request #97 from ZeruLight/fix/rework-distributions

fix/rework-distributions
This commit is contained in:
wish
2023-11-11 19:42:08 +11:00
committed by GitHub
4 changed files with 178 additions and 131 deletions

View File

@@ -0,0 +1,11 @@
BEGIN;
-- Adds a Distribution that can be accepted up to 20 times that gives one of Item Type 30 (Item Box extra page)
INSERT INTO distribution (type, event_name, description, times_acceptable) VALUES (1, 'Extra Item Storage', '~C05Adds one new page to your Item Box.', 20);
INSERT INTO distribution_items (distribution_id, item_type, quantity) VALUES ((SELECT id FROM distribution ORDER BY id DESC LIMIT 1), 30, 1);
-- Adds a Distribution that can be accepted up to 20 times that gives one of Item Type 31 (Equipment Box extra page)
INSERT INTO distribution (type, event_name, description, times_acceptable) VALUES (1, 'Extra Equipment Storage', '~C05Adds one new page to your Equipment Box.', 20);
INSERT INTO distribution_items (distribution_id, item_type, quantity) VALUES ((SELECT id FROM distribution ORDER BY id DESC LIMIT 1), 31, 1);
END;

View File

@@ -10,7 +10,7 @@ import (
// MsgMhfEnumerateDistItem represents the MSG_MHF_ENUMERATE_DIST_ITEM // MsgMhfEnumerateDistItem represents the MSG_MHF_ENUMERATE_DIST_ITEM
type MsgMhfEnumerateDistItem struct { type MsgMhfEnumerateDistItem struct {
AckHandle uint32 AckHandle uint32
Unk0 uint8 DistType uint8
Unk1 uint8 Unk1 uint8
Unk2 uint16 Unk2 uint16
Unk3 []byte Unk3 []byte
@@ -24,9 +24,9 @@ func (m *MsgMhfEnumerateDistItem) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfEnumerateDistItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfEnumerateDistItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8() m.DistType = bf.ReadUint8()
m.Unk1 = bf.ReadUint8() m.Unk1 = bf.ReadUint8()
m.Unk2 = bf.ReadUint16() m.Unk2 = bf.ReadUint16() // Maximum? Hardcoded to 256
m.Unk3 = bf.ReadBytes(uint(bf.ReadUint8())) m.Unk3 = bf.ReadBytes(uint(bf.ReadUint8()))
return nil return nil
} }

View File

@@ -0,0 +1,36 @@
BEGIN;
-- This will delete all of your old distribution data!
--ALTER TABLE IF EXISTS public.distribution DROP COLUMN IF EXISTS data;
CREATE TABLE public.distribution_items
(
id serial PRIMARY KEY,
distribution_id integer NOT NULL,
item_type integer NOT NULL,
item_id integer,
quantity integer
);
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_hr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_hr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_sr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_sr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_gr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_gr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_hr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_hr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_sr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_sr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_gr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_gr DROP NOT NULL;
UPDATE distribution SET min_hr=NULL WHERE min_hr=65535;
UPDATE distribution SET max_hr=NULL WHERE max_hr=65535;
UPDATE distribution SET min_sr=NULL WHERE min_sr=65535;
UPDATE distribution SET max_sr=NULL WHERE max_sr=65535;
UPDATE distribution SET min_gr=NULL WHERE min_gr=65535;
UPDATE distribution SET max_gr=NULL WHERE max_gr=65535;
END;

View File

@@ -4,21 +4,22 @@ import (
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring" ps "erupe-ce/common/pascalstring"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"time"
"go.uber.org/zap" "go.uber.org/zap"
) )
type ItemDist struct { type Distribution struct {
ID uint32 `db:"id"` ID uint32 `db:"id"`
Deadline uint32 `db:"deadline"` Deadline time.Time `db:"deadline"`
TimesAcceptable uint16 `db:"times_acceptable"` TimesAcceptable uint16 `db:"times_acceptable"`
TimesAccepted uint16 `db:"times_accepted"` TimesAccepted uint16 `db:"times_accepted"`
MinHR uint16 `db:"min_hr"` MinHR int16 `db:"min_hr"`
MaxHR uint16 `db:"max_hr"` MaxHR int16 `db:"max_hr"`
MinSR uint16 `db:"min_sr"` MinSR int16 `db:"min_sr"`
MaxSR uint16 `db:"max_sr"` MaxSR int16 `db:"max_sr"`
MinGR uint16 `db:"min_gr"` MinGR int16 `db:"min_gr"`
MaxGR uint16 `db:"max_gr"` MaxGR int16 `db:"max_gr"`
EventName string `db:"event_name"` EventName string `db:"event_name"`
Description string `db:"description"` Description string `db:"description"`
Data []byte `db:"data"` Data []byte `db:"data"`
@@ -26,54 +27,55 @@ type ItemDist struct {
func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateDistItem) pkt := p.(*mhfpacket.MsgMhfEnumerateDistItem)
var itemDists []Distribution
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
distCount := 0 rows, err := s.server.db.Queryx(`
dists, err := s.server.db.Queryx(`
SELECT d.id, event_name, description, times_acceptable, SELECT d.id, event_name, description, times_acceptable,
min_hr, max_hr, min_sr, max_sr, min_gr, max_gr, COALESCE(min_hr, -1) AS min_hr, COALESCE(max_hr, -1) AS max_hr,
COALESCE(min_sr, -1) AS min_sr, COALESCE(max_sr, -1) AS max_sr,
COALESCE(min_gr, -1) AS min_gr, COALESCE(max_gr, -1) AS max_gr,
( (
SELECT count(*) SELECT count(*) FROM distributions_accepted da
FROM distributions_accepted da WHERE d.id = da.distribution_id AND da.character_id = $1
WHERE d.id = da.distribution_id
AND da.character_id = $1
) AS times_accepted, ) AS times_accepted,
CASE COALESCE(deadline, TO_TIMESTAMP(0)) AS deadline
WHEN (EXTRACT(epoch FROM deadline)::int) IS NULL THEN 0
ELSE (EXTRACT(epoch FROM deadline)::int)
END deadline
FROM distribution d FROM distribution d
WHERE character_id = $1 AND type = $2 OR character_id IS NULL AND type = $2 ORDER BY id DESC; WHERE character_id = $1 AND type = $2 OR character_id IS NULL AND type = $2 ORDER BY id DESC
`, s.charID, pkt.Unk0) `, s.charID, pkt.DistType)
if err == nil {
var itemDist Distribution
for rows.Next() {
err = rows.StructScan(&itemDist)
if err != nil { if err != nil {
s.logger.Error("Error getting distribution data from db", zap.Error(err)) continue
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
} else {
for dists.Next() {
distCount++
distData := &ItemDist{}
err = dists.StructScan(&distData)
if err != nil {
s.logger.Error("Error parsing item distribution data", zap.Error(err))
} }
bf.WriteUint32(distData.ID) itemDists = append(itemDists, itemDist)
bf.WriteUint32(distData.Deadline) }
}
bf.WriteUint16(uint16(len(itemDists)))
for _, dist := range itemDists {
bf.WriteUint32(dist.ID)
bf.WriteUint32(uint32(dist.Deadline.Unix()))
bf.WriteUint32(0) // Unk bf.WriteUint32(0) // Unk
bf.WriteUint16(distData.TimesAcceptable) bf.WriteUint16(dist.TimesAcceptable)
bf.WriteUint16(distData.TimesAccepted) bf.WriteUint16(dist.TimesAccepted)
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk
bf.WriteUint16(distData.MinHR) bf.WriteInt16(dist.MinHR)
bf.WriteUint16(distData.MaxHR) bf.WriteInt16(dist.MaxHR)
bf.WriteUint16(distData.MinSR) bf.WriteInt16(dist.MinSR)
bf.WriteUint16(distData.MaxSR) bf.WriteInt16(dist.MaxSR)
bf.WriteUint16(distData.MinGR) bf.WriteInt16(dist.MinGR)
bf.WriteUint16(distData.MaxGR) bf.WriteInt16(dist.MaxGR)
bf.WriteUint8(0) bf.WriteUint8(0)
bf.WriteUint16(0) bf.WriteUint16(0)
bf.WriteUint8(0) bf.WriteUint8(0)
bf.WriteUint16(0) bf.WriteUint16(0)
bf.WriteUint16(0) bf.WriteUint16(0)
bf.WriteUint8(0) bf.WriteUint8(0)
ps.Uint8(bf, distData.EventName, true) ps.Uint8(bf, dist.EventName, true)
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
for j := 0; j < 13; j++ { for j := 0; j < 13; j++ {
bf.WriteUint8(0) bf.WriteUint8(0)
@@ -90,75 +92,73 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
} }
} }
} }
resp := byteframe.NewByteFrame() doAckBufSucceed(s, pkt.AckHandle, bf.Data())
resp.WriteUint16(uint16(distCount))
resp.WriteBytes(bf.Data())
resp.WriteUint8(0)
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
type DistributionItem struct {
ItemType uint8 `db:"item_type"`
ID uint32 `db:"id"`
ItemID uint32 `db:"item_id"`
Quantity uint32 `db:"quantity"`
}
func getDistributionItems(s *Session, i uint32) []DistributionItem {
var distItems []DistributionItem
rows, err := s.server.db.Queryx(`SELECT id, item_type, COALESCE(item_id, 0) AS item_id, COALESCE(quantity, 0) AS quantity FROM distribution_items WHERE distribution_id=$1`, i)
if err == nil {
var distItem DistributionItem
for rows.Next() {
err = rows.StructScan(&distItem)
if err != nil {
continue
}
distItems = append(distItems, distItem)
}
}
return distItems
} }
func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfApplyDistItem) pkt := p.(*mhfpacket.MsgMhfApplyDistItem)
bf := byteframe.NewByteFrame()
if pkt.DistributionID == 0 { bf.WriteUint32(pkt.DistributionID)
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 6)) distItems := getDistributionItems(s, pkt.DistributionID)
} else { bf.WriteUint16(uint16(len(distItems)))
row := s.server.db.QueryRowx("SELECT data FROM distribution WHERE id = $1", pkt.DistributionID) for _, item := range distItems {
dist := &ItemDist{} bf.WriteUint8(item.ItemType)
err := row.StructScan(dist) bf.WriteUint32(item.ItemID)
if err != nil { bf.WriteUint32(item.Quantity)
s.logger.Error("Error parsing item distribution data", zap.Error(err)) bf.WriteUint32(item.ID)
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 6)) }
return doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
if len(dist.Data) >= 2 { func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) {
distData := byteframe.NewByteFrameFromBytes(dist.Data) pkt := p.(*mhfpacket.MsgMhfAcquireDistItem)
distItems := int(distData.ReadUint16()) if pkt.DistributionID > 0 {
for i := 0; i < distItems; i++ { _, err := s.server.db.Exec(`INSERT INTO public.distributions_accepted VALUES ($1, $2)`, pkt.DistributionID, s.charID)
if len(dist.Data) >= 2+(i*13) { if err == nil {
itemType := distData.ReadUint8() distItems := getDistributionItems(s, pkt.DistributionID)
_ = distData.ReadBytes(6) for _, item := range distItems {
quantity := int(distData.ReadUint16()) switch item.ItemType {
_ = distData.ReadBytes(4)
switch itemType {
case 17: case 17:
_ = addPointNetcafe(s, quantity) _ = addPointNetcafe(s, int(item.Quantity))
case 19: case 19:
s.server.db.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", quantity, s.charID) s.server.db.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID)
case 20: case 20:
s.server.db.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", quantity, s.charID) s.server.db.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID)
case 21: case 21:
s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", quantity, s.charID) s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID)
case 23: case 23:
saveData, err := GetCharacterSaveData(s, s.charID) saveData, err := GetCharacterSaveData(s, s.charID)
if err == nil { if err == nil {
saveData.RP += uint16(quantity) saveData.RP += uint16(item.Quantity)
saveData.Save(s) saveData.Save(s)
} }
} }
} }
} }
} }
bf := byteframe.NewByteFrame()
bf.WriteUint32(pkt.DistributionID)
bf.WriteBytes(dist.Data)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
_, err = s.server.db.Exec(`
INSERT INTO public.distributions_accepted
VALUES ($1, $2)
`, pkt.DistributionID, s.charID)
if err != nil {
s.logger.Error("Error updating accepted dist count", zap.Error(err))
}
}
}
func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireDistItem)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }