road leaderboard initial implementation

This commit is contained in:
wish
2022-08-19 03:53:28 +10:00
parent 56ae30745d
commit 1ba3d55566
3 changed files with 216 additions and 16 deletions

View File

@@ -1,19 +1,19 @@
package mhfpacket package mhfpacket
import ( import (
"errors" "errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
) )
// MsgMhfEnumerateRengokuRanking represents the MSG_MHF_ENUMERATE_RENGOKU_RANKING // MsgMhfEnumerateRengokuRanking represents the MSG_MHF_ENUMERATE_RENGOKU_RANKING
type MsgMhfEnumerateRengokuRanking struct { type MsgMhfEnumerateRengokuRanking struct {
AckHandle uint32 AckHandle uint32
Unk0 uint32 Leaderboard uint32
Unk1 uint16 // Hardcoded 0 in the binary Unk1 uint16 // Hardcoded 0 in the binary
Unk2 uint16 // Hardcoded 00 01 in the binary Unk2 uint16 // Hardcoded 00 01 in the binary
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -24,7 +24,7 @@ func (m *MsgMhfEnumerateRengokuRanking) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfEnumerateRengokuRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfEnumerateRengokuRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint32() m.Leaderboard = bf.ReadUint32()
m.Unk1 = bf.ReadUint16() m.Unk1 = bf.ReadUint16()
m.Unk2 = bf.ReadUint16() m.Unk2 = bf.ReadUint16()
return nil return nil

View File

@@ -0,0 +1,11 @@
BEGIN;
CREATE TABLE IF NOT EXISTS rengoku_score (
character_id integer PRIMARY KEY,
max_stages_mp integer,
max_points_mp integer,
max_stages_sp integer,
max_points_sp integer
);
END;

View File

@@ -1,6 +1,8 @@
package channelserver package channelserver
import ( import (
ps "erupe-ce/common/pascalstring"
"fmt"
"io/ioutil" "io/ioutil"
"path/filepath" "path/filepath"
@@ -17,7 +19,19 @@ func handleMsgMhfSaveRengokuData(s *Session, p mhfpacket.MHFPacket) {
if err != nil { if err != nil {
s.logger.Fatal("Failed to update rengokudata savedata in db", zap.Error(err)) s.logger.Fatal("Failed to update rengokudata savedata in db", zap.Error(err))
} }
bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
bf.Seek(71, 0)
maxStageMp := bf.ReadUint32()
maxScoreMp := bf.ReadUint32()
bf.Seek(4, 1)
maxStageSp := bf.ReadUint32()
maxScoreSp := bf.ReadUint32()
var t int
err = s.server.db.QueryRow("SELECT character_id FROM rengoku_score WHERE character_id=$1", s.charID).Scan(&t)
if err != nil {
s.server.db.Exec("INSERT INTO rengoku_score (character_id) VALUES ($1)", s.charID)
}
s.server.db.Exec("UPDATE rengoku_score SET max_stages_mp=$1, max_points_mp=$2, max_stages_sp=$3, max_points_sp=$4 WHERE character_id=$5", maxStageMp, maxScoreMp, maxStageSp, maxScoreSp, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
@@ -81,16 +95,191 @@ func handleMsgMhfGetRengokuBinary(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, data) doAckBufSucceed(s, pkt.AckHandle, data)
} }
const rengokuScoreQuery = `
SELECT max_stages_mp, max_points_mp, max_stages_sp, max_points_sp, c.name, gc.guild_id
FROM rengoku_score rs
LEFT JOIN characters c ON c.id = rs.character_id
LEFT JOIN guild_characters gc ON gc.character_id = rs.character_id
`
type RengokuScore struct {
Name string `db:"name"`
GuildID int `db:"guild_id"`
MaxStagesMP uint32 `db:"max_stages_mp"`
MaxPointsMP uint32 `db:"max_points_mp"`
MaxStagesSP uint32 `db:"max_stages_sp"`
MaxPointsSP uint32 `db:"max_points_sp"`
}
func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateRengokuRanking) pkt := p.(*mhfpacket.MsgMhfEnumerateRengokuRanking)
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
isApplicant, _ := guild.HasApplicationForCharID(s, s.charID)
if isApplicant {
guild = nil
}
var score RengokuScore
i := uint32(1)
bf := byteframe.NewByteFrame()
scoreData := byteframe.NewByteFrame()
switch pkt.Leaderboard {
case 0: // Max stage overall MP
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_stages_mp DESC", rengokuScoreQuery))
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxStagesMP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxStagesMP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
case 1: // Max RdP overall MP
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_points_mp DESC", rengokuScoreQuery))
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxPointsMP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxPointsMP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
case 2: // Max stage guild MP
if guild != nil {
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_stages_mp DESC", rengokuScoreQuery), guild.ID)
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxStagesMP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxStagesMP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
} else {
bf.WriteBytes(make([]byte, 11))
}
case 3: // Max RdP guild MP
if guild != nil {
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_points_mp DESC", rengokuScoreQuery), guild.ID)
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxPointsMP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxPointsMP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
} else {
bf.WriteBytes(make([]byte, 11))
}
case 4: // Max stage overall SP
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_stages_sp DESC", rengokuScoreQuery))
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxStagesSP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxStagesSP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
case 5: // Max RdP overall SP
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_points_sp DESC", rengokuScoreQuery))
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxPointsSP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxPointsSP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
case 6: // Max stage guild SP
if guild != nil {
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_stages_sp DESC", rengokuScoreQuery), guild.ID)
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxStagesSP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxStagesSP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
} else {
bf.WriteBytes(make([]byte, 11))
}
case 7: // Max RdP guild SP
if guild != nil {
rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_points_sp DESC", rengokuScoreQuery), guild.ID)
for rows.Next() {
rows.StructScan(&score)
if score.Name == s.Name {
bf.WriteUint32(i)
bf.WriteUint32(score.MaxPointsSP)
ps.Uint8(bf, s.Name, true)
ps.Uint8(bf, "", false)
}
scoreData.WriteUint32(i)
scoreData.WriteUint32(score.MaxPointsSP)
ps.Uint8(scoreData, score.Name, true)
ps.Uint8(scoreData, "", false)
i++
}
} else {
bf.WriteBytes(make([]byte, 11))
}
}
bf.WriteUint8(uint8(i) - 1)
bf.WriteBytes(scoreData.Data())
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetRengokuRankingRank(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetRengokuRankingRank(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetRengokuRankingRank) pkt := p.(*mhfpacket.MsgMhfGetRengokuRankingRank)
// What is this for?
resp := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
resp.WriteBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) bf.WriteUint32(0) // Max stage overall MP rank
bf.WriteUint32(0) // Max RdP overall MP rank
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }