Skip to content

Commit

Permalink
optimise Gacha code & fix rarity bug
Browse files Browse the repository at this point in the history
  • Loading branch information
sekaiwish committed Nov 22, 2023
1 parent 3f9c2e8 commit ab6c86c
Showing 1 changed file with 137 additions and 105 deletions.
242 changes: 137 additions & 105 deletions server/channelserver/handlers_shop_gacha.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,103 +116,113 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
return
}

var count uint16
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")
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")
if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return
}
resp := byteframe.NewByteFrame()
resp.WriteUint32(0)
bf := byteframe.NewByteFrame()
var gacha Gacha
for shopEntries.Next() {
err = shopEntries.StructScan(&gacha)
if err != nil {
continue
var gachas []Gacha
for rows.Next() {
err = rows.StructScan(&gacha)
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)
}
bf.WriteUint16(uint16(len(gachas)))
bf.WriteUint16(uint16(len(gachas)))
for _, g := range gachas {
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 {
resp.WriteUint8(0)
bf.WriteUint16(0)
}
bf.WriteUint8(g.GachaType)
if _config.ErupeConfig.RealClientMode >= _config.G10 {
bf.WriteBool(g.Hidden)
}
resp.WriteUint8(gacha.GachaType)
resp.WriteBool(gacha.Hidden)
count++
}
resp.Seek(0, 0)
resp.WriteUint16(count)
resp.WriteUint16(count)
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
case 2: // Actual gacha
bf := byteframe.NewByteFrame()
bf.WriteUint32(pkt.ShopID)
var gachaType int
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 {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return
}
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)
var entryCount uint16
bf.WriteUint16(0)
gachaEntry := GachaEntry{}
gachaItem := GachaItem{}
for entries.Next() {
entryCount++
entries.StructScan(&gachaEntry)
bf.WriteUint8(gachaEntry.EntryType)
bf.WriteUint32(gachaEntry.ID)
bf.WriteUint8(gachaEntry.ItemType)
bf.WriteUint32(gachaEntry.ItemNumber)
bf.WriteUint16(gachaEntry.ItemQuantity)

var entry GachaEntry
var entries []GachaEntry
var item GachaItem
for rows.Next() {
err = rows.StructScan(&entry)
if err == nil {
entries = append(entries, entry)
}
}
bf.WriteUint16(uint16(len(entries)))
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
bf.WriteUint16(1)
} else {
bf.WriteUint16(uint16(gachaEntry.Weight / divisor))
bf.WriteUint16(uint16(ge.Weight / divisor))
}
bf.WriteUint8(gachaEntry.Rarity)
bf.WriteUint8(gachaEntry.Rolls)
bf.WriteUint8(ge.Rarity)
bf.WriteUint8(ge.Rolls)

var itemCount uint8
temp := byteframe.NewByteFrame()
items, err := s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id=$1`, gachaEntry.ID)
rows, err = s.server.db.Queryx(`SELECT item_type, item_id, quantity FROM gacha_items WHERE entry_id=$1`, ge.ID)
if err != nil {
bf.WriteUint8(0)
} else {
for items.Next() {
itemCount++
items.StructScan(&gachaItem)
temp.WriteUint16(uint16(gachaItem.ItemType))
temp.WriteUint16(gachaItem.ItemID)
temp.WriteUint16(gachaItem.Quantity)
for rows.Next() {
err = rows.StructScan(&item)
if err == nil {
items = append(items, item)
}
}
bf.WriteUint8(itemCount)
bf.WriteUint8(uint8(len(items)))
}

bf.WriteUint16(gachaEntry.FrontierPoints)
bf.WriteUint8(gachaEntry.DailyLimit)
if gachaEntry.EntryType < 10 {
ps.Uint8(bf, gachaEntry.Name, true)
bf.WriteUint16(ge.FrontierPoints)
bf.WriteUint8(ge.DailyLimit)
if ge.EntryType < 10 {
ps.Uint8(bf, ge.Name, true)
} else {
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())
case 3: // Hunting Festival Exchange
fallthrough
Expand Down Expand Up @@ -424,7 +434,7 @@ func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPlayNormalGacha)
bf := byteframe.NewByteFrame()
var gachaEntries []GachaEntry
var entries []GachaEntry
var entry GachaEntry
var rewards []GachaItem
var reward GachaItem
Expand All @@ -433,31 +443,40 @@ func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
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 {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return
}
for entries.Next() {
entries.StructScan(&entry)
gachaEntries = append(gachaEntries, entry)
for rows.Next() {
err = rows.StructScan(&entry)
if err != nil {
continue
}
entries = append(entries, entry)
}
rewardEntries, err := getRandomEntries(gachaEntries, rolls, false)

rewardEntries, err := getRandomEntries(entries, rolls, false)
temp := byteframe.NewByteFrame()
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)
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 items.Next() {
items.StructScan(&reward)
for rows.Next() {
err = rows.StructScan(&reward)
if err != nil {
continue
}
rewards = append(rewards, reward)
temp.WriteUint8(reward.ItemType)
temp.WriteUint16(reward.ItemID)
temp.WriteUint16(reward.Quantity)
temp.WriteUint8(entry.Rarity)
temp.WriteUint8(rewardEntries[i].Rarity)
}
}

bf.WriteUint8(uint8(len(rewards)))
bf.WriteBytes(temp.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
Expand All @@ -467,7 +486,7 @@ func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPlayStepupGacha)
bf := byteframe.NewByteFrame()
var gachaEntries []GachaEntry
var entries []GachaEntry
var entry GachaEntry
var rewards []GachaItem
var reward GachaItem
Expand All @@ -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(`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)
temp := byteframe.NewByteFrame()
guaranteedItems := getGuaranteedItems(s, pkt.GachaID, pkt.RollType)
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)

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 {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return
}
for entries.Next() {
entries.StructScan(&entry)
gachaEntries = append(gachaEntries, entry)
for rows.Next() {
err = rows.StructScan(&entry)
if err != nil {
continue
}
entries = append(entries, entry)
}
rewardEntries, err := getRandomEntries(gachaEntries, rolls, false)

guaranteedItems := getGuaranteedItems(s, pkt.GachaID, pkt.RollType)
rewardEntries, err := getRandomEntries(entries, rolls, false)
temp := byteframe.NewByteFrame()
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)
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 items.Next() {
items.StructScan(&reward)
for rows.Next() {
err = rows.StructScan(&reward)
if err != nil {
continue
}
rewards = append(rewards, reward)
temp.WriteUint8(reward.ItemType)
temp.WriteUint16(reward.ItemID)
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)))
for _, item := range guaranteedItems {
bf.WriteUint8(item.ItemType)
bf.WriteUint16(item.ItemID)
bf.WriteUint16(item.Quantity)
bf.WriteUint8(0)
}
bf.WriteBytes(temp.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
addGachaItem(s, rewards)
Expand Down Expand Up @@ -561,7 +589,7 @@ func handleMsgMhfGetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPlayBoxGacha)
bf := byteframe.NewByteFrame()
var gachaEntries []GachaEntry
var entries []GachaEntry
var entry GachaEntry
var rewards []GachaItem
var reward GachaItem
Expand All @@ -570,34 +598,38 @@ func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
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 {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return
}
for entries.Next() {
entries.StructScan(&entry)
gachaEntries = append(gachaEntries, entry)
for rows.Next() {
err = rows.StructScan(&entry)
if err == nil {
entries = append(entries, entry)
}
}
rewardEntries, err := getRandomEntries(gachaEntries, rolls, true)
rewardEntries, err := getRandomEntries(entries, rolls, true)
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 {
continue
}
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() {
items.StructScan(&reward)
rewards = append(rewards, reward)
temp.WriteUint8(reward.ItemType)
temp.WriteUint16(reward.ItemID)
temp.WriteUint16(reward.Quantity)
temp.WriteUint8(0)
err = items.StructScan(&reward)
if err == nil {
rewards = append(rewards, reward)
}
}
}
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())
addGachaItem(s, rewards)
}
Expand Down

0 comments on commit ab6c86c

Please sign in to comment.