optimise Gacha code & fix rarity bug

This commit is contained in:
wish
2023-11-22 22:54:18 +11:00
parent 3f9c2e87f1
commit ab6c86ce8e

View File

@@ -116,103 +116,113 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
return return
} }
var count uint16 rows, err := s.server.db.Queryx("SELECT id, min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden FROM gacha_shop")
shopEntries, err := s.server.db.Queryx("SELECT id, min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden FROM gacha_shop")
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
resp := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
resp.WriteUint32(0)
var gacha Gacha var gacha Gacha
for shopEntries.Next() { var gachas []Gacha
err = shopEntries.StructScan(&gacha) for rows.Next() {
if err != nil { err = rows.StructScan(&gacha)
continue if err == nil {
gachas = append(gachas, gacha)
} }
resp.WriteUint32(gacha.ID)
resp.WriteBytes(make([]byte, 16)) // Rank restriction
resp.WriteUint32(gacha.MinGR)
resp.WriteUint32(gacha.MinHR)
resp.WriteUint32(0) // only 0 in known packet
ps.Uint8(resp, gacha.Name, true)
ps.Uint8(resp, gacha.URLBanner, false)
ps.Uint8(resp, gacha.URLFeature, false)
resp.WriteBool(gacha.Wide)
ps.Uint8(resp, gacha.URLThumbnail, false)
resp.WriteUint8(0) // Unk
if gacha.Recommended {
resp.WriteUint8(2)
} else {
resp.WriteUint8(0)
}
resp.WriteUint8(gacha.GachaType)
resp.WriteBool(gacha.Hidden)
count++
} }
resp.Seek(0, 0) bf.WriteUint16(uint16(len(gachas)))
resp.WriteUint16(count) bf.WriteUint16(uint16(len(gachas)))
resp.WriteUint16(count) for _, g := range gachas {
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) bf.WriteUint32(g.ID)
bf.WriteUint32(0) // Unknown rank restrictions
bf.WriteUint32(0)
bf.WriteUint32(0)
bf.WriteUint32(0)
bf.WriteUint32(g.MinGR)
bf.WriteUint32(g.MinHR)
bf.WriteUint32(0) // only 0 in known packet
ps.Uint8(bf, g.Name, true)
ps.Uint8(bf, g.URLBanner, false)
ps.Uint8(bf, g.URLFeature, false)
if _config.ErupeConfig.RealClientMode >= _config.G10 {
bf.WriteBool(g.Wide)
ps.Uint8(bf, g.URLThumbnail, false)
}
if g.Recommended {
bf.WriteUint16(2)
} else {
bf.WriteUint16(0)
}
bf.WriteUint8(g.GachaType)
if _config.ErupeConfig.RealClientMode >= _config.G10 {
bf.WriteBool(g.Hidden)
}
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
case 2: // Actual gacha case 2: // Actual gacha
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(pkt.ShopID) bf.WriteUint32(pkt.ShopID)
var gachaType int var gachaType int
s.server.db.QueryRow(`SELECT gacha_type FROM gacha_shop WHERE id = $1`, pkt.ShopID).Scan(&gachaType) s.server.db.QueryRow(`SELECT gacha_type FROM gacha_shop WHERE id = $1`, pkt.ShopID).Scan(&gachaType)
entries, err := s.server.db.Queryx(`SELECT entry_type, id, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points, name FROM gacha_entries WHERE gacha_id = $1 ORDER BY weight DESC`, pkt.ShopID) rows, err := s.server.db.Queryx(`SELECT entry_type, id, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points, COALESCE(name, '') AS name FROM gacha_entries WHERE gacha_id = $1 ORDER BY weight DESC`, pkt.ShopID)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
var divisor float64 var divisor float64
s.server.db.QueryRow(`SELECT COALESCE(SUM(weight) / 100000.0, 0) AS chance FROM gacha_entries WHERE gacha_id = $1`, pkt.ShopID).Scan(&divisor) s.server.db.QueryRow(`SELECT COALESCE(SUM(weight) / 100000.0, 0) AS chance FROM gacha_entries WHERE gacha_id = $1`, pkt.ShopID).Scan(&divisor)
var entryCount uint16
bf.WriteUint16(0) var entry GachaEntry
gachaEntry := GachaEntry{} var entries []GachaEntry
gachaItem := GachaItem{} var item GachaItem
for entries.Next() { for rows.Next() {
entryCount++ err = rows.StructScan(&entry)
entries.StructScan(&gachaEntry) if err == nil {
bf.WriteUint8(gachaEntry.EntryType) entries = append(entries, entry)
bf.WriteUint32(gachaEntry.ID) }
bf.WriteUint8(gachaEntry.ItemType) }
bf.WriteUint32(gachaEntry.ItemNumber) bf.WriteUint16(uint16(len(entries)))
bf.WriteUint16(gachaEntry.ItemQuantity) for _, ge := range entries {
var items []GachaItem
bf.WriteUint8(ge.EntryType)
bf.WriteUint32(ge.ID)
bf.WriteUint8(ge.ItemType)
bf.WriteUint32(ge.ItemNumber)
bf.WriteUint16(ge.ItemQuantity)
if gachaType >= 4 { // If box if gachaType >= 4 { // If box
bf.WriteUint16(1) bf.WriteUint16(1)
} else { } else {
bf.WriteUint16(uint16(gachaEntry.Weight / divisor)) bf.WriteUint16(uint16(ge.Weight / divisor))
} }
bf.WriteUint8(gachaEntry.Rarity) bf.WriteUint8(ge.Rarity)
bf.WriteUint8(gachaEntry.Rolls) bf.WriteUint8(ge.Rolls)
var itemCount uint8 rows, err = s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id=$1`, ge.ID)
temp := byteframe.NewByteFrame()
items, err := s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id=$1`, gachaEntry.ID)
if err != nil { if err != nil {
bf.WriteUint8(0) bf.WriteUint8(0)
} else { } else {
for items.Next() { for rows.Next() {
itemCount++ err = rows.StructScan(&item)
items.StructScan(&gachaItem) if err == nil {
temp.WriteUint16(uint16(gachaItem.ItemType)) items = append(items, item)
temp.WriteUint16(gachaItem.ItemID) }
temp.WriteUint16(gachaItem.Quantity)
} }
bf.WriteUint8(itemCount) bf.WriteUint8(uint8(len(items)))
} }
bf.WriteUint16(gachaEntry.FrontierPoints) bf.WriteUint16(ge.FrontierPoints)
bf.WriteUint8(gachaEntry.DailyLimit) bf.WriteUint8(ge.DailyLimit)
if gachaEntry.EntryType < 10 { if ge.EntryType < 10 {
ps.Uint8(bf, gachaEntry.Name, true) ps.Uint8(bf, ge.Name, true)
} else { } else {
bf.WriteUint8(0) bf.WriteUint8(0)
} }
bf.WriteBytes(temp.Data()) for _, gi := range items {
bf.WriteUint16(uint16(gi.ItemType))
bf.WriteUint16(gi.ItemID)
bf.WriteUint16(gi.Quantity)
}
} }
bf.Seek(4, 0)
bf.WriteUint16(entryCount)
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
case 3: // Hunting Festival Exchange case 3: // Hunting Festival Exchange
fallthrough fallthrough
@@ -424,7 +434,7 @@ func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPlayNormalGacha) pkt := p.(*mhfpacket.MsgMhfPlayNormalGacha)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var gachaEntries []GachaEntry var entries []GachaEntry
var entry GachaEntry var entry GachaEntry
var rewards []GachaItem var rewards []GachaItem
var reward GachaItem var reward GachaItem
@@ -433,31 +443,40 @@ func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
temp := byteframe.NewByteFrame()
entries, err := s.server.db.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID) rows, err := s.server.db.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
for entries.Next() { for rows.Next() {
entries.StructScan(&entry) err = rows.StructScan(&entry)
gachaEntries = append(gachaEntries, entry)
}
rewardEntries, err := getRandomEntries(gachaEntries, rolls, false)
for i := range rewardEntries {
items, err := s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID)
if err != nil { if err != nil {
continue continue
} }
for items.Next() { entries = append(entries, entry)
items.StructScan(&reward) }
rewardEntries, err := getRandomEntries(entries, rolls, false)
temp := byteframe.NewByteFrame()
for i := range rewardEntries {
rows, err = s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID)
if err != nil {
continue
}
for rows.Next() {
err = rows.StructScan(&reward)
if err != nil {
continue
}
rewards = append(rewards, reward) rewards = append(rewards, reward)
temp.WriteUint8(reward.ItemType) temp.WriteUint8(reward.ItemType)
temp.WriteUint16(reward.ItemID) temp.WriteUint16(reward.ItemID)
temp.WriteUint16(reward.Quantity) temp.WriteUint16(reward.Quantity)
temp.WriteUint8(entry.Rarity) temp.WriteUint8(rewardEntries[i].Rarity)
} }
} }
bf.WriteUint8(uint8(len(rewards))) bf.WriteUint8(uint8(len(rewards)))
bf.WriteBytes(temp.Data()) bf.WriteBytes(temp.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
@@ -467,7 +486,7 @@ func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPlayStepupGacha) pkt := p.(*mhfpacket.MsgMhfPlayStepupGacha)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var gachaEntries []GachaEntry var entries []GachaEntry
var entry GachaEntry var entry GachaEntry
var rewards []GachaItem var rewards []GachaItem
var reward GachaItem var reward GachaItem
@@ -479,40 +498,49 @@ func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {
s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+(SELECT frontier_points FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2) WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$3)", pkt.GachaID, pkt.RollType, s.charID) s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+(SELECT frontier_points FROM gacha_entries WHERE gacha_id = $1 AND entry_type = $2) WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$3)", pkt.GachaID, pkt.RollType, s.charID)
s.server.db.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID) s.server.db.Exec(`DELETE FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`, pkt.GachaID, s.charID)
s.server.db.Exec(`INSERT INTO gacha_stepup (gacha_id, step, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, pkt.RollType+1, s.charID) s.server.db.Exec(`INSERT INTO gacha_stepup (gacha_id, step, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, pkt.RollType+1, s.charID)
temp := byteframe.NewByteFrame()
guaranteedItems := getGuaranteedItems(s, pkt.GachaID, pkt.RollType) rows, err := s.server.db.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID)
for _, item := range guaranteedItems {
temp.WriteUint8(item.ItemType)
temp.WriteUint16(item.ItemID)
temp.WriteUint16(item.Quantity)
temp.WriteUint8(0)
}
entries, err := s.server.db.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
for entries.Next() { for rows.Next() {
entries.StructScan(&entry) err = rows.StructScan(&entry)
gachaEntries = append(gachaEntries, entry)
}
rewardEntries, err := getRandomEntries(gachaEntries, rolls, false)
for i := range rewardEntries {
items, err := s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID)
if err != nil { if err != nil {
continue continue
} }
for items.Next() { entries = append(entries, entry)
items.StructScan(&reward) }
guaranteedItems := getGuaranteedItems(s, pkt.GachaID, pkt.RollType)
rewardEntries, err := getRandomEntries(entries, rolls, false)
temp := byteframe.NewByteFrame()
for i := range rewardEntries {
rows, err = s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID)
if err != nil {
continue
}
for rows.Next() {
err = rows.StructScan(&reward)
if err != nil {
continue
}
rewards = append(rewards, reward) rewards = append(rewards, reward)
temp.WriteUint8(reward.ItemType) temp.WriteUint8(reward.ItemType)
temp.WriteUint16(reward.ItemID) temp.WriteUint16(reward.ItemID)
temp.WriteUint16(reward.Quantity) temp.WriteUint16(reward.Quantity)
temp.WriteUint8(entry.Rarity) temp.WriteUint8(rewardEntries[i].Rarity)
} }
} }
bf.WriteUint8(uint8(len(rewards) + len(guaranteedItems))) bf.WriteUint8(uint8(len(rewards) + len(guaranteedItems)))
bf.WriteUint8(uint8(len(rewards))) bf.WriteUint8(uint8(len(rewards)))
for _, item := range guaranteedItems {
bf.WriteUint8(item.ItemType)
bf.WriteUint16(item.ItemID)
bf.WriteUint16(item.Quantity)
bf.WriteUint8(0)
}
bf.WriteBytes(temp.Data()) bf.WriteBytes(temp.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
addGachaItem(s, rewards) addGachaItem(s, rewards)
@@ -561,7 +589,7 @@ func handleMsgMhfGetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPlayBoxGacha) pkt := p.(*mhfpacket.MsgMhfPlayBoxGacha)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var gachaEntries []GachaEntry var entries []GachaEntry
var entry GachaEntry var entry GachaEntry
var rewards []GachaItem var rewards []GachaItem
var reward GachaItem var reward GachaItem
@@ -570,17 +598,18 @@ func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
temp := byteframe.NewByteFrame() rows, err := s.server.db.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID)
entries, err := s.server.db.Queryx(`SELECT id, weight, rarity FROM gacha_entries WHERE gacha_id = $1 AND entry_type = 100 ORDER BY weight DESC`, pkt.GachaID)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return return
} }
for entries.Next() { for rows.Next() {
entries.StructScan(&entry) err = rows.StructScan(&entry)
gachaEntries = append(gachaEntries, entry) if err == nil {
entries = append(entries, entry)
}
} }
rewardEntries, err := getRandomEntries(gachaEntries, rolls, true) rewardEntries, err := getRandomEntries(entries, rolls, true)
for i := range rewardEntries { for i := range rewardEntries {
items, err := s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID) items, err := s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id = $1`, rewardEntries[i].ID)
if err != nil { if err != nil {
@@ -588,16 +617,19 @@ func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
} }
s.server.db.Exec(`INSERT INTO gacha_box (gacha_id, entry_id, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, rewardEntries[i].ID, s.charID) s.server.db.Exec(`INSERT INTO gacha_box (gacha_id, entry_id, character_id) VALUES ($1, $2, $3)`, pkt.GachaID, rewardEntries[i].ID, s.charID)
for items.Next() { for items.Next() {
items.StructScan(&reward) err = items.StructScan(&reward)
rewards = append(rewards, reward) if err == nil {
temp.WriteUint8(reward.ItemType) rewards = append(rewards, reward)
temp.WriteUint16(reward.ItemID) }
temp.WriteUint16(reward.Quantity)
temp.WriteUint8(0)
} }
} }
bf.WriteUint8(uint8(len(rewards))) bf.WriteUint8(uint8(len(rewards)))
bf.WriteBytes(temp.Data()) for _, r := range rewards {
bf.WriteUint8(r.ItemType)
bf.WriteUint16(r.ItemID)
bf.WriteUint16(r.Quantity)
bf.WriteUint8(0)
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
addGachaItem(s, rewards) addGachaItem(s, rewards)
} }