diff --git a/network/mhfpacket/msg_mhf_get_achievement.go b/network/mhfpacket/msg_mhf_get_achievement.go index 4b41ce72b..afa49d0d4 100644 --- a/network/mhfpacket/msg_mhf_get_achievement.go +++ b/network/mhfpacket/msg_mhf_get_achievement.go @@ -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 } diff --git a/patch-schema/achievements.sql b/patch-schema/achievements.sql index 5c24f9e89..333ae5ed6 100644 --- a/patch-schema/achievements.sql +++ b/patch-schema/achievements.sql @@ -2,7 +2,7 @@ BEGIN; CREATE TABLE IF NOT EXISTS public.achievements ( - id int NOT NULL, + id int NOT NULL PRIMARY KEY , ach0 int DEFAULT 0, ach1 int DEFAULT 0, ach2 int DEFAULT 0, diff --git a/server/channelserver/handlers_achievement.go b/server/channelserver/handlers_achievement.go index b9197f6ea..a7628ed8f 100644 --- a/server/channelserver/handlers_achievement.go +++ b/server/channelserver/handlers_achievement.go @@ -3,24 +3,23 @@ package channelserver import ( "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" + "fmt" + "go.uber.org/zap" + "io" ) -var achievementCurves = [][]uint32{ +var achievementCurves = [][]int32{ // 0: HR weapon use, Class use, Tore dailies - {5, 15, 30, 50, 100, 150, 200, 250, 300}, + {5, 15, 30, 50, 100, 150, 200, 300}, // 1: Weapon collector, G wep enhances - {1, 3, 5, 15, 30, 50, 75, 100, 150}, + {1, 3, 5, 15, 30, 50, 75, 100}, // 2: Festa wins - {1, 2, 3, 4, 5, 6, 7, 8, 9}, - // 3: GR weapon use - {10, 50, 100, 200, 350, 500, 750, 1000, 1500}, - // 4: Armor refinement - {0, 5, 5, 5, 5, 5, 5, 5, 5}, - // 5: Sigil crafts - {0, 50, 50, 50, 50, 50, 50, 50, 50}, + {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][]uint32{ +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], @@ -28,52 +27,119 @@ var achievementCurveMap = map[uint8][]uint32{ 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[4], 29: achievementCurves[5], 30: achievementCurves[3], 31: achievementCurves[3], + 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) - err := s.server.db.QueryRow("SELECT id FROM achievements WHERE id=$1", s.charID) - if err != nil { - s.server.db.Exec("INSERT INTO achievements (id) VALUES ($1)", s.charID) + 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) } - scores := make([]int, 33) - s.server.db.QueryRow("SELECT * FROM achievements WHERE id=$1", s.charID).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]) + 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() - points := uint32(69) - resp.WriteUint32(points) - resp.WriteUint32(points) - resp.WriteUint32(points) - resp.WriteUint32(points) - resp.WriteBytes([]byte{0x02, 0x00, 0x00}) + var points uint32 + resp.WriteBytes(make([]byte, 16)) + resp.WriteBytes([]byte{0x02, 0x00, 0x00}) // Unk - entries := 34 - resp.WriteUint8(uint8(entries)) // Entry count - for i := 0; i < entries; i++ { - resp.WriteUint8(uint8(i)) // achievement id - resp.WriteUint8(uint8(i)) // level - resp.WriteUint16(20) // point value - resp.WriteUint32(100) // required - resp.WriteUint8(0) - if i < 10 { - resp.WriteUint16(0x7FFF) - } else if i < 20 { - resp.WriteUint16(0x3FFF) - } else { - resp.WriteUint16(0x1FFF) - } - //resp.WriteUint16(0x7F7F) // unk - resp.WriteUint8(0) - resp.WriteUint32(100) // progress + 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) // level increased notification + 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()) } @@ -84,7 +150,10 @@ 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) {}