major rewrite

This commit is contained in:
wish
2024-07-28 22:15:14 +10:00
parent 80e83f656e
commit b6a963b131
9 changed files with 350 additions and 1071 deletions

View File

@@ -11,9 +11,7 @@ import (
// MsgMhfAcquireItem represents the MSG_MHF_ACQUIRE_ITEM // MsgMhfAcquireItem represents the MSG_MHF_ACQUIRE_ITEM
type MsgMhfAcquireItem struct { type MsgMhfAcquireItem struct {
AckHandle uint32 AckHandle uint32
NullPadding uint16 //0 in Z2 RewardIDs []uint32
Length uint16
Unk1 []uint32
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -24,10 +22,10 @@ func (m *MsgMhfAcquireItem) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfAcquireItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfAcquireItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.NullPadding = bf.ReadUint16() bf.ReadUint16() // Zeroed
m.Length = bf.ReadUint16() ids := bf.ReadUint16()
for i := 0; i < int(m.Length); i++ { for i := uint16(0); i < ids; i++ {
m.Unk1 = append(m.Unk1, bf.ReadUint32()) m.RewardIDs = append(m.RewardIDs, bf.ReadUint32())
} }
return nil return nil
} }

View File

@@ -2,8 +2,8 @@ package mhfpacket
import ( import (
"errors" "errors"
"erupe-ce/common/bfutil"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/common/stringsupport"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/network/clientctx" "erupe-ce/network/clientctx"
) )
@@ -12,8 +12,7 @@ import (
type MsgMhfApplyCampaign struct { type MsgMhfApplyCampaign struct {
AckHandle uint32 AckHandle uint32
CampaignID uint32 CampaignID uint32
NullPadding uint16 // set as 0 in z2 Code string
CodeString string
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -25,9 +24,8 @@ func (m *MsgMhfApplyCampaign) Opcode() network.PacketID {
func (m *MsgMhfApplyCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfApplyCampaign) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.CampaignID = bf.ReadUint32() m.CampaignID = bf.ReadUint32()
m.NullPadding = bf.ReadUint16() bf.ReadUint16() // Zeroed
m.CodeString = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) m.Code = string(bfutil.UpToNull(bf.ReadBytes(16)))
bf.ReadInt8()
return nil return nil
} }

View File

@@ -11,8 +11,6 @@ import (
// MsgMhfEnumerateItem represents the MSG_MHF_ENUMERATE_ITEM // MsgMhfEnumerateItem represents the MSG_MHF_ENUMERATE_ITEM
type MsgMhfEnumerateItem struct { type MsgMhfEnumerateItem struct {
AckHandle uint32 AckHandle uint32
NullPadding uint16 // 0 in Z2
Unk1 uint16 //0002
CampaignID uint32 CampaignID uint32
} }
@@ -24,8 +22,8 @@ func (m *MsgMhfEnumerateItem) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfEnumerateItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfEnumerateItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.NullPadding = bf.ReadUint16() bf.ReadUint16() // Zeroed
m.Unk1 = bf.ReadUint16() bf.ReadUint16() // Always 2
m.CampaignID = bf.ReadUint32() m.CampaignID = bf.ReadUint32()
return nil return nil
} }

View File

@@ -11,12 +11,9 @@ import (
// MsgMhfTransferItem represents the MSG_MHF_TRANSFER_ITEM // MsgMhfTransferItem represents the MSG_MHF_TRANSFER_ITEM
type MsgMhfTransferItem struct { type MsgMhfTransferItem struct {
AckHandle uint32 AckHandle uint32
// looking at packets, these were static across sessions and did not actually QuestID uint32
// correlate with any item IDs that would make sense to get after quests so ItemType uint8
// I have no idea what this actually does Quantity uint16
Unk0 uint32
Unk1 uint8
Unk2 uint16
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -27,10 +24,10 @@ func (m *MsgMhfTransferItem) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfTransferItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfTransferItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint32() m.QuestID = bf.ReadUint32()
m.Unk1 = bf.ReadUint8() m.ItemType = bf.ReadUint8()
bf.ReadUint8() // Zeroed bf.ReadUint8() // Zeroed
m.Unk2 = bf.ReadUint16() m.Quantity = bf.ReadUint16()
return nil return nil
} }

File diff suppressed because it is too large Load Diff

View File

@@ -8,27 +8,23 @@ CREATE TABLE IF NOT EXISTS public.campaigns (
max_sr INTEGER, max_sr INTEGER,
min_gr INTEGER, min_gr INTEGER,
max_gr INTEGER, max_gr INTEGER,
recieve_type INTEGER, reward_type INTEGER,
stamp_amount INTEGER, stamps INTEGER,
hide INTEGER, unk INTEGER,
background_id INTEGER, background_id INTEGER,
hide_npc BOOLEAN,
start_time TIMESTAMP WITH TIME ZONE, start_time TIMESTAMP WITH TIME ZONE,
end_time TIMESTAMP WITH TIME ZONE, end_time TIMESTAMP WITH TIME ZONE,
period_ended BOOLEAN, title TEXT,
string0 TEXT, reward TEXT,
string1 TEXT,
string2 TEXT,
string3 TEXT,
link TEXT, link TEXT,
code_prefix TEXT code_prefix TEXT
); );
CREATE TABLE IF NOT EXISTS public.campaign_categories ( CREATE TABLE IF NOT EXISTS public.campaign_categories (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
cat_type INTEGER, type INTEGER,
title TEXT, title TEXT,
description_text TEXT description TEXT
); );
CREATE TABLE IF NOT EXISTS public.campaign_category_links ( CREATE TABLE IF NOT EXISTS public.campaign_category_links (
@@ -37,14 +33,17 @@ CREATE TABLE IF NOT EXISTS public.campaign_category_links (
category_id INTEGER category_id INTEGER
); );
CREATE TABLE IF NOT EXISTS public.campaign_entries ( CREATE TABLE IF NOT EXISTS public.campaign_rewards (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
campaign_id INTEGER, campaign_id INTEGER,
hide BOOLEAN,
item_type INTEGER, item_type INTEGER,
item_amount INTEGER, quantity INTEGER,
item_no INTEGER, item_id INTEGER
deadline TIMESTAMP WITH TIME ZONE );
CREATE TABLE IF NOT EXISTS public.campaign_rewards_claimed (
character_id INTEGER,
reward_id INTEGER
); );
CREATE TABLE IF NOT EXISTS public.campaign_state ( CREATE TABLE IF NOT EXISTS public.campaign_state (
@@ -54,4 +53,14 @@ CREATE TABLE IF NOT EXISTS public.campaign_state (
code TEXT code TEXT
); );
CREATE TABLE IF NOT EXISTS public.campaign_codes (
code TEXT,
multi BOOLEAN
);
CREATE TABLE IF NOT EXISTS public.campaign_quest (
campaign_id INTEGER,
character_id INTEGER
);
END; END;

View File

@@ -641,11 +641,6 @@ func handleMsgSysInfokyserver(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetCaUniqueID(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetCaUniqueID(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfTransferItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfTransferItem)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
func handleMsgMhfEnumeratePrice(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumeratePrice(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumeratePrice) pkt := p.(*mhfpacket.MsgMhfEnumeratePrice)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()

View File

@@ -1,14 +1,11 @@
package channelserver package channelserver
import ( import (
"database/sql"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring" ps "erupe-ce/common/pascalstring"
"erupe-ce/common/stringsupport" "erupe-ce/common/stringsupport"
_config "erupe-ce/config" _config "erupe-ce/config"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"fmt"
"log"
"time" "time"
) )
@@ -20,42 +17,36 @@ type CampaignEvent struct {
MaxSR int16 `db:"max_sr"` MaxSR int16 `db:"max_sr"`
MinGR int16 `db:"min_gr"` MinGR int16 `db:"min_gr"`
MaxGR int16 `db:"max_gr"` MaxGR int16 `db:"max_gr"`
RecieveType uint16 `db:"recieve_type"` //1 Item/Weapon //2 Event Quest //3 Item/Weapon RewardType uint16 `db:"reward_type"`
StampAmount uint8 `db:"stamp_amount"` Stamps uint8 `db:"stamps"`
Hide uint8 `db:"hide"` //1 hides // 10 and 0 seem to be visible ?? is 10 overhang? Unk uint8 `db:"unk"`
BackgroundID uint16 `db:"background_id"` BackgroundID uint16 `db:"background_id"`
HideNPC uint16 `db:"hide_npc"` //TODO: giving this the value 1 or above made the NPC glitch / hide
Start time.Time `db:"start_time"` Start time.Time `db:"start_time"`
End time.Time `db:"end_time"` End time.Time `db:"end_time"`
PeriodEnded bool `db:"period_ended"` Title string `db:"title"`
String0 string `db:"string0"` Reward string `db:"reward"`
String1 string `db:"string1"`
String2 string `db:"string2"`
String3 string `db:"string3"`
Link string `db:"link"` Link string `db:"link"`
Prefix string `db:"code_prefix"` Prefix string `db:"code_prefix"`
} }
type CampaignCategory struct { type CampaignCategory struct {
ID uint16 `db:"id"` ID uint16 `db:"id"`
Type uint8 `db:"cat_type"` Type uint8 `db:"type"`
Title string `db:"title"` Title string `db:"title"`
Description string `db:"description_text"` Description string `db:"description"`
} }
type CampaignLink struct { type CampaignLink struct {
CategoryID uint16 `db:"category_id"` CategoryID uint16 `db:"category_id"`
CampaignID uint32 `db:"campaign_id"` CampaignID uint32 `db:"campaign_id"`
} }
type CampaignEntry struct {
type CampaignReward struct {
ID uint32 `db:"id"` ID uint32 `db:"id"`
Hide bool `db:"hide"` ItemType uint16 `db:"item_type"`
ItemType uint8 `db:"item_type"` Quantity uint16 `db:"quantity"`
Amount uint16 `db:"item_amount"` ItemID uint16 `db:"item_id"`
ItemNo uint16 `db:"item_no"` Deadline time.Time `db:"deadline"`
Unk4 uint16 `db:"unk1"`
Unk5 uint32 `db:"unk2"`
DeadLine time.Time `db:"deadline"`
} }
func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
@@ -64,15 +55,14 @@ func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
var events []CampaignEvent var events []CampaignEvent
var categories []CampaignCategory var categories []CampaignCategory
var campaignLinks []CampaignLink var campaignLinks []CampaignLink
err := s.server.db.Select(&events, "SELECT id,min_hr,max_hr,min_sr,max_sr,min_gr,max_gr,recieve_type,stamp_amount,hide,background_id,hide_npc,start_time,end_time,period_ended,string0,string1,string2,string3,link,code_prefix FROM campaigns") err := s.server.db.Select(&events, "SELECT id,min_hr,max_hr,min_sr,max_sr,min_gr,max_gr,reward_type,stamps,unk,background_id,start_time,end_time,title,reward,link,code_prefix FROM campaigns")
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
err = s.server.db.Select(&categories, "SELECT id, cat_type, title, description_text FROM campaign_categories") err = s.server.db.Select(&categories, "SELECT id, type, title, description FROM campaign_categories")
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return return
@@ -90,7 +80,7 @@ func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
} }
for _, event := range events { for _, event := range events {
bf.WriteUint32(event.ID) bf.WriteUint32(event.ID)
bf.WriteUint32(0) // always 0 in reference bf.WriteUint32(0)
bf.WriteInt16(event.MinHR) bf.WriteInt16(event.MinHR)
bf.WriteInt16(event.MaxHR) bf.WriteInt16(event.MaxHR)
bf.WriteInt16(event.MinSR) bf.WriteInt16(event.MinSR)
@@ -99,20 +89,23 @@ func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt16(event.MinGR) bf.WriteInt16(event.MinGR)
bf.WriteInt16(event.MaxGR) bf.WriteInt16(event.MaxGR)
} }
bf.WriteUint16(event.RecieveType) bf.WriteUint16(event.RewardType)
bf.WriteUint8(event.StampAmount) bf.WriteUint8(event.Stamps)
bf.WriteUint8(event.Hide) bf.WriteUint8(event.Unk) // Related to stamp count
bf.WriteUint16(event.BackgroundID) bf.WriteUint16(event.BackgroundID)
bf.WriteUint16(event.HideNPC) bf.WriteUint16(0)
bf.WriteUint32(uint32(event.Start.Unix())) bf.WriteUint32(uint32(event.Start.Unix()))
bf.WriteUint32(uint32(event.End.Unix())) bf.WriteUint32(uint32(event.End.Unix()))
bf.WriteBool(event.PeriodEnded) if event.End.After(time.Now()) {
ps.Uint8(bf, event.String0, true) bf.WriteBool(true)
ps.Uint8(bf, event.String1, true) } else {
ps.Uint8(bf, event.String2, true) bf.WriteBool(false)
ps.Uint8(bf, event.String3, true) }
ps.Uint8(bf, event.Title, true)
ps.Uint8(bf, event.Reward, true)
ps.Uint8(bf, "", false)
ps.Uint8(bf, "", false)
ps.Uint8(bf, event.Link, true) ps.Uint8(bf, event.Link, true)
} }
if len(events) > 255 { if len(events) > 255 {
@@ -123,7 +116,7 @@ func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
} }
for _, event := range events { for _, event := range events {
bf.WriteUint32(event.ID) bf.WriteUint32(event.ID)
bf.WriteUint8(1) //StampAmount * This Amount = Stamps Shown bf.WriteUint8(1) // Related to stamp count
bf.WriteBytes([]byte(event.Prefix)) bf.WriteBytes([]byte(event.Prefix))
} }
@@ -160,29 +153,30 @@ func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfStateCampaign) pkt := p.(*mhfpacket.MsgMhfStateCampaign)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var stamps, amount int var required int
var period_ended bool var deadline time.Time
err := s.server.db.QueryRow(`SELECT COUNT(*) FROM campaign_state WHERE campaign_id = $1 AND character_id = $2`, pkt.CampaignID, s.charID).Scan(&stamps) var stamps []uint32
err := s.server.db.Select(&stamps, "SELECT id FROM campaign_state WHERE campaign_id = $1 AND character_id = $2", pkt.CampaignID, s.charID)
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
err = s.server.db.QueryRow(`SELECT stamp_amount,period_ended FROM campaigns WHERE id = $1`, pkt.CampaignID).Scan(&amount, &period_ended) err = s.server.db.QueryRow(`SELECT stamps, end_time FROM campaigns WHERE id = $1`, pkt.CampaignID).Scan(&required, &deadline)
if err != nil { if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
var unkArray = []uint32{1, 2, 3, 4, 5, 6} //Not figured out what this does yet....? bf.WriteUint16(uint16(len(stamps) + 1))
bf.WriteUint16(uint16(stamps + 1)) // game client seems to -1
if amount == 1 { if len(stamps) < required {
bf.WriteUint16(1) bf.WriteUint16(0)
} else if stamps >= amount || period_ended { } else if len(stamps) >= required || deadline.After(time.Now()) {
bf.WriteUint16(2) bf.WriteUint16(2)
} else if amount > 1 {
bf.WriteUint16(3)
} }
for _, value := range unkArray {
bf.WriteUint32(value) for _, v := range stamps {
bf.WriteUint32(v)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
@@ -191,67 +185,89 @@ func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfApplyCampaign(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfApplyCampaign(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfApplyCampaign) pkt := p.(*mhfpacket.MsgMhfApplyCampaign)
var code string // Check if the code exists and check if it's a multi-code
// Query to check if the event code exists in the database var multi bool
err := s.server.db.QueryRow("SELECT code FROM public.campaign_state WHERE code = $1", pkt.CodeString).Scan(&code) err := s.server.db.QueryRow(`SELECT multi FROM public.campaign_codes WHERE code = $1 GROUP BY multi`, pkt.Code).Scan(&multi)
if err != nil {
switch {
case err == sql.ErrNoRows:
fmt.Println("Event code does not exist in the database.")
s.server.db.Exec(`INSERT INTO public.campaign_state ( code, campaign_id ,character_id) VALUES ($1,$2,$3)`, pkt.CodeString, pkt.CampaignID, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
case err != nil:
log.Fatal(err)
default:
fmt.Printf("Event code '%s' exists in the database.\n", code)
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
} }
// Check if the code is already used
var exists bool
if multi {
s.server.db.QueryRow(`SELECT COUNT(*) FROM public.campaign_state WHERE code = $1 AND character_id = $2`, pkt.Code, s.charID).Scan(&exists)
} else {
s.server.db.QueryRow(`SELECT COUNT(*) FROM public.campaign_state WHERE code = $1`, pkt.Code).Scan(&exists)
}
if exists {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
s.server.db.Exec(`INSERT INTO public.campaign_state (code, campaign_id, character_id) VALUES ($1, $2, $3)`, pkt.Code, pkt.CampaignID, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateItem) pkt := p.(*mhfpacket.MsgMhfEnumerateItem)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var stamps, amount uint16 var stamps, required, rewardType uint16
var deadline time.Time
err := s.server.db.QueryRow(`SELECT COUNT(*) FROM campaign_state WHERE campaign_id = $1 AND character_id = $2`, pkt.CampaignID, s.charID).Scan(&stamps) err := s.server.db.QueryRow(`SELECT COUNT(*) FROM campaign_state WHERE campaign_id = $1 AND character_id = $2`, pkt.CampaignID, s.charID).Scan(&stamps)
if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return
}
err = s.server.db.QueryRow(`SELECT stamp_amount FROM campaigns WHERE id = $1`, pkt.CampaignID).Scan(&amount)
if err != nil {
doAckBufFail(s, pkt.AckHandle, make([]byte, 4))
return
}
if stamps >= amount {
var items []CampaignEntry
err = s.server.db.Select(&items, `SELECT id,hide,item_type,item_amount,item_no,unk1,unk2,deadline FROM campaign_entries WHERE campaign_id = $1`, pkt.CampaignID)
if err != nil { if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return return
} }
err = s.server.db.QueryRow(`SELECT stamps, reward_type, end_time FROM campaigns WHERE id = $1`, pkt.CampaignID).Scan(&required, &rewardType, &deadline)
if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return
}
if stamps >= required {
var items []CampaignReward
if rewardType == 2 {
var exists int
s.server.db.QueryRow(`SELECT COUNT(*) FROM campaign_quest WHERE campaign_id = $1 AND character_id = $2`, pkt.CampaignID, s.charID).Scan(&exists)
if exists > 0 {
err = s.server.db.Select(&items, `
SELECT id, item_type, quantity, item_id, TO_TIMESTAMP(0) AS deadline FROM campaign_rewards
WHERE campaign_id = $1 AND item_type != 9
AND NOT EXISTS (SELECT 1 FROM campaign_rewards_claimed WHERE reward_id = campaign_rewards.id AND character_id = $2)
`, pkt.CampaignID, s.charID)
} else {
err = s.server.db.Select(&items, `
SELECT cr.id, cr.item_type, cr.quantity, cr.item_id, COALESCE(c.end_time, TO_TIMESTAMP(0)) AS deadline FROM campaign_rewards cr
JOIN campaigns c ON cr.campaign_id = c.id
WHERE campaign_id = $1 AND item_type = 9`, pkt.CampaignID)
}
} else {
err = s.server.db.Select(&items, `
SELECT id, item_type, quantity, item_id, TO_TIMESTAMP(0) AS deadline FROM campaign_rewards
WHERE campaign_id = $1
AND NOT EXISTS (SELECT 1 FROM campaign_rewards_claimed WHERE reward_id = campaign_rewards.id AND character_id = $2)
`, pkt.CampaignID, s.charID)
}
if err != nil {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return
}
bf.WriteUint16(uint16(len(items))) bf.WriteUint16(uint16(len(items)))
for _, item := range items { for _, item := range items {
bf.WriteUint32(item.ID) bf.WriteUint32(item.ID)
bf.WriteBool(item.Hide) bf.WriteUint16(item.ItemType)
bf.WriteUint8(item.ItemType) bf.WriteUint16(item.Quantity)
bf.WriteUint16(item.Amount) bf.WriteUint16(item.ItemID) //HACK:placed quest id in this field to fit with Item No pattern. however it could be another field... possibly the other unks.
bf.WriteUint16(item.ItemNo) //HACK:placed quest id in this field to fit with Item No pattern. however it could be another field... possibly the other unks. bf.WriteUint16(0) //Unk4, gets cast to uint8
bf.WriteUint16(0) //Unk4
bf.WriteUint32(0) //Unk5 bf.WriteUint32(0) //Unk5
bf.WriteUint32(uint32(item.DeadLine.Unix())) bf.WriteUint32(uint32(deadline.Unix()))
} }
if len(items) == 0 { if len(items) == 0 {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
} else { } else {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
@@ -260,6 +276,24 @@ func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfAcquireItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireItem) pkt := p.(*mhfpacket.MsgMhfAcquireItem)
for _, id := range pkt.RewardIDs {
s.server.db.Exec(`INSERT INTO campaign_rewards_claimed (reward_id, character_id) VALUES ($1, $2)`, id, s.charID)
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfTransferItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfTransferItem)
if pkt.ItemType == 9 {
var campaignID uint32
err := s.server.db.QueryRow(`
SELECT ce.campaign_id FROM campaign_rewards ce
JOIN event_quests eq ON ce.item_id = eq.quest_id
WHERE eq.id = $1
`, pkt.QuestID, s.charID).Scan(&campaignID)
if err == nil {
s.server.db.Exec(`INSERT INTO campaign_quest (campaign_id, character_id) VALUES ($1, $2)`, campaignID, s.charID)
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -276,33 +276,27 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) {
bf.WriteUint8(questType) bf.WriteUint8(questType)
if questType == 9 { if questType == 9 {
var stamps int var stamps int
var amount int = 1 var amount = 1
var deadline time.Time var deadline time.Time
err := s.server.db.QueryRow(`SELECT COUNT(*) FROM campaign_state WHERE campaign_id = ( err := s.server.db.QueryRow(`SELECT COUNT(*) FROM campaign_state WHERE campaign_id = (
SELECT campaign_id SELECT campaign_id
FROM campaign_entries FROM campaign_rewards
WHERE item_type = 9 WHERE item_type = 9
AND item_no = $1 AND item_id = $1
) AND character_id = $2`, questId, s.charID).Scan(&stamps) ) AND character_id = $2`, questId, s.charID).Scan(&stamps)
err2 := s.server.db.QueryRow(`SELECT stamp_amount, ( err2 := s.server.db.QueryRow(`SELECT stamps, end_time
SELECT deadline
FROM campaign_entries
WHERE item_type = 9
AND campaign_id = campaigns.id
) AS deadline
FROM campaigns FROM campaigns
WHERE id = ( WHERE id = (
SELECT campaign_id SELECT campaign_id
FROM campaign_entries FROM campaign_rewards
WHERE item_type = 9 WHERE item_type = 9
AND item_no = $1 AND item_id = $1
)`, questId).Scan(&amount, &deadline) )`, questId).Scan(&amount, &deadline)
// Check if there are enough stamps to activate the quest, the deadline hasn't passed, and there are no errors // Check if there are enough stamps to activate the quest, the deadline hasn't passed, and there are no errors
if stamps >= amount && deadline.After(time.Now()) && err == nil && err2 == nil { if stamps >= amount && deadline.After(time.Now()) && err == nil && err2 == nil {
bf.WriteBool(true) bf.WriteBool(true)
} else { } else {
bf.WriteBool(false) bf.WriteBool(false)
} }
} else { } else {
bf.WriteBool(true) bf.WriteBool(true)