Merge pull request #19 from ZeruLight/feature/achievements

feature/achievements
This commit is contained in:
wish
2022-08-08 05:06:40 +10:00
committed by GitHub
3 changed files with 186 additions and 83 deletions

View File

@@ -1,18 +1,18 @@
package mhfpacket
import (
"errors"
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
// MsgMhfGetAchievement represents the MSG_MHF_GET_ACHIEVEMENT
type MsgMhfGetAchievement struct{
AckHandle uint32
Unk0 uint32 // id?
Unk1 uint32 // char?
type MsgMhfGetAchievement struct {
AckHandle uint32
CharID uint32
Unk1 uint32 // char?
}
// Opcode returns the ID associated with this packet type.
@@ -22,8 +22,8 @@ func (m *MsgMhfGetAchievement) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfGetAchievement) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint32()
m.AckHandle = bf.ReadUint32()
m.CharID = bf.ReadUint32()
m.Unk1 = bf.ReadUint32()
return nil
}

View File

@@ -0,0 +1,41 @@
BEGIN;
CREATE TABLE IF NOT EXISTS public.achievements
(
id int NOT NULL PRIMARY KEY ,
ach0 int DEFAULT 0,
ach1 int DEFAULT 0,
ach2 int DEFAULT 0,
ach3 int DEFAULT 0,
ach4 int DEFAULT 0,
ach5 int DEFAULT 0,
ach6 int DEFAULT 0,
ach7 int DEFAULT 0,
ach8 int DEFAULT 0,
ach9 int DEFAULT 0,
ach10 int DEFAULT 0,
ach11 int DEFAULT 0,
ach12 int DEFAULT 0,
ach13 int DEFAULT 0,
ach14 int DEFAULT 0,
ach15 int DEFAULT 0,
ach16 int DEFAULT 0,
ach17 int DEFAULT 0,
ach18 int DEFAULT 0,
ach19 int DEFAULT 0,
ach20 int DEFAULT 0,
ach21 int DEFAULT 0,
ach22 int DEFAULT 0,
ach23 int DEFAULT 0,
ach24 int DEFAULT 0,
ach25 int DEFAULT 0,
ach26 int DEFAULT 0,
ach27 int DEFAULT 0,
ach28 int DEFAULT 0,
ach29 int DEFAULT 0,
ach30 int DEFAULT 0,
ach31 int DEFAULT 0,
ach32 int DEFAULT 0
);
END;

View File

@@ -3,86 +3,143 @@ package channelserver
import (
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket"
"fmt"
"go.uber.org/zap"
"io"
)
var achievementCurves = [][]int32{
// 0: HR weapon use, Class use, Tore dailies
{5, 15, 30, 50, 100, 150, 200, 300},
// 1: Weapon collector, G wep enhances
{1, 5, 10, 15, 30, 50, 75, 100},
// 2: Festa wins
{1, 2, 3, 4, 5, 6, 7, 8},
// 3: GR weapon use, Sigil crafts
{10, 50, 100, 200, 350, 500, 750, 999},
}
var achievementCurveMap = map[uint8][]int32{
0: achievementCurves[0], 1: achievementCurves[0], 2: achievementCurves[0], 3: achievementCurves[0],
4: achievementCurves[0], 5: achievementCurves[0], 6: achievementCurves[0], 7: achievementCurves[1],
8: achievementCurves[2], 9: achievementCurves[0], 10: achievementCurves[0], 11: achievementCurves[0],
12: achievementCurves[0], 13: achievementCurves[0], 14: achievementCurves[0], 15: achievementCurves[0],
16: achievementCurves[3], 17: achievementCurves[3], 18: achievementCurves[3], 19: achievementCurves[3],
20: achievementCurves[3], 21: achievementCurves[3], 22: achievementCurves[3], 23: achievementCurves[3],
24: achievementCurves[3], 25: achievementCurves[3], 26: achievementCurves[3], 27: achievementCurves[1],
28: achievementCurves[1], 29: achievementCurves[3], 30: achievementCurves[3], 31: achievementCurves[3],
32: achievementCurves[3],
}
type Achievement struct {
Level uint8
Value uint32
NextValue uint16
Required uint32
Updated bool
Progress uint32
Trophy uint8
}
func GetAchData(id uint8, score int32) Achievement {
curve := achievementCurveMap[id]
var ach Achievement
for i, v := range curve {
temp := score - v
if temp < 0 {
ach.Progress = uint32(score)
ach.Required = uint32(curve[i])
switch ach.Level {
case 0:
ach.NextValue = 5
case 1, 2, 3:
ach.NextValue = 10
case 4, 5:
ach.NextValue = 15
case 6:
ach.NextValue = 15
ach.Trophy = 0x40
case 7:
ach.NextValue = 20
ach.Trophy = 0x60
}
return ach
} else {
score = temp
ach.Level++
switch ach.Level {
case 1:
ach.Value += 5
case 2, 3, 4:
ach.Value += 10
case 5, 6, 7:
ach.Value += 15
case 8:
ach.Value += 20
}
}
}
ach.Required = uint32(curve[7])
ach.Trophy = 0x7F
ach.Progress = ach.Required
return ach
}
func handleMsgMhfGetAchievement(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetAchievement)
achievementStruct := []struct {
ID uint8 // Main ID
Unk0 uint8 // always FF
Unk1 uint16 // 0x05 0x00
Unk2 uint32 // 0x01 0x0A 0x05 0x00
}{
{ID: 0, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 1, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 2, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 3, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 4, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 5, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 6, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 7, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 8, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 9, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 10, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 11, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 12, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 13, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 14, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 15, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 16, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 17, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 18, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 19, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 20, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 21, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 22, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 23, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 24, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 25, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 26, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 27, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 28, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 29, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 30, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 31, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 32, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 33, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 34, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 35, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 36, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 37, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 38, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 39, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 40, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 41, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 42, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 43, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 44, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 45, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 46, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 47, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 48, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 49, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 50, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 51, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 52, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 53, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 54, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 55, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 56, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 57, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 58, Unk0: 0xFF, Unk1: 0, Unk2: 0},
{ID: 59, Unk0: 0xFF, Unk1: 0, Unk2: 0},
row := s.server.db.QueryRow("SELECT id FROM achievements WHERE id=$1", pkt.CharID)
if row != nil {
s.server.db.Exec("INSERT INTO achievements (id) VALUES ($1)", pkt.CharID)
}
var scores [33]int32
row = s.server.db.QueryRow("SELECT * FROM achievements WHERE id=$1", pkt.CharID)
if row != nil {
err := row.Scan(&scores[0], &scores[0],
&scores[1], &scores[2], &scores[3], &scores[4], &scores[5], &scores[6], &scores[7], &scores[8], &scores[9],
&scores[10], &scores[11], &scores[12], &scores[13], &scores[14], &scores[15], &scores[16], &scores[17],
&scores[18], &scores[19], &scores[20], &scores[21], &scores[22], &scores[23], &scores[24], &scores[25],
&scores[26], &scores[27], &scores[28], &scores[29], &scores[30], &scores[31], &scores[32])
if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 20))
s.logger.Error("ERR@", zap.Error(err))
return
}
}
resp := byteframe.NewByteFrame()
resp.WriteUint8(uint8(len(achievementStruct))) // Entry count
for _, entry := range achievementStruct {
resp.WriteUint8(entry.ID)
resp.WriteUint8(entry.Unk0)
resp.WriteUint16(entry.Unk1)
resp.WriteUint32(entry.Unk2)
var points uint32
resp.WriteBytes(make([]byte, 16))
resp.WriteBytes([]byte{0x02, 0x00, 0x00}) // Unk
var id uint8
entries := uint8(33)
resp.WriteUint8(entries) // Entry count
for id = 0; id < entries; id++ {
achData := GetAchData(id, scores[id])
points += achData.Value
resp.WriteUint8(id)
resp.WriteUint8(achData.Level)
resp.WriteUint16(achData.NextValue)
resp.WriteUint32(achData.Required)
resp.WriteBool(false) // TODO: Notify on rank increase since last checked, see MhfDisplayedAchievement
resp.WriteUint8(achData.Trophy)
/* Trophy bitfield
0000 0000
abcd efgh
B - Bronze (0x40)
B-C - Silver (0x60)
B-H - Gold (0x7F)
*/
resp.WriteUint16(0) // Unk
resp.WriteUint32(achData.Progress)
}
resp.Seek(0, io.SeekStart)
resp.WriteUint32(points)
resp.WriteUint32(points)
resp.WriteUint32(points)
resp.WriteUint32(points)
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
}
@@ -93,11 +150,16 @@ func handleMsgMhfSetCaAchievementHist(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfResetAchievement(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfAddAchievement(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfAddAchievement(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAddAchievement)
s.server.db.Exec(fmt.Sprintf("UPDATE achievements SET ach%d=ach%d+1 WHERE id=$1", pkt.AchievementID, pkt.AchievementID), s.charID)
}
func handleMsgMhfPaymentAchievement(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfDisplayedAchievement(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfDisplayedAchievement(s *Session, p mhfpacket.MHFPacket) {
// This is how you would figure out if the rank-up notification needs to occur
}
func handleMsgMhfGetCaAchievementHist(s *Session, p mhfpacket.MHFPacket) {}