Road Shop Rotation

Added Road Shop inventory's weekly dynamic rotation.

Thank you everyone who helped with this!
This commit is contained in:
Malckyor
2022-06-15 07:58:28 +09:00
committed by GitHub
parent 9c6950d200
commit 2d7f55600f
2 changed files with 80 additions and 9 deletions

View File

@@ -0,0 +1,39 @@
BEGIN;
CREATE TABLE IF NOT EXISTS public.normal_shop_items
(
shoptype integer,
shopid integer,
itemhash integer not null,
itemid integer,
points integer,
tradequantity integer,
rankreqlow integer,
rankreqhigh integer,
rankreqg integer,
storelevelreq integer,
maximumquantity integer,
boughtquantity integer,
roadfloorsrequired integer,
weeklyfataliskills integer,
enable_weeks character varying(8)
);
ALTER TABLE IF EXISTS public.normal_shop_items
(
ADD COLUMN enable_weeks character varying(8)
);
CREATE TABLE IF NOT EXISTS public.shop_item_state
(
char_id bigint REFERENCES characters (id),
itemhash int UNIQUE NOT NULL,
usedquantity int,
week int
);
ALTER TABLE IF EXISTS public.shop_item_state
(
ADD COLUMN week int
);
END;

View File

@@ -2,16 +2,28 @@ package channelserver
import ( import (
"encoding/hex" "encoding/hex"
"fmt"
"strings"
"time" "time"
//"github.com/Solenataris/Erupe/common/stringsupport" //"github.com/Solenataris/Erupe/common/stringsupport"
"github.com/Solenataris/Erupe/network/mhfpacket"
"github.com/Andoryuuta/byteframe" "github.com/Andoryuuta/byteframe"
"github.com/Solenataris/Erupe/network/mhfpacket"
"github.com/lib/pq" "github.com/lib/pq"
"github.com/sachaos/lottery" "github.com/sachaos/lottery"
"go.uber.org/zap" "go.uber.org/zap"
) )
func contains(s []string, str string) bool {
for _, v := range s {
if v == str {
return true
}
}
return false
}
func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateShop) pkt := p.(*mhfpacket.MsgMhfEnumerateShop)
// SHOP TYPES: // SHOP TYPES:
@@ -149,20 +161,28 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
} else { } else {
shopEntries, err := s.server.db.Query("SELECT itemhash,itemID,Points,TradeQuantity,rankReqLow,rankReqHigh,rankReqG,storeLevelReq,maximumQuantity,boughtQuantity,roadFloorsRequired,weeklyFatalisKills FROM normal_shop_items WHERE shoptype=$1 AND shopid=$2", pkt.ShopType, pkt.ShopID) _, week := time.Now().ISOWeek()
season := fmt.Sprintf("%d", week%4)
shopEntries, err := s.server.db.Query("SELECT itemhash,itemID,Points,TradeQuantity,rankReqLow,rankReqHigh,rankReqG,storeLevelReq,maximumQuantity,boughtQuantity,roadFloorsRequired,weeklyFatalisKills, COALESCE(enable_weeks, '') FROM normal_shop_items WHERE shoptype=$1 AND shopid=$2", pkt.ShopType, pkt.ShopID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
var ItemHash, entryCount int var ItemHash, entryCount int
var itemID, Points, TradeQuantity, rankReqLow, rankReqHigh, rankReqG, storeLevelReq, maximumQuantity, boughtQuantity, roadFloorsRequired, weeklyFatalisKills, charQuantity uint16 var itemID, Points, TradeQuantity, rankReqLow, rankReqHigh, rankReqG, storeLevelReq, maximumQuantity, boughtQuantity, roadFloorsRequired, weeklyFatalisKills, charQuantity uint16
var itemWeeks string
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(0) // total defs resp.WriteUint32(0) // total defs
for shopEntries.Next() { for shopEntries.Next() {
err = shopEntries.Scan(&ItemHash, &itemID, &Points, &TradeQuantity, &rankReqLow, &rankReqHigh, &rankReqG, &storeLevelReq, &maximumQuantity, &boughtQuantity, &roadFloorsRequired, &weeklyFatalisKills) err = shopEntries.Scan(&ItemHash, &itemID, &Points, &TradeQuantity, &rankReqLow, &rankReqHigh, &rankReqG, &storeLevelReq, &maximumQuantity, &boughtQuantity, &roadFloorsRequired, &weeklyFatalisKills, &itemWeeks)
if err != nil { if err != nil {
panic(err) panic(err)
} }
if len(itemWeeks) > 0 && !contains(strings.Split(itemWeeks, ","), season) {
continue
}
resp.WriteUint32(uint32(ItemHash)) resp.WriteUint32(uint32(ItemHash))
resp.WriteUint16(0) // unk, always 0 in existing packets resp.WriteUint16(0) // unk, always 0 in existing packets
resp.WriteUint16(itemID) resp.WriteUint16(itemID)
@@ -175,9 +195,13 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint16(storeLevelReq) resp.WriteUint16(storeLevelReq)
resp.WriteUint16(maximumQuantity) resp.WriteUint16(maximumQuantity)
if maximumQuantity > 0 { if maximumQuantity > 0 {
err = s.server.db.QueryRow("SELECT COALESCE(usedquantity,0) FROM shop_item_state WHERE itemhash=$1 AND char_id=$2", ItemHash, s.charID).Scan(&charQuantity) var itemWeek int
err = s.server.db.QueryRow("SELECT COALESCE(usedquantity,0), COALESCE(week,-1) FROM shop_item_state WHERE itemhash=$1 AND char_id=$2", ItemHash, s.charID).Scan(&charQuantity, &itemWeek)
if err != nil { if err != nil {
resp.WriteUint16(0) resp.WriteUint16(0)
} else if pkt.ShopID == 7 && itemWeek >= 0 && itemWeek != week {
clearShopItemState(s, s.charID, uint32(ItemHash))
resp.WriteUint16(0)
} else { } else {
resp.WriteUint16(charQuantity) resp.WriteUint16(charQuantity)
} }
@@ -200,6 +224,7 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
} }
func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) {
_, week := time.Now().ISOWeek()
// writing out to an editable shop enumeration // writing out to an editable shop enumeration
pkt := p.(*mhfpacket.MsgMhfAcquireExchangeShop) pkt := p.(*mhfpacket.MsgMhfAcquireExchangeShop)
if pkt.DataSize == 10 { if pkt.DataSize == 10 {
@@ -207,10 +232,10 @@ func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) {
_ = bf.ReadUint16() // unk, always 1 in examples _ = bf.ReadUint16() // unk, always 1 in examples
itemHash := bf.ReadUint32() itemHash := bf.ReadUint32()
buyCount := bf.ReadUint32() buyCount := bf.ReadUint32()
_, err := s.server.db.Exec(`INSERT INTO shop_item_state (char_id, itemhash, usedquantity) _, err := s.server.db.Exec(`INSERT INTO shop_item_state (char_id, itemhash, usedquantity, week)
VALUES ($1,$2,$3) ON CONFLICT (char_id, itemhash) VALUES ($1,$2,$3,$4) ON CONFLICT (char_id, itemhash)
DO UPDATE SET usedquantity = shop_item_state.usedquantity + $3 DO UPDATE SET usedquantity = shop_item_state.usedquantity + $3
WHERE EXCLUDED.char_id=$1 AND EXCLUDED.itemhash=$2`, s.charID, itemHash, buyCount) WHERE EXCLUDED.char_id=$1 AND EXCLUDED.itemhash=$2`, s.charID, itemHash, buyCount, week)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update shop_item_state in db", zap.Error(err)) s.logger.Fatal("Failed to update shop_item_state in db", zap.Error(err))
} }
@@ -218,6 +243,13 @@ func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func clearShopItemState(s *Session, charId uint32, itemHash uint32) {
_, err := s.server.db.Exec(`DELETE FROM shop_item_state WHERE char_id=$1 AND itemhash=$2`, charId, itemHash)
if err != nil {
s.logger.Fatal("Failed to delete shop_item_state in db", zap.Error(err))
}
}
func handleMsgMhfGetGachaPlayHistory(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetGachaPlayHistory(s *Session, p mhfpacket.MHFPacket) {
// returns number of times the gacha was played, will need persistent db stuff // returns number of times the gacha was played, will need persistent db stuff
pkt := p.(*mhfpacket.MsgMhfGetGachaPlayHistory) pkt := p.(*mhfpacket.MsgMhfGetGachaPlayHistory)
@@ -703,4 +735,4 @@ func handleMsgMhfResetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {
panic(err) panic(err)
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }