From 9c772a09fcc347e92ea3b01995417159eb9b801b Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 27 Jul 2022 21:05:57 +1000 Subject: [PATCH 1/4] initial festa build --- Erupe/config.json | 2 +- Erupe/festa.sql | 164 +++++++++++++ Erupe/server/channelserver/handlers_festa.go | 220 +++++++++++++----- Erupe/server/channelserver/handlers_guild.go | 20 +- .../channelserver/handlers_guild_member.go | 51 ++-- 5 files changed, 364 insertions(+), 93 deletions(-) create mode 100644 Erupe/festa.sql diff --git a/Erupe/config.json b/Erupe/config.json index eb59db613..b3be9512f 100644 --- a/Erupe/config.json +++ b/Erupe/config.json @@ -11,7 +11,7 @@ "MaxHexdumpLength": 256, "Event": 0, "DivaEvent": 0, - "FestaEvent": 0, + "FestaEvent": -1, "TournamentEvent": 0, "MezFesEvent": true, "SaveDumps": { diff --git a/Erupe/festa.sql b/Erupe/festa.sql new file mode 100644 index 000000000..da56e8c89 --- /dev/null +++ b/Erupe/festa.sql @@ -0,0 +1,164 @@ +BEGIN; + +CREATE TYPE event_type AS ENUM ('festa', 'diva', 'vs', 'mezfes'); + +DROP TABLE IF EXISTS public.event_week; + +ALTER TABLE IF EXISTS public.guild_characters + ADD COLUMN IF NOT EXISTS souls int DEFAULT 0; + +ALTER TABLE IF EXISTS public.guilds + DROP COLUMN IF EXISTS festival_colour; + +CREATE TABLE IF NOT EXISTS public.events +( + id serial NOT NULL PRIMARY KEY, + event_type event_type NOT NULL, + start_time timestamp without time zone NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS public.festa_registrations +( + guild_id int NOT NULL, + team festival_colour NOT NULL +); + +CREATE TABLE IF NOT EXISTS public.festa_trials +( + id serial NOT NULL PRIMARY KEY, + objective int NOT NULL, + goal_id int NOT NULL, + times_req int NOT NULL, + locale_req int NOT NULL DEFAULT 0, + reward int NOT NULL +); + +-- Ripped trials +INSERT INTO public.festa_trials + (objective, goal_id, times_req, locale_req, reward) +VALUES + (1,27,1,0,1), + (5,53034,0,0,400), + (5,22042,0,0,89), + (5,23397,0,0,89), + (1,28,1,0,1), + (1,68,1,0,1), + (1,6,1,0,2), + (1,38,1,0,2), + (1,20,1,0,3), + (1,39,1,0,4), + (1,48,1,0,4), + (1,67,1,0,4), + (1,93,1,0,4), + (1,22,1,0,5), + (1,52,1,0,5), + (1,101,1,0,5), + (1,1,1,0,5), + (1,37,1,0,5), + (1,15,1,0,5), + (1,45,1,0,5), + (1,74,1,0,5), + (1,78,1,0,5), + (1,103,1,0,5), + (1,51,1,0,6), + (1,17,1,0,6), + (1,21,1,0,6), + (1,92,1,0,6), + (1,47,1,0,7), + (1,46,1,0,7), + (1,26,1,0,7), + (1,14,1,0,7), + (1,11,1,0,7), + (1,44,1,0,8), + (1,43,1,0,8), + (1,49,1,0,8), + (1,40,1,0,8), + (1,76,1,0,8), + (1,89,1,0,8), + (1,94,1,0,8), + (1,96,1,0,8), + (1,75,1,0,8), + (1,91,1,0,8), + (1,53,1,0,9), + (1,80,1,0,9), + (1,42,1,0,9), + (1,79,1,0,9), + (1,81,1,0,10), + (1,41,1,0,10), + (1,82,1,0,10), + (1,90,1,0,10), + (1,149,1,0,10), + (1,85,1,0,11), + (1,95,1,0,11), + (1,121,1,0,11), + (1,142,1,0,11), + (1,141,1,0,11), + (1,146,1,0,12), + (1,147,1,0,12), + (1,148,1,0,12), + (1,151,1,0,12), + (1,152,1,0,12), + (1,159,1,0,12), + (1,153,1,0,12), + (1,162,1,0,12), + (1,111,1,0,13), + (1,110,1,0,13), + (1,112,1,0,13), + (1,109,1,0,14), + (1,169,1,0,15), + (2,33,1,0,6), + (2,104,1,0,8), + (2,119,1,0,8), + (2,120,1,0,8), + (2,54,1,0,8), + (2,59,1,0,8), + (2,64,1,0,8), + (2,65,1,0,8), + (2,99,1,0,9), + (2,83,1,0,9), + (2,84,1,0,10), + (2,77,1,0,10), + (2,106,1,0,10), + (2,55,1,0,10), + (2,58,1,0,10), + (2,7,1,0,10), + (2,50,1,0,11), + (2,131,1,0,11), + (2,129,1,0,11), + (2,140,1,0,11), + (2,122,1,0,11), + (2,126,1,0,11), + (2,127,1,0,11), + (2,128,1,0,11), + (2,130,1,0,11), + (2,139,1,0,11), + (2,144,1,0,11), + (2,150,1,0,11), + (2,158,1,0,11), + (2,164,1,0,15), + (2,165,1,0,15), + (2,2,1,7,15), + (2,36,1,0,15), + (2,71,1,0,15), + (2,108,1,0,15), + (2,116,1,0,15), + (2,107,1,0,15), + (2,154,1,0,17), + (2,166,1,0,17), + (2,170,1,0,18), + (3,31,1,0,1), + (3,8,1,0,3), + (3,123,1,0,8), + (3,105,1,0,9), + (3,125,1,0,11), + (3,115,1,0,12), + (3,114,1,0,12), + (3,161,1,0,12), + (4,670,1,0,1), + (4,671,1,0,1), + (4,672,1,0,1), + (4,675,1,0,1), + (4,673,1,0,1), + (4,674,1,0,1); + +END; \ No newline at end of file diff --git a/Erupe/server/channelserver/handlers_festa.go b/Erupe/server/channelserver/handlers_festa.go index c1f3cecfb..3c39f9999 100644 --- a/Erupe/server/channelserver/handlers_festa.go +++ b/Erupe/server/channelserver/handlers_festa.go @@ -2,12 +2,11 @@ package channelserver import ( "encoding/hex" - "math/rand" - "time" - "erupe-ce/common/byteframe" ps "erupe-ce/common/pascalstring" "erupe-ce/network/mhfpacket" + "math/rand" + "time" ) func handleMsgMhfSaveMezfesData(s *Session, p mhfpacket.MHFPacket) { @@ -69,65 +68,129 @@ func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) { doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } +func cleanupFesta(s *Session) { + s.server.db.Exec("DELETE FROM events WHERE event_type='festa'") + s.server.db.Exec("DELETE FROM festa_registrations") + s.server.db.Exec("UPDATE guild_characters SET souls=0") +} + +func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 { + timestamps := make([]uint32, 5) + midnight := Time_Current_Midnight() + if debug && start <= 3 { + switch start { + case 1: + timestamps[0] = uint32(midnight.Unix()) + timestamps[1] = uint32(midnight.Add(24 * 7 * time.Hour).Unix()) + timestamps[2] = uint32(midnight.Add(24 * 14 * time.Hour).Unix()) + timestamps[3] = uint32(midnight.Add(24*14*time.Hour + 150*time.Minute).Unix()) + timestamps[4] = uint32(midnight.Add(24*28*time.Hour + 11*time.Hour).Unix()) + case 2: + timestamps[0] = uint32(midnight.Add(-24 * 7 * time.Hour).Unix()) + timestamps[1] = uint32(midnight.Unix()) + timestamps[2] = uint32(midnight.Add(24 * 7 * time.Hour).Unix()) + timestamps[3] = uint32(midnight.Add(24*7*time.Hour + 150*time.Minute).Unix()) + timestamps[4] = uint32(midnight.Add(24 * 21 * time.Hour).Add(11 * time.Hour).Unix()) + case 3: + timestamps[0] = uint32(midnight.Add(-24 * 14 * time.Hour).Unix()) + timestamps[1] = uint32(midnight.Add(-24*7*time.Hour + 11*time.Hour).Unix()) + timestamps[2] = uint32(midnight.Unix()) + timestamps[3] = uint32(midnight.Add(150 * time.Minute).Unix()) + timestamps[4] = uint32(midnight.Add(24*14*time.Hour + 11*time.Hour).Unix()) + } + return timestamps + } + if start == 0 || Time_Current_Adjusted().Unix() > int64(start)+2977200 { + cleanupFesta(s) + // Generate a new festa, starting midnight tomorrow + start = uint32(midnight.Add(24 * time.Hour).Unix()) + s.server.db.Exec("INSERT INTO events (event_type, start_time) VALUES ('festa', to_timestamp($1)::timestamp without time zone)", start) + } + timestamps[0] = start + timestamps[1] = timestamps[0] + 604800 + timestamps[2] = timestamps[1] + 604800 + timestamps[3] = timestamps[2] + 9000 + timestamps[4] = timestamps[3] + 1240200 + return timestamps +} + +type Trial struct { + ID uint32 `db:"id"` + Objective uint8 `db:"objective"` + GoalID uint32 `db:"goal_id"` + TimesReq uint16 `db:"times_req"` + Locale uint16 `db:"locale_req"` + Reward uint16 `db:"reward"` +} + func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfInfoFesta) bf := byteframe.NewByteFrame() - state := s.server.erupeConfig.DevModeOptions.FestaEvent - bf.WriteUint32(0xdeadbeef) // festaID - // Registration Week Start - // Introductory Week Start - // Totalling Time - // Reward Festival Start (2.5hrs after totalling) - // 2 weeks after RewardFes (next fes?) - midnight := Time_Current_Midnight() - switch state { - case 1: - bf.WriteUint32(uint32(midnight.Unix())) - bf.WriteUint32(uint32(midnight.Add(24 * 7 * time.Hour).Unix())) - bf.WriteUint32(uint32(midnight.Add(24 * 14 * time.Hour).Unix())) - bf.WriteUint32(uint32(midnight.Add(24*14*time.Hour + 150*time.Minute).Unix())) - bf.WriteUint32(uint32(midnight.Add(24*28*time.Hour + 11*time.Hour).Unix())) - case 2: - bf.WriteUint32(uint32(midnight.Add(-24 * 7 * time.Hour).Unix())) - bf.WriteUint32(uint32(midnight.Unix())) - bf.WriteUint32(uint32(midnight.Add(24 * 7 * time.Hour).Unix())) - bf.WriteUint32(uint32(midnight.Add(24*7*time.Hour + 150*time.Minute).Unix())) - bf.WriteUint32(uint32(midnight.Add(24 * 21 * time.Hour).Add(11 * time.Hour).Unix())) - case 3: - bf.WriteUint32(uint32(midnight.Add(-24 * 14 * time.Hour).Unix())) - bf.WriteUint32(uint32(midnight.Add(-24*7*time.Hour + 11*time.Hour).Unix())) - bf.WriteUint32(uint32(midnight.Unix())) - bf.WriteUint32(uint32(midnight.Add(150 * time.Minute).Unix())) - bf.WriteUint32(uint32(midnight.Add(24*14*time.Hour + 11*time.Hour).Unix())) - default: + + id, start := uint32(0xDEADBEEF), uint32(0) + rows, _ := s.server.db.Queryx("SELECT id, (EXTRACT(epoch FROM start_time)::int) as start_time FROM events WHERE event_type='festa'") + for rows.Next() { + rows.Scan(&id, &start) + } + + var timestamps []uint32 + if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.FestaEvent >= 0 { + if s.server.erupeConfig.DevModeOptions.FestaEvent == 0 { + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + return + } + timestamps = generateFestaTimestamps(s, uint32(s.server.erupeConfig.DevModeOptions.FestaEvent), true) + } else { + timestamps = generateFestaTimestamps(s, start, false) + } + + if timestamps[0] > uint32(Time_Current_Adjusted().Unix()) { doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) return } - bf.WriteUint32(uint32(Time_Current_Adjusted().Unix())) // TS Current Time + + var blueSouls, redSouls uint32 + s.server.db.QueryRow("SELECT SUM(gc.souls) FROM guild_characters gc INNER JOIN festa_registrations fr ON fr.guild_id = gc.guild_id WHERE fr.team = 'blue'").Scan(&blueSouls) + s.server.db.QueryRow("SELECT SUM(gc.souls) FROM guild_characters gc INNER JOIN festa_registrations fr ON fr.guild_id = gc.guild_id WHERE fr.team = 'red'").Scan(&redSouls) + + bf.WriteUint32(id) + for _, timestamp := range timestamps { + bf.WriteUint32(timestamp) + } + bf.WriteUint32(uint32(Time_Current_Adjusted().Unix())) bf.WriteUint8(4) ps.Uint8(bf, "", false) bf.WriteUint32(0) - bf.WriteUint32(0) // Blue souls - bf.WriteUint32(0) // Red souls + bf.WriteUint32(blueSouls) + bf.WriteUint32(redSouls) - trials := 0 - bf.WriteUint16(uint16(trials)) - for i := 0; i < trials; i++ { - bf.WriteUint32(uint32(i + 1)) // trialID - bf.WriteUint8(0xFF) // unk - bf.WriteUint8(uint8(i)) // objective - bf.WriteUint32(0x1B) // monID, itemID if deliver - bf.WriteUint16(1) // huntsRemain? - bf.WriteUint16(0) // location - bf.WriteUint16(1) // numSoulsReward - bf.WriteUint8(0xFF) // unk - bf.WriteUint8(0xFF) // monopolised - bf.WriteUint16(0) // unk + rows, _ = s.server.db.Queryx("SELECT * FROM festa_trials") + trialData := byteframe.NewByteFrame() + var count uint16 + for rows.Next() { + trial := &Trial{} + err := rows.StructScan(&trial) + if err != nil { + continue + } + count++ + trialData.WriteUint32(trial.ID) + trialData.WriteUint8(0) // Unk + trialData.WriteUint8(trial.Objective) + trialData.WriteUint32(trial.GoalID) + trialData.WriteUint16(trial.TimesReq) + trialData.WriteUint16(trial.Locale) + trialData.WriteUint16(trial.Reward) + trialData.WriteUint8(0xFF) // Unk + trialData.WriteUint8(0xFF) // MonopolyState + trialData.WriteUint16(0) // Unk } + bf.WriteUint16(count) + bf.WriteBytes(trialData.Data()) - unk := 0 // static rewards? - bf.WriteUint16(uint16(unk)) - for i := 0; i < unk; i++ { + unk := uint16(0) // static rewards? + bf.WriteUint16(unk) + for i := uint16(0); i < unk; i++ { bf.WriteUint32(0) bf.WriteUint16(0) bf.WriteUint16(0) @@ -144,8 +207,15 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { // state festa (U)ser func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfStateFestaU) + guild, err := GetGuildInfoByCharacterId(s, s.charID) + if err != nil || guild == nil { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return + } + var souls uint32 + s.server.db.QueryRow("SELECT souls FROM guild_characters WHERE character_id=$1", s.charID).Scan(&souls) bf := byteframe.NewByteFrame() - bf.WriteUint32(0) // souls + bf.WriteUint32(souls) bf.WriteUint32(0) // unk doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } @@ -153,8 +223,13 @@ func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) { // state festa (G)uild func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfStateFestaG) + guild, err := GetGuildInfoByCharacterId(s, s.charID) + if err != nil || guild == nil { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return + } resp := byteframe.NewByteFrame() - resp.WriteUint32(0) // souls + resp.WriteUint32(guild.Souls) resp.WriteUint32(1) // unk resp.WriteUint32(1) // unk resp.WriteUint32(1) // unk, rank? @@ -164,31 +239,54 @@ func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateFestaMember) + guild, err := GetGuildInfoByCharacterId(s, s.charID) + if err != nil || guild == nil { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return + } + members, err := GetGuildMembers(s, guild.ID, false) + if err != nil { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return + } bf := byteframe.NewByteFrame() - bf.WriteUint16(0) // numMembers - // uint16 unk - // uint32 charID - // uint32 souls + bf.WriteUint16(uint16(len(members))) + for _, member := range members { + bf.WriteUint16(0) + bf.WriteUint32(member.CharID) + bf.WriteUint32(member.Souls) + } doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfVoteFesta(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfEntryFesta) + pkt := p.(*mhfpacket.MsgMhfVoteFesta) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } func handleMsgMhfEntryFesta(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEntryFesta) - bf := byteframe.NewByteFrame() + guild, err := GetGuildInfoByCharacterId(s, s.charID) + if err != nil || guild == nil { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return + } rand.Seed(time.Now().UnixNano()) - bf.WriteUint32(uint32(rand.Intn(2))) - // Update guild table + team := uint32(rand.Intn(2)) + switch team { + case 0: + s.server.db.Exec("INSERT INTO festa_registrations VALUES ($1, 'blue')", guild.ID) + case 1: + s.server.db.Exec("INSERT INTO festa_registrations VALUES ($1, 'red')", guild.ID) + } + bf := byteframe.NewByteFrame() + bf.WriteUint32(team) doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfChargeFesta(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfChargeFesta) - // Update festa state table + s.server.db.Exec("UPDATE guild_characters SET souls=souls+$1 WHERE character_id=$2", pkt.Souls, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } diff --git a/Erupe/server/channelserver/handlers_guild.go b/Erupe/server/channelserver/handlers_guild.go index 9051e8098..2277e7561 100644 --- a/Erupe/server/channelserver/handlers_guild.go +++ b/Erupe/server/channelserver/handlers_guild.go @@ -12,10 +12,10 @@ import ( "strings" "time" - "erupe-ce/common/byteframe" "erupe-ce/common/bfutil" - "erupe-ce/common/stringsupport" + "erupe-ce/common/byteframe" ps "erupe-ce/common/pascalstring" + "erupe-ce/common/stringsupport" "erupe-ce/network/mhfpacket" "github.com/jmoiron/sqlx" "go.uber.org/zap" @@ -56,6 +56,7 @@ type Guild struct { PugiName2 string `db:"pugi_name_2"` PugiName3 string `db:"pugi_name_3"` FestivalColour FestivalColour `db:"festival_colour"` + Souls uint32 `db:"souls"` Rank uint16 `db:"rank"` AllianceID uint32 `db:"alliance_id"` Icon *GuildIcon `db:"icon"` @@ -124,7 +125,14 @@ SELECT pugi_name_1, pugi_name_2, pugi_name_3, - festival_colour, + CASE WHEN ( + SELECT team FROM festa_registrations fr WHERE fr.guild_id = g.id + ) IS NULL THEN 'none' ELSE ( + SELECT team FROM festa_registrations fr WHERE fr.guild_id = g.id + ) END festival_colour, + ( + SELECT SUM(souls) FROM guild_characters gc WHERE gc.guild_id = g.id + ) AS souls, CASE WHEN rank_rp <= 48 THEN rank_rp/24 WHEN rank_rp <= 288 THEN rank_rp/48+1 @@ -138,14 +146,12 @@ SELECT ga.parent_id = g.id OR ga.sub1_id = g.id OR ga.sub2_id = g.id - ) IS NULL THEN 0 - ELSE ( + ) IS NULL THEN 0 ELSE ( SELECT id FROM guild_alliances ga WHERE ga.parent_id = g.id OR ga.sub1_id = g.id OR ga.sub2_id = g.id - ) - END alliance_id, + ) END alliance_id, icon, ( SELECT count(1) FROM guild_characters gc WHERE gc.guild_id = g.id diff --git a/Erupe/server/channelserver/handlers_guild_member.go b/Erupe/server/channelserver/handlers_guild_member.go index db9623b4a..2077f7fb4 100644 --- a/Erupe/server/channelserver/handlers_guild_member.go +++ b/Erupe/server/channelserver/handlers_guild_member.go @@ -12,6 +12,7 @@ type GuildMember struct { GuildID uint32 `db:"guild_id"` CharID uint32 `db:"character_id"` JoinedAt *time.Time `db:"joined_at"` + Souls uint32 `db:"souls"` Name string `db:"name"` IsApplicant bool `db:"is_applicant"` OrderIndex uint8 `db:"order_index"` @@ -49,30 +50,32 @@ func (gm *GuildMember) IsRecruiter() bool { } const guildMembersSelectSQL = ` -SELECT g.id as guild_id, - joined_at, - c.name, - character.character_id, - coalesce(gc.order_index, 0) as order_index, - c.last_login, - coalesce(gc.avoid_leadership, false) as avoid_leadership, - c.hrp, - c.gr, - c.weapon_id, - c.weapon_type, - character.is_applicant, - CASE WHEN g.leader_id = c.id THEN 1 ELSE 0 END as is_leader -FROM ( - SELECT character_id, true as is_applicant, guild_id - FROM guild_applications ga - WHERE ga.application_type = 'applied' - UNION - SELECT character_id, false as is_applicant, guild_id - FROM guild_characters gc - ) character - JOIN characters c on character.character_id = c.id - LEFT JOIN guild_characters gc ON gc.character_id = character.character_id - JOIN guilds g ON g.id = character.guild_id +SELECT + g.id as guild_id, + joined_at, + souls, + c.name, + character.character_id, + coalesce(gc.order_index, 0) as order_index, + c.last_login, + coalesce(gc.avoid_leadership, false) as avoid_leadership, + c.hrp, + c.gr, + c.weapon_id, + c.weapon_type, + character.is_applicant, + CASE WHEN g.leader_id = c.id THEN 1 ELSE 0 END as is_leader + FROM ( + SELECT character_id, true as is_applicant, guild_id + FROM guild_applications ga + WHERE ga.application_type = 'applied' + UNION + SELECT character_id, false as is_applicant, guild_id + FROM guild_characters gc + ) character + JOIN characters c on character.character_id = c.id + LEFT JOIN guild_characters gc ON gc.character_id = character.character_id + JOIN guilds g ON g.id = character.guild_id ` func GetGuildMembers(s *Session, guildID uint32, applicants bool) ([]*GuildMember, error) { From 3638d8aabf92a24e82e87bfe255bead43ed9cdc3 Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 27 Jul 2022 21:07:15 +1000 Subject: [PATCH 2/4] further decoding and guild fix --- Erupe/server/channelserver/handlers_festa.go | 23 +++++++++++++++++++- Erupe/server/channelserver/handlers_guild.go | 4 ++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Erupe/server/channelserver/handlers_festa.go b/Erupe/server/channelserver/handlers_festa.go index 3c39f9999..8db270a4f 100644 --- a/Erupe/server/channelserver/handlers_festa.go +++ b/Erupe/server/channelserver/handlers_festa.go @@ -198,7 +198,28 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { bf.WriteBool(false) } - d, _ := hex.DecodeString("0001D4C001F4000411B6648100010001152A81F589A497A793C196B18B528E6D926381F52A0011B6648100020001152A81F589A497A793C196B18B528E6D926381F52A000C952CE10003000109E54BE54E89B38F970029FDCE04000400001381818D84836C8352819993A294B091D1818100000811B6648100010001152A81F589A497A793C196B18B528E6D926381F52A0011B6648100020001152A81F589A497A793C196B18B528E6D926381F52A0011B6648100030001152A81F589A497A793C196B18B528E6D926381F52A0011B6648100040001152A81F589A497A793C196B18B528E6D926381F52A0011B6648100050001152A81F589A497A793C196B18B528E6D926381F52A0011B6648100060001152A81F589A497A793C196B18B528E6D926381F52A000C952CE10007000109E54BE54E89B38F9700000000000008000001000000000100001388000007D0000003E800000064012C00C8009600640032") + bf.WriteUint16(0x0001) + bf.WriteUint32(0xD4C001F4) + + categoryWinners := uint16(0) // NYI + bf.WriteUint16(categoryWinners) + for i := uint16(0); i < categoryWinners; i++ { + bf.WriteUint32(0) // Guild ID + bf.WriteUint16(i + 1) // Category ID + bf.WriteUint16(0) // Festa Team + ps.Uint8(bf, "", true) // Guild Name + } + + dailyWinners := uint16(0) // NYI + bf.WriteUint16(dailyWinners) + for i := uint16(0); i < dailyWinners; i++ { + bf.WriteUint32(0) // Guild ID + bf.WriteUint16(i + 1) // Category ID + bf.WriteUint16(0) // Festa Team + ps.Uint8(bf, "", true) // Guild Name + } + + d, _ := hex.DecodeString("000000000000000100001388000007D0000003E800000064012C00C8009600640032") bf.WriteBytes(d) ps.Uint16(bf, "", false) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) diff --git a/Erupe/server/channelserver/handlers_guild.go b/Erupe/server/channelserver/handlers_guild.go index 2277e7561..8ea45e891 100644 --- a/Erupe/server/channelserver/handlers_guild.go +++ b/Erupe/server/channelserver/handlers_guild.go @@ -163,8 +163,8 @@ SELECT func (guild *Guild) Save(s *Session) error { _, err := s.server.db.Exec(` - UPDATE guilds SET main_motto=$2, sub_motto=$3, comment=$4, pugi_name_1=$5, pugi_name_2=$6, pugi_name_3=$7, festival_colour=$8, icon=$9 WHERE id=$1 - `, guild.ID, guild.MainMotto, guild.SubMotto, guild.Comment, guild.PugiName1, guild.PugiName2, guild.PugiName3, guild.FestivalColour, guild.Icon) + UPDATE guilds SET main_motto=$2, sub_motto=$3, comment=$4, pugi_name_1=$5, pugi_name_2=$6, pugi_name_3=$7, icon=$8 WHERE id=$1 + `, guild.ID, guild.MainMotto, guild.SubMotto, guild.Comment, guild.PugiName1, guild.PugiName2, guild.PugiName3, guild.Icon) if err != nil { s.logger.Error("failed to update guild data", zap.Error(err), zap.Uint32("guildID", guild.ID)) From 69eb7e1cba3955eb2fdde6e1cf77765d43a4adf1 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 28 Jul 2022 01:51:17 +1000 Subject: [PATCH 3/4] implement canned festa prizes --- Erupe/festa.sql | 147 +++++++++++++++++++ Erupe/server/channelserver/handlers_festa.go | 68 +++++++-- 2 files changed, 202 insertions(+), 13 deletions(-) diff --git a/Erupe/festa.sql b/Erupe/festa.sql index da56e8c89..ce7d03594 100644 --- a/Erupe/festa.sql +++ b/Erupe/festa.sql @@ -33,6 +33,153 @@ CREATE TABLE IF NOT EXISTS public.festa_trials reward int NOT NULL ); +CREATE TYPE prize_type AS ENUM ('personal', 'guild'); + +CREATE TABLE IF NOT EXISTS public.festa_prizes +( + id serial NOT NULL PRIMARY KEY, + type prize_type NOT NULL, + tier int NOT NULL, + souls_req int NOT NULL, + item_id int NOT NULL, + num_item int NOT NULL +); + +CREATE TABLE IF NOT EXISTS public.festa_prizes_accepted +( + prize_id int NOT NULL, + character_id int NOT NULL +); + +-- Ripped prizes +INSERT INTO public.festa_prizes + (type, tier, souls_req, item_id, num_item) +VALUES + ('personal', 1, 1, 9647, 7), + ('personal', 2, 1, 9647, 7), + ('personal', 3, 1, 9647, 7), + ('personal', 1, 200, 11284, 4), + ('personal', 2, 200, 11284, 4), + ('personal', 3, 200, 11284, 4), + ('personal', 1, 400, 11381, 3), + ('personal', 2, 400, 11381, 3), + ('personal', 3, 400, 11381, 3), + ('personal', 1, 600, 11284, 8), + ('personal', 2, 600, 11284, 8), + ('personal', 3, 600, 11284, 8), + ('personal', 1, 800, 11384, 3), + ('personal', 2, 800, 11384, 3), + ('personal', 3, 800, 11384, 3), + ('personal', 1, 1000, 11284, 12), + ('personal', 2, 1000, 11284, 12), + ('personal', 3, 1000, 11284, 12), + ('personal', 1, 1200, 11381, 5), + ('personal', 2, 1200, 11381, 5), + ('personal', 3, 1200, 11381, 5), + ('personal', 1, 1400, 11284, 16), + ('personal', 2, 1400, 11284, 16), + ('personal', 3, 1400, 11284, 16), + ('personal', 1, 1700, 11384, 5), + ('personal', 2, 1700, 11384, 5), + ('personal', 3, 1700, 11384, 5), + ('personal', 1, 2000, 11284, 16), + ('personal', 2, 2000, 11284, 16), + ('personal', 3, 2000, 11284, 16), + ('personal', 1, 2500, 11382, 4), + ('personal', 2, 2500, 11382, 4), + ('personal', 3, 2500, 11382, 4), + ('personal', 1, 3000, 11284, 24), + ('personal', 2, 3000, 11284, 24), + ('personal', 3, 3000, 11284, 24), + ('personal', 1, 4000, 11385, 4), + ('personal', 2, 4000, 11385, 4), + ('personal', 3, 4000, 11385, 4), + ('personal', 1, 5000, 11381, 11), + ('personal', 2, 5000, 11381, 11), + ('personal', 3, 5000, 11381, 11), + ('personal', 1, 6000, 5177, 5), + ('personal', 2, 6000, 5177, 5), + ('personal', 3, 6000, 5177, 5), + ('personal', 1, 7000, 11384, 11), + ('personal', 2, 7000, 11384, 11), + ('personal', 3, 7000, 11384, 11), + ('personal', 1, 10000, 11382, 8), + ('personal', 2, 10000, 11382, 8), + ('personal', 3, 10000, 11382, 8), + ('personal', 1, 15000, 11385, 4), + ('personal', 2, 15000, 11385, 4), + ('personal', 3, 15000, 11385, 4), + ('personal', 1, 20000, 11381, 13), + ('personal', 2, 20000, 11381, 13), + ('personal', 3, 20000, 11381, 13), + ('personal', 1, 25000, 11385, 4), + ('personal', 2, 25000, 11385, 4), + ('personal', 3, 25000, 11385, 4), + ('personal', 1, 30000, 11383, 1), + ('personal', 2, 30000, 11383, 1), + ('personal', 3, 30000, 11383, 1); + +INSERT INTO public.festa_prizes +(type, tier, souls_req, item_id, num_item) +VALUES + ('guild', 1, 100, 7468, 5), + ('guild', 2, 100, 7468, 5), + ('guild', 3, 100, 7465, 5), + ('guild', 1, 300, 7469, 5), + ('guild', 2, 300, 7469, 5), + ('guild', 3, 300, 7466, 5), + ('guild', 1, 700, 7470, 5), + ('guild', 2, 700, 7470, 5), + ('guild', 3, 700, 7467, 5), + ('guild', 1, 1500, 13405, 14), + ('guild', 1, 1500, 1520, 3), + ('guild', 2, 1500, 13405, 14), + ('guild', 2, 1500, 1520, 3), + ('guild', 3, 1500, 7011, 3), + ('guild', 3, 1500, 13405, 14), + ('guild', 1, 3000, 10201, 10), + ('guild', 2, 3000, 10201, 10), + ('guild', 3, 3000, 10201, 10), + ('guild', 1, 6000, 13895, 14), + ('guild', 1, 6000, 1520, 6), + ('guild', 2, 6000, 13895, 14), + ('guild', 2, 6000, 1520, 6), + ('guild', 3, 6000, 13895, 14), + ('guild', 3, 6000, 7011, 4), + ('guild', 1, 12000, 13406, 14), + ('guild', 1, 12000, 1520, 9), + ('guild', 2, 12000, 13406, 14), + ('guild', 2, 12000, 1520, 9), + ('guild', 3, 12000, 13406, 14), + ('guild', 3, 12000, 7011, 5), + ('guild', 1, 25000, 10207, 10), + ('guild', 2, 25000, 10207, 10), + ('guild', 3, 25000, 10207, 10), + ('guild', 1, 50000, 1520, 12), + ('guild', 1, 50000, 13896, 14), + ('guild', 2, 50000, 1520, 12), + ('guild', 2, 50000, 13896, 14), + ('guild', 3, 50000, 7011, 6), + ('guild', 3, 50000, 13896, 14), + ('guild', 1, 100000, 10201, 10), + ('guild', 2, 100000, 10201, 10), + ('guild', 3, 100000, 10201, 10), + ('guild', 1, 200000, 13406, 16), + ('guild', 2, 200000, 13406, 16), + ('guild', 3, 200000, 13406, 16), + ('guild', 1, 300000, 13896, 16), + ('guild', 2, 300000, 13896, 16), + ('guild', 3, 300000, 13896, 16), + ('guild', 1, 400000, 10207, 10), + ('guild', 2, 400000, 10207, 10), + ('guild', 3, 400000, 10207, 10), + ('guild', 1, 500000, 13407, 6), + ('guild', 1, 500000, 13897, 6), + ('guild', 2, 500000, 13407, 6), + ('guild', 2, 500000, 13897, 6), + ('guild', 3, 500000, 13407, 6), + ('guild', 3, 500000, 13897, 6); + -- Ripped trials INSERT INTO public.festa_trials (objective, goal_id, times_req, locale_req, reward) diff --git a/Erupe/server/channelserver/handlers_festa.go b/Erupe/server/channelserver/handlers_festa.go index 8db270a4f..d05e97239 100644 --- a/Erupe/server/channelserver/handlers_festa.go +++ b/Erupe/server/channelserver/handlers_festa.go @@ -71,6 +71,7 @@ func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) { func cleanupFesta(s *Session) { s.server.db.Exec("DELETE FROM events WHERE event_type='festa'") s.server.db.Exec("DELETE FROM festa_registrations") + s.server.db.Exec("DELETE FROM festa_prizes_accepted") s.server.db.Exec("UPDATE guild_characters SET souls=0") } @@ -320,32 +321,73 @@ func handleMsgMhfAcquireFesta(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfAcquireFestaPersonalPrize) - // Set prize as claimed + s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES ($1, $2)", pkt.PrizeID, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } func handleMsgMhfAcquireFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfAcquireFestaIntermediatePrize) - // Set prize as claimed + s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES ($1, $2)", pkt.PrizeID, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } -// uint32 numPrizes -// struct festaPrize -// uint32 prizeID -// uint32 prizeTier (1/2/3, 3 = GR) -// uint32 soulsReq -// uint32 unk (00 00 00 07) -// uint32 itemID -// uint32 numItem -// bool claimed +type Prize struct { + ID uint32 `db:"id"` + Tier uint32 `db:"tier"` + SoulsReq uint32 `db:"souls_req"` + ItemID uint32 `db:"item_id"` + NumItem uint32 `db:"num_item"` + Claimed int `db:"claimed"` +} func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateFestaPersonalPrize) - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + rows, _ := s.server.db.Queryx("SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = 4) AS claimed FROM festa_prizes fp WHERE type='personal'") + var count uint32 + prizeData := byteframe.NewByteFrame() + for rows.Next() { + prize := &Prize{} + err := rows.StructScan(&prize) + if err != nil { + continue + } + count++ + prizeData.WriteUint32(prize.ID) + prizeData.WriteUint32(prize.Tier) + prizeData.WriteUint32(prize.SoulsReq) + prizeData.WriteUint32(7) // Unk + prizeData.WriteUint32(prize.ItemID) + prizeData.WriteUint32(prize.NumItem) + prizeData.WriteBool(prize.Claimed > 0) + } + bf := byteframe.NewByteFrame() + bf.WriteUint32(count) + bf.WriteBytes(prizeData.Data()) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfEnumerateFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateFestaIntermediatePrize) - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + rows, _ := s.server.db.Queryx("SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = 4) AS claimed FROM festa_prizes fp WHERE type='guild'") + var count uint32 + prizeData := byteframe.NewByteFrame() + for rows.Next() { + prize := &Prize{} + err := rows.StructScan(&prize) + if err != nil { + continue + } + count++ + prizeData.WriteUint32(prize.ID) + prizeData.WriteUint32(prize.Tier) + prizeData.WriteUint32(prize.SoulsReq) + prizeData.WriteUint32(7) // Unk + prizeData.WriteUint32(prize.ItemID) + prizeData.WriteUint32(prize.NumItem) + prizeData.WriteBool(prize.Claimed > 0) + } + bf := byteframe.NewByteFrame() + bf.WriteUint32(count) + bf.WriteBytes(prizeData.Data()) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } From 732199358ad07831aa4d3dcd7decfa2022d5d5a6 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 28 Jul 2022 02:36:50 +1000 Subject: [PATCH 4/4] handle acquiring festa finale --- Erupe/server/channelserver/handlers_festa.go | 57 ++++++++++---------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/Erupe/server/channelserver/handlers_festa.go b/Erupe/server/channelserver/handlers_festa.go index d05e97239..76b6dedad 100644 --- a/Erupe/server/channelserver/handlers_festa.go +++ b/Erupe/server/channelserver/handlers_festa.go @@ -79,25 +79,26 @@ func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 { timestamps := make([]uint32, 5) midnight := Time_Current_Midnight() if debug && start <= 3 { + midnight := uint32(midnight.Unix()) switch start { case 1: - timestamps[0] = uint32(midnight.Unix()) - timestamps[1] = uint32(midnight.Add(24 * 7 * time.Hour).Unix()) - timestamps[2] = uint32(midnight.Add(24 * 14 * time.Hour).Unix()) - timestamps[3] = uint32(midnight.Add(24*14*time.Hour + 150*time.Minute).Unix()) - timestamps[4] = uint32(midnight.Add(24*28*time.Hour + 11*time.Hour).Unix()) + timestamps[0] = midnight + timestamps[1] = timestamps[0] + 604800 + timestamps[2] = timestamps[1] + 604800 + timestamps[3] = timestamps[2] + 9000 + timestamps[4] = timestamps[3] + 1240200 case 2: - timestamps[0] = uint32(midnight.Add(-24 * 7 * time.Hour).Unix()) - timestamps[1] = uint32(midnight.Unix()) - timestamps[2] = uint32(midnight.Add(24 * 7 * time.Hour).Unix()) - timestamps[3] = uint32(midnight.Add(24*7*time.Hour + 150*time.Minute).Unix()) - timestamps[4] = uint32(midnight.Add(24 * 21 * time.Hour).Add(11 * time.Hour).Unix()) + timestamps[0] = midnight - 604800 + timestamps[1] = midnight + timestamps[2] = timestamps[1] + 604800 + timestamps[3] = timestamps[2] + 9000 + timestamps[4] = timestamps[3] + 1240200 case 3: - timestamps[0] = uint32(midnight.Add(-24 * 14 * time.Hour).Unix()) - timestamps[1] = uint32(midnight.Add(-24*7*time.Hour + 11*time.Hour).Unix()) - timestamps[2] = uint32(midnight.Unix()) - timestamps[3] = uint32(midnight.Add(150 * time.Minute).Unix()) - timestamps[4] = uint32(midnight.Add(24*14*time.Hour + 11*time.Hour).Unix()) + timestamps[0] = midnight - 1209600 + timestamps[1] = midnight - 604800 + timestamps[2] = midnight + timestamps[3] = timestamps[2] + 9000 + timestamps[4] = timestamps[3] + 1240200 } return timestamps } @@ -189,15 +190,9 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint16(count) bf.WriteBytes(trialData.Data()) - unk := uint16(0) // static rewards? - bf.WriteUint16(unk) - for i := uint16(0); i < unk; i++ { - bf.WriteUint32(0) - bf.WriteUint16(0) - bf.WriteUint16(0) - bf.WriteUint32(0) - bf.WriteBool(false) - } + // Static bonus rewards + rewards, _ := hex.DecodeString("001901000007015E05F000000000000100000703E81B6300000000010100000C03E8000000000000000100000D0000000000000000000100000100000000000000000002000007015E05F000000000000200000703E81B6300000000010200000C03E8000000000000000200000D0000000000000000000200000400000000000000000003000007015E05F000000000000300000703E81B6300000000010300000C03E8000000000000000300000D0000000000000000000300000100000000000000000004000007015E05F000000000000400000703E81B6300000000010400000C03E8000000000000000400000D0000000000000000000400000400000000000000000005000007015E05F000000000000500000703E81B6300000000010500000C03E8000000000000000500000D00000000000000000005000001000000000000000000") + bf.WriteBytes(rewards) bf.WriteUint16(0x0001) bf.WriteUint32(0xD4C001F4) @@ -238,7 +233,16 @@ func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) { s.server.db.QueryRow("SELECT souls FROM guild_characters WHERE character_id=$1", s.charID).Scan(&souls) bf := byteframe.NewByteFrame() bf.WriteUint32(souls) - bf.WriteUint32(0) // unk + + // This definitely isn't right, but it does stop you from claiming the festa infinitely. + var claimed uint32 + s.server.db.QueryRow("SELECT count(*) FROM festa_prizes_accepted fpa WHERE fpa.prize_id=0 AND fpa.character_id=$1", s.charID).Scan(&claimed) + if claimed > 0 { + bf.WriteUint32(0) // unk + } else { + bf.WriteUint32(0x01000000) // unk + } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } @@ -314,8 +318,7 @@ func handleMsgMhfChargeFesta(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireFesta(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfAcquireFesta) - // Mark festa as claimed - // Update guild table? + s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES (0, $1)", s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) }