Merge branch 'main' into feature/gacha-enum

This commit is contained in:
wish
2023-02-13 22:28:19 +11:00
32 changed files with 767 additions and 587 deletions

View File

@@ -1,15 +1,20 @@
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"
) )
// MsgMhfContractMercenary represents the MSG_MHF_CONTRACT_MERCENARY // MsgMhfContractMercenary represents the MSG_MHF_CONTRACT_MERCENARY
type MsgMhfContractMercenary struct{} type MsgMhfContractMercenary struct {
AckHandle uint32
PactMercID uint32
CID uint32
Op uint8
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfContractMercenary) Opcode() network.PacketID { func (m *MsgMhfContractMercenary) Opcode() network.PacketID {
@@ -18,7 +23,11 @@ func (m *MsgMhfContractMercenary) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfContractMercenary) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfContractMercenary) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.PactMercID = bf.ReadUint32()
m.CID = bf.ReadUint32()
m.Op = bf.ReadUint8()
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -1,15 +1,21 @@
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"
) )
// MsgMhfGetWeeklySeibatuRankingReward represents the MSG_MHF_GET_WEEKLY_SEIBATU_RANKING_REWARD // MsgMhfGetWeeklySeibatuRankingReward represents the MSG_MHF_GET_WEEKLY_SEIBATU_RANKING_REWARD
type MsgMhfGetWeeklySeibatuRankingReward struct{} type MsgMhfGetWeeklySeibatuRankingReward struct {
AckHandle uint32
Unk0 uint32
Unk1 uint32
Unk2 uint32
Unk3 uint32
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfGetWeeklySeibatuRankingReward) Opcode() network.PacketID { func (m *MsgMhfGetWeeklySeibatuRankingReward) Opcode() network.PacketID {
@@ -18,7 +24,12 @@ func (m *MsgMhfGetWeeklySeibatuRankingReward) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfGetWeeklySeibatuRankingReward) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfGetWeeklySeibatuRankingReward) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint32()
m.Unk1 = bf.ReadUint32()
m.Unk2 = bf.ReadUint32()
m.Unk3 = bf.ReadUint32()
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -1,15 +1,18 @@
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"
) )
// MsgMhfPostTinyBin represents the MSG_MHF_POST_TINY_BIN // MsgMhfPostTinyBin represents the MSG_MHF_POST_TINY_BIN
type MsgMhfPostTinyBin struct{} type MsgMhfPostTinyBin struct {
AckHandle uint32
Unk []byte
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfPostTinyBin) Opcode() network.PacketID { func (m *MsgMhfPostTinyBin) Opcode() network.PacketID {
@@ -18,7 +21,9 @@ func (m *MsgMhfPostTinyBin) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfPostTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfPostTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.Unk = bf.ReadBytes(14)
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -1,15 +1,26 @@
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"
) )
// MsgMhfPresentBox represents the MSG_MHF_PRESENT_BOX // MsgMhfPresentBox represents the MSG_MHF_PRESENT_BOX
type MsgMhfPresentBox struct{} type MsgMhfPresentBox struct {
AckHandle uint32
Unk0 uint32
Unk1 uint32
Unk2 uint32
Unk3 uint32
Unk4 uint32
Unk5 uint32
Unk6 uint32
Unk7 uint32
Unk8 uint32
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfPresentBox) Opcode() network.PacketID { func (m *MsgMhfPresentBox) Opcode() network.PacketID {
@@ -18,7 +29,17 @@ func (m *MsgMhfPresentBox) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfPresentBox) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfPresentBox) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint32()
m.Unk1 = bf.ReadUint32()
m.Unk2 = bf.ReadUint32()
m.Unk3 = bf.ReadUint32()
m.Unk4 = bf.ReadUint32()
m.Unk5 = bf.ReadUint32()
m.Unk6 = bf.ReadUint32()
m.Unk7 = bf.ReadUint32()
m.Unk8 = bf.ReadUint32()
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -12,7 +12,7 @@ import (
type MsgMhfReadMercenaryM struct { type MsgMhfReadMercenaryM struct {
AckHandle uint32 AckHandle uint32
CharID uint32 CharID uint32
Unk0 uint32 MercID uint32
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -24,7 +24,7 @@ func (m *MsgMhfReadMercenaryM) Opcode() network.PacketID {
func (m *MsgMhfReadMercenaryM) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfReadMercenaryM) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.CharID = bf.ReadUint32() m.CharID = bf.ReadUint32()
m.Unk0 = bf.ReadUint32() m.MercID = bf.ReadUint32()
return nil return nil
} }

View File

@@ -11,7 +11,7 @@ import (
// MsgMhfReadMercenaryW represents the MSG_MHF_READ_MERCENARY_W // MsgMhfReadMercenaryW represents the MSG_MHF_READ_MERCENARY_W
type MsgMhfReadMercenaryW struct { type MsgMhfReadMercenaryW struct {
AckHandle uint32 AckHandle uint32
Unk0 bool Op uint8
Unk1 uint8 Unk1 uint8
Unk2 uint16 // Hardcoded 0 in the binary Unk2 uint16 // Hardcoded 0 in the binary
} }
@@ -24,7 +24,7 @@ func (m *MsgMhfReadMercenaryW) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfReadMercenaryW) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfReadMercenaryW) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadBool() m.Op = bf.ReadUint8()
m.Unk1 = bf.ReadUint8() m.Unk1 = bf.ReadUint8()
m.Unk2 = bf.ReadUint16() m.Unk2 = bf.ReadUint16()
return nil return nil

View File

@@ -10,11 +10,10 @@ import (
// MsgMhfSaveMercenary represents the MSG_MHF_SAVE_MERCENARY // MsgMhfSaveMercenary represents the MSG_MHF_SAVE_MERCENARY
type MsgMhfSaveMercenary struct { type MsgMhfSaveMercenary struct {
AckHandle uint32 AckHandle uint32
GCP uint32 GCP uint32
Unk0 uint32 PactMercID uint32
MercData []byte MercData []byte
Unk1 uint32
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -27,9 +26,10 @@ func (m *MsgMhfSaveMercenary) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clie
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
bf.ReadUint32() // lenData bf.ReadUint32() // lenData
m.GCP = bf.ReadUint32() m.GCP = bf.ReadUint32()
m.Unk0 = bf.ReadUint32() m.PactMercID = bf.ReadUint32()
m.MercData = bf.ReadBytes(uint(bf.ReadUint32())) dataSize := bf.ReadUint32()
m.Unk1 = bf.ReadUint32() _ = bf.ReadUint32() // Merc index?
m.MercData = bf.ReadBytes(uint(dataSize))
return nil return nil
} }

View File

@@ -0,0 +1,7 @@
BEGIN;
ALTER TABLE IF EXISTS public.guild_characters ADD rp_today INT DEFAULT 0;
ALTER TABLE IF EXISTS public.guild_characters ADD rp_yesterday INT DEFAULT 0;
END;

View File

@@ -0,0 +1,9 @@
BEGIN;
UPDATE characters SET savemercenary = NULL;
ALTER TABLE characters ADD rasta_id INT;
ALTER TABLE characters ADD pact_id INT;
END;

View File

@@ -528,8 +528,6 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
func handleMsgCaExchangeItem(s *Session, p mhfpacket.MHFPacket) {} func handleMsgCaExchangeItem(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfPresentBox(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfServerCommand(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfServerCommand(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfAnnounce(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAnnounce(s *Session, p mhfpacket.MHFPacket) {
@@ -588,10 +586,11 @@ func handleMsgMhfEnumerateUnionItem(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
err := s.server.db.QueryRow("SELECT item_box FROM users, characters WHERE characters.id = $1 AND users.id = characters.user_id", int(s.charID)).Scan(&boxContents) err := s.server.db.QueryRow("SELECT item_box FROM users, characters WHERE characters.id = $1 AND users.id = characters.user_id", int(s.charID)).Scan(&boxContents)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get shared item box contents from db", zap.Error(err)) s.logger.Error("Failed to get shared item box contents from db", zap.Error(err))
bf.WriteBytes(make([]byte, 4))
} else { } else {
if len(boxContents) == 0 { if len(boxContents) == 0 {
bf.WriteUint32(0x00) bf.WriteBytes(make([]byte, 4))
} else { } else {
amount := len(boxContents) / 4 amount := len(boxContents) / 4
bf.WriteUint16(uint16(amount)) bf.WriteUint16(uint16(amount))
@@ -616,7 +615,9 @@ func handleMsgMhfUpdateUnionItem(s *Session, p mhfpacket.MHFPacket) {
err := s.server.db.QueryRow("SELECT item_box FROM users, characters WHERE characters.id = $1 AND users.id = characters.user_id", int(s.charID)).Scan(&boxContents) err := s.server.db.QueryRow("SELECT item_box FROM users, characters WHERE characters.id = $1 AND users.id = characters.user_id", int(s.charID)).Scan(&boxContents)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get shared item box contents from db", zap.Error(err)) s.logger.Error("Failed to get shared item box contents from db", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} else { } else {
amount := len(boxContents) / 4 amount := len(boxContents) / 4
oldItems = make([]Item, amount) oldItems = make([]Item, amount)
@@ -664,9 +665,9 @@ func handleMsgMhfUpdateUnionItem(s *Session, p mhfpacket.MHFPacket) {
// Upload new item cache // Upload new item cache
_, err = s.server.db.Exec("UPDATE users SET item_box = $1 FROM characters WHERE users.id = characters.user_id AND characters.id = $2", bf.Data(), int(s.charID)) _, err = s.server.db.Exec("UPDATE users SET item_box = $1 FROM characters WHERE users.id = characters.user_id AND characters.id = $2", bf.Data(), int(s.charID))
if err != nil { if err != nil {
s.logger.Fatal("Failed to update shared item box contents in db", zap.Error(err)) s.logger.Error("Failed to update shared item box contents in db", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfGetCogInfo(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetCogInfo(s *Session, p mhfpacket.MHFPacket) {}
@@ -1621,7 +1622,7 @@ func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) {
s.QueueAck(pkt.AckHandle, resp.Data()) s.QueueAck(pkt.AckHandle, resp.Data())
*/ */
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckBufSucceed(s, pkt.AckHandle, []byte{})
} }
func handleMsgMhfRegistSpabiTime(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfRegistSpabiTime(s *Session, p mhfpacket.MHFPacket) {}
@@ -1703,14 +1704,6 @@ func handleMsgMhfPostNotice(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetRandFromTable(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetRandFromTable(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetTinyBin(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetTinyBin)
// requested after conquest quests
doAckBufSucceed(s, pkt.AckHandle, []byte{})
}
func handleMsgMhfPostTinyBin(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) {
@@ -1720,45 +1713,6 @@ func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetRyoudama(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetRyoudama)
// likely guild related
// REQ: 00 04 13 53 8F 18 00
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 01 FE 4E
// REQ: 00 06 13 53 8F 18 00
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00
// REQ: 00 05 13 53 8F 18 00
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 0E 2A 15 9E CC 00 00 00 01 82 79 83 4E 83 8A 81 5B 83 69 00 00 00 00 1E 55 B0 2F 00 00 00 01 8D F7 00 00 00 00 00 00 00 00 00 00 00 00 2A 15 9E CC 00 00 00 02 82 79 83 4E 83 8A 81 5B 83 69 00 00 00 00 03 D5 30 56 00 00 00 02 95 BD 91 F2 97 42 00 00 00 00 00 00 00 00 3F 57 76 9F 00 00 00 03 93 56 92 6E 96 B3 97 70 00 00 00 00 00 00 38 D9 0E C4 00 00 00 03 87 64 83 78 83 42 00 00 00 00 00 00 00 00 23 F3 B9 77 00 00 00 04 82 B3 82 CC 82 DC 82 E9 81 99 00 00 00 00 3F 1B 17 9C 00 00 00 04 82 B1 82 A4 82 BD 00 00 00 00 00 00 00 00 00 B9 F9 C0 00 00 00 05 82 CD 82 E9 82 A9 00 00 00 00 00 00 00 00 23 9F 9A EA 00 00 00 05 83 70 83 62 83 4C 83 83 83 49 00 00 00 00 38 D9 0E C4 00 00 00 06 87 64 83 78 83 42 00 00 00 00 00 00 00 00 1E 55 B0 2F 00 00 00 06 8D F7 00 00 00 00 00 00 00 00 00 00 00 00 03 D5 30 56 00 00 00 07 95 BD 91 F2 97 42 00 00 00 00 00 00 00 00 02 D3 B8 77 00 00 00 07 6F 77 6C 32 35 32 35 00 00 00 00 00 00 00
data, _ := hex.DecodeString("0A218EAD0000000000000000000000010000000000000000")
doAckBufSucceed(s, pkt.AckHandle, data)
}
func handleMsgMhfPostRyoudama(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
// if the game gets bad responses for this it breaks the ability to save
pkt := p.(*mhfpacket.MsgMhfGetTenrouirai)
var data []byte
var err error
if pkt.Unk0 == 1 {
data, err = hex.DecodeString("0A218EAD000000000000000000000001010000000000060010")
} else if pkt.Unk2 == 4 {
data, err = hex.DecodeString("0A218EAD0000000000000000000000210101005000000202010102020104001000000202010102020106003200000202010002020104000C003202020101020201030032000002020101020202059C4000000202010002020105C35000320202010102020201003C00000202010102020203003200000201010001020203002800320201010101020204000C00000201010101020206002800000201010001020101003C00320201020101020105C35000000301020101020106003200000301020001020104001000320301020101020105C350000003010201010202030028000003010200010201030032003203010201010202059C4000000301020101010206002800000301020001010201003C00320301020101010206003200000301020101010204000C000003010200010101010050003203010201010101059C40000003010201010101030032000003010200010101040010003203010001010101060032000003010001010102030028000003010001010101010050003203010000010102059C4000000301000001010206002800000301000001010010")
} else {
data = []byte{0x00, 0x00, 0x00, 0x00}
s.logger.Info("GET_TENROUIRAI request for unknown type")
}
if err != nil {
panic(err)
}
doAckBufSucceed(s, pkt.AckHandle, data)
}
func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPostTenrouirai)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
}
func handleMsgMhfGetDailyMissionMaster(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetDailyMissionMaster(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {}
@@ -1774,7 +1728,8 @@ func handleMsgMhfGetEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT COALESCE(skin_hist::bytea, $2::bytea) FROM characters WHERE id = $1", s.charID, make([]byte, 0xC80)).Scan(&data) err := s.server.db.QueryRow("SELECT COALESCE(skin_hist::bytea, $2::bytea) FROM characters WHERE id = $1", s.charID, make([]byte, 0xC80)).Scan(&data)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get skin_hist savedata from db", zap.Error(err)) s.logger.Error("Failed to load skin_hist", zap.Error(err))
data = make([]byte, 3200)
} }
doAckBufSucceed(s, pkt.AckHandle, data) doAckBufSucceed(s, pkt.AckHandle, data)
} }
@@ -1785,7 +1740,9 @@ func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT COALESCE(skin_hist, $2) FROM characters WHERE id = $1", s.charID, make([]byte, 0xC80)).Scan(&data) err := s.server.db.QueryRow("SELECT COALESCE(skin_hist, $2) FROM characters WHERE id = $1", s.charID, make([]byte, 0xC80)).Scan(&data)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get skin_hist from db", zap.Error(err)) s.logger.Error("Failed to save skin_hist", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return
} }
var bit int var bit int
@@ -1834,8 +1791,8 @@ func handleMsgMhfGetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) {
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT minidata FROM characters WHERE id = $1", pkt.CharID).Scan(&data) err := s.server.db.QueryRow("SELECT minidata FROM characters WHERE id = $1", pkt.CharID).Scan(&data)
if err != nil { if err != nil {
data = make([]byte, 0x400) // returning empty might avoid a client softlock s.logger.Error("Failed to load minidata")
//s.logger.Fatal("Failed to get minidata from db", zap.Error(err)) data = make([]byte, 1)
} }
doAckBufSucceed(s, pkt.AckHandle, data) doAckBufSucceed(s, pkt.AckHandle, data)
} }
@@ -1845,7 +1802,7 @@ func handleMsgMhfSetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) {
dumpSaveData(s, pkt.RawDataPayload, "minidata") dumpSaveData(s, pkt.RawDataPayload, "minidata")
_, err := s.server.db.Exec("UPDATE characters SET minidata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err := s.server.db.Exec("UPDATE characters SET minidata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update minidata in db", zap.Error(err)) s.logger.Error("Failed to save minidata", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }

View File

@@ -15,7 +15,7 @@ func handleMsgMhfAcquireCafeItem(s *Session, p mhfpacket.MHFPacket) {
var netcafePoints uint32 var netcafePoints uint32
err := s.server.db.QueryRow("UPDATE characters SET netcafe_points = netcafe_points - $1 WHERE id = $2 RETURNING netcafe_points", pkt.PointCost, s.charID).Scan(&netcafePoints) err := s.server.db.QueryRow("UPDATE characters SET netcafe_points = netcafe_points - $1 WHERE id = $2 RETURNING netcafe_points", pkt.PointCost, s.charID).Scan(&netcafePoints)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get netcafe points from db", zap.Error(err)) s.logger.Error("Failed to get netcafe points from db", zap.Error(err))
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(netcafePoints) resp.WriteUint32(netcafePoints)
@@ -27,7 +27,7 @@ func handleMsgMhfUpdateCafepoint(s *Session, p mhfpacket.MHFPacket) {
var netcafePoints uint32 var netcafePoints uint32
err := s.server.db.QueryRow("SELECT COALESCE(netcafe_points, 0) FROM characters WHERE id = $1", s.charID).Scan(&netcafePoints) err := s.server.db.QueryRow("SELECT COALESCE(netcafe_points, 0) FROM characters WHERE id = $1", s.charID).Scan(&netcafePoints)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get netcate points from db", zap.Error(err)) s.logger.Error("Failed to get netcate points from db", zap.Error(err))
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(netcafePoints) resp.WriteUint32(netcafePoints)
@@ -49,7 +49,7 @@ func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
var dailyTime time.Time var dailyTime time.Time
err := s.server.db.QueryRow("SELECT COALESCE(daily_time, $2) FROM characters WHERE id = $1", s.charID, time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)).Scan(&dailyTime) err := s.server.db.QueryRow("SELECT COALESCE(daily_time, $2) FROM characters WHERE id = $1", s.charID, time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)).Scan(&dailyTime)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get daily_time savedata from db", zap.Error(err)) s.logger.Error("Failed to get daily_time savedata from db", zap.Error(err))
} }
var bondBonus, bonusQuests, dailyQuests uint32 var bondBonus, bonusQuests, dailyQuests uint32

View File

@@ -1,9 +1,36 @@
package channelserver package channelserver
import ( import (
"encoding/hex"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
) )
func handleMsgMhfGetRyoudama(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetRyoudama)
// likely guild related
// REQ: 00 04 13 53 8F 18 00
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 01 FE 4E
// REQ: 00 06 13 53 8F 18 00
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00
// REQ: 00 05 13 53 8F 18 00
// RSP: 0A 21 8E AD 00 00 00 00 00 00 00 00 00 00 00 0E 2A 15 9E CC 00 00 00 01 82 79 83 4E 83 8A 81 5B 83 69 00 00 00 00 1E 55 B0 2F 00 00 00 01 8D F7 00 00 00 00 00 00 00 00 00 00 00 00 2A 15 9E CC 00 00 00 02 82 79 83 4E 83 8A 81 5B 83 69 00 00 00 00 03 D5 30 56 00 00 00 02 95 BD 91 F2 97 42 00 00 00 00 00 00 00 00 3F 57 76 9F 00 00 00 03 93 56 92 6E 96 B3 97 70 00 00 00 00 00 00 38 D9 0E C4 00 00 00 03 87 64 83 78 83 42 00 00 00 00 00 00 00 00 23 F3 B9 77 00 00 00 04 82 B3 82 CC 82 DC 82 E9 81 99 00 00 00 00 3F 1B 17 9C 00 00 00 04 82 B1 82 A4 82 BD 00 00 00 00 00 00 00 00 00 B9 F9 C0 00 00 00 05 82 CD 82 E9 82 A9 00 00 00 00 00 00 00 00 23 9F 9A EA 00 00 00 05 83 70 83 62 83 4C 83 83 83 49 00 00 00 00 38 D9 0E C4 00 00 00 06 87 64 83 78 83 42 00 00 00 00 00 00 00 00 1E 55 B0 2F 00 00 00 06 8D F7 00 00 00 00 00 00 00 00 00 00 00 00 03 D5 30 56 00 00 00 07 95 BD 91 F2 97 42 00 00 00 00 00 00 00 00 02 D3 B8 77 00 00 00 07 6F 77 6C 32 35 32 35 00 00 00 00 00 00 00
data, _ := hex.DecodeString("0A218EAD0000000000000000000000010000000000000000")
doAckBufSucceed(s, pkt.AckHandle, data)
}
func handleMsgMhfPostRyoudama(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetTinyBin(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetTinyBin)
// requested after conquest quests
doAckBufSucceed(s, pkt.AckHandle, []byte{})
}
func handleMsgMhfPostTinyBin(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPostTinyBin)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfCaravanMyScore(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfCaravanMyScore(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -53,7 +53,7 @@ func init() {
} }
func sendDisabledCommandMessage(s *Session, cmd config.Command) { func sendDisabledCommandMessage(s *Session, cmd config.Command) {
sendServerChatMessage(s, fmt.Sprintf("%s command is disabled", cmd.Name)) sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandDisabled"], cmd.Name))
} }
func sendServerChatMessage(s *Session, message string) { func sendServerChatMessage(s *Session, message string) {
@@ -78,6 +78,233 @@ func sendServerChatMessage(s *Session, message string) {
s.QueueSendMHF(castedBin) s.QueueSendMHF(castedBin)
} }
func parseChatCommand(s *Session, command string) {
if strings.HasPrefix(command, commands["Reload"].Prefix) {
// Flush all objects and users and reload
if commands["Reload"].Enabled {
sendServerChatMessage(s, s.server.dict["commandReload"])
var temp mhfpacket.MHFPacket
deleteNotif := byteframe.NewByteFrame()
for _, object := range s.stage.objects {
if object.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysDeleteUser{CharID: session.charID}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
deleteNotif.WriteUint16(0x0010)
s.QueueSend(deleteNotif.Data())
time.Sleep(500 * time.Millisecond)
reloadNotif := byteframe.NewByteFrame()
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: session.charID,
BinaryType: uint8(i + 1),
}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
}
for _, obj := range s.stage.objects {
if obj.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDuplicateObject{
ObjID: obj.id,
X: obj.x,
Y: obj.y,
Z: obj.z,
Unk0: 0,
OwnerCharID: obj.ownerCharID,
}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
reloadNotif.WriteUint16(0x0010)
s.QueueSend(reloadNotif.Data())
} else {
sendDisabledCommandMessage(s, commands["Reload"])
}
}
if strings.HasPrefix(command, commands["KeyQuest"].Prefix) {
if commands["KeyQuest"].Enabled {
if strings.HasPrefix(command, fmt.Sprintf("%s get", commands["KeyQuest"].Prefix)) {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandKqfGet"], s.kqf))
} else if strings.HasPrefix(command, fmt.Sprintf("%s set", commands["KeyQuest"].Prefix)) {
var hexs string
n, numerr := fmt.Sscanf(command, fmt.Sprintf("%s set %%s", commands["KeyQuest"].Prefix), &hexs)
if numerr != nil || n != 1 || len(hexs) != 16 {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandKqfSetError"], commands["KeyQuest"].Prefix))
} else {
hexd, _ := hex.DecodeString(hexs)
s.kqf = hexd
s.kqfOverride = true
sendServerChatMessage(s, s.server.dict["commandKqfSetSuccess"])
}
}
} else {
sendDisabledCommandMessage(s, commands["KeyQuest"])
}
}
if strings.HasPrefix(command, commands["Rights"].Prefix) {
// Set account rights
if commands["Rights"].Enabled {
var v uint32
n, err := fmt.Sscanf(command, fmt.Sprintf("%s %%d", commands["Rights"].Prefix), &v)
if err != nil || n != 1 {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRightsError"], commands["Rights"].Prefix))
} else {
_, err = s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID)
if err == nil {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRightsSuccess"], v))
}
}
} else {
sendDisabledCommandMessage(s, commands["Rights"])
}
}
if strings.HasPrefix(command, commands["Course"].Prefix) {
if commands["Course"].Enabled {
var name string
n, err := fmt.Sscanf(command, fmt.Sprintf("%s %%s", commands["Course"].Prefix), &name)
if err != nil || n != 1 {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseError"], commands["Course"].Prefix))
} else {
name = strings.ToLower(name)
for _, course := range mhfpacket.Courses() {
for _, alias := range course.Aliases {
if strings.ToLower(name) == strings.ToLower(alias) {
if slices.Contains(s.server.erupeConfig.Courses, config.Course{Name: course.Aliases[0], Enabled: true}) {
if s.FindCourse(name).ID != 0 {
ei := slices.IndexFunc(s.courses, func(c mhfpacket.Course) bool {
for _, alias := range c.Aliases {
if strings.ToLower(name) == strings.ToLower(alias) {
return true
}
}
return false
})
if ei != -1 {
s.courses = append(s.courses[:ei], s.courses[ei+1:]...)
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseDisabled"], course.Aliases[0]))
}
} else {
s.courses = append(s.courses, course)
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseEnabled"], course.Aliases[0]))
}
var newInt uint32
for _, course := range s.courses {
newInt += uint32(math.Pow(2, float64(course.ID)))
}
s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", newInt, s.charID)
updateRights(s)
} else {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseLocked"], course.Aliases[0]))
}
}
}
}
}
} else {
sendDisabledCommandMessage(s, commands["Course"])
}
}
if strings.HasPrefix(command, commands["Raviente"].Prefix) {
if commands["Raviente"].Enabled {
if getRaviSemaphore(s.server) != nil {
s.server.raviente.Lock()
if !strings.HasPrefix(command, "!ravi ") {
sendServerChatMessage(s, s.server.dict["commandRaviNoCommand"])
} else {
if strings.HasPrefix(command, "!ravi start") {
if s.server.raviente.register.startTime == 0 {
s.server.raviente.register.startTime = s.server.raviente.register.postTime
sendServerChatMessage(s, s.server.dict["commandRaviStartSuccess"])
s.notifyRavi()
} else {
sendServerChatMessage(s, s.server.dict["commandRaviStartError"])
}
} else if strings.HasPrefix(command, "!ravi cm") || strings.HasPrefix(command, "!ravi checkmultiplier") {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRaviMultiplier"], s.server.raviente.GetRaviMultiplier(s.server)))
} else if strings.HasPrefix(command, "!ravi sr") || strings.HasPrefix(command, "!ravi sendres") {
if s.server.raviente.state.stateData[28] > 0 {
sendServerChatMessage(s, s.server.dict["commandRaviResSuccess"])
s.server.raviente.state.stateData[28] = 0
} else {
sendServerChatMessage(s, s.server.dict["commandRaviResError"])
}
} else if strings.HasPrefix(command, "!ravi ss") || strings.HasPrefix(command, "!ravi sendsed") {
sendServerChatMessage(s, s.server.dict["commandRaviSedSuccess"])
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP
} else if strings.HasPrefix(command, "!ravi rs") || strings.HasPrefix(command, "!ravi reqsed") {
sendServerChatMessage(s, s.server.dict["commandRaviRequest"])
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP + 12
} else {
sendServerChatMessage(s, s.server.dict["commandRaviError"])
}
}
s.server.raviente.Unlock()
} else {
sendServerChatMessage(s, s.server.dict["commandRaviNoPlayers"])
}
} else {
sendDisabledCommandMessage(s, commands["Raviente"])
}
}
if strings.HasPrefix(command, commands["Teleport"].Prefix) {
if commands["Teleport"].Enabled {
var x, y int16
n, err := fmt.Sscanf(command, fmt.Sprintf("%s %%d %%d", commands["Teleport"].Prefix), &x, &y)
if err != nil || n != 2 {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandTeleportError"], commands["Teleport"].Prefix))
} else {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandTeleportSuccess"], x, y))
// Make the inside of the casted binary
payload := byteframe.NewByteFrame()
payload.SetLE()
payload.WriteUint8(2) // SetState type(position == 2)
payload.WriteInt16(x) // X
payload.WriteInt16(y) // Y
payloadBytes := payload.Data()
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
CharID: s.charID,
MessageType: BinaryMessageTypeState,
RawDataPayload: payloadBytes,
})
}
} else {
sendDisabledCommandMessage(s, commands["Teleport"])
}
}
}
func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysCastBinary) pkt := p.(*mhfpacket.MsgSysCastBinary)
tmp := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) tmp := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
@@ -144,6 +371,18 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
roll.WriteNullTerminatedBytes([]byte(dice)) roll.WriteNullTerminatedBytes([]byte(dice))
roll.WriteNullTerminatedBytes(tmp.ReadNullTerminatedBytes()) roll.WriteNullTerminatedBytes(tmp.ReadNullTerminatedBytes())
realPayload = roll.Data() realPayload = roll.Data()
} else {
bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
bf.SetLE()
chatMessage := &binpacket.MsgBinChat{}
chatMessage.Parse(bf)
if strings.HasPrefix(chatMessage.Message, "!") {
parseChatCommand(s, chatMessage.Message)
return
}
if (pkt.BroadcastType == BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == BroadcastTypeWorld {
s.server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message)
}
} }
} }
@@ -167,8 +406,7 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
} }
case BroadcastTypeServer: case BroadcastTypeServer:
if pkt.MessageType == 1 { if pkt.MessageType == 1 {
raviSema := getRaviSemaphore(s) if getRaviSemaphore(s.server) != nil {
if raviSema != "" {
s.server.BroadcastMHF(resp, s) s.server.BroadcastMHF(resp, s)
} }
} else { } else {
@@ -190,266 +428,6 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
} }
s.Unlock() s.Unlock()
} }
// Handle chat
if pkt.MessageType == BinaryMessageTypeChat {
bf := byteframe.NewByteFrameFromBytes(realPayload)
// IMPORTANT! Casted binary objects are sent _as they are in memory_,
// this means little endian for LE CPUs, might be different for PS3/PS4/PSP/XBOX.
bf.SetLE()
chatMessage := &binpacket.MsgBinChat{}
chatMessage.Parse(bf)
fmt.Printf("Got chat message: %+v\n", chatMessage)
// Discord integration
if (pkt.BroadcastType == BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == BroadcastTypeWorld {
s.server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message)
}
if strings.HasPrefix(chatMessage.Message, commands["Reload"].Prefix) {
// Flush all objects and users and reload
if commands["Reload"].Enabled {
sendServerChatMessage(s, "Reloading players...")
var temp mhfpacket.MHFPacket
deleteNotif := byteframe.NewByteFrame()
for _, object := range s.stage.objects {
if object.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysDeleteUser{CharID: session.charID}
deleteNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(deleteNotif, s.clientContext)
}
deleteNotif.WriteUint16(0x0010)
s.QueueSend(deleteNotif.Data())
time.Sleep(500 * time.Millisecond)
reloadNotif := byteframe.NewByteFrame()
for _, session := range s.server.sessions {
if s == session {
continue
}
temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: session.charID,
BinaryType: uint8(i + 1),
}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
}
for _, obj := range s.stage.objects {
if obj.ownerCharID == s.charID {
continue
}
temp = &mhfpacket.MsgSysDuplicateObject{
ObjID: obj.id,
X: obj.x,
Y: obj.y,
Z: obj.z,
Unk0: 0,
OwnerCharID: obj.ownerCharID,
}
reloadNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(reloadNotif, s.clientContext)
}
reloadNotif.WriteUint16(0x0010)
s.QueueSend(reloadNotif.Data())
} else {
sendDisabledCommandMessage(s, commands["Reload"])
}
}
if strings.HasPrefix(chatMessage.Message, commands["KeyQuest"].Prefix) {
if commands["KeyQuest"].Enabled {
if strings.HasPrefix(chatMessage.Message, "!kqf get") {
sendServerChatMessage(s, fmt.Sprintf("KQF: %x", s.kqf))
} else if strings.HasPrefix(chatMessage.Message, "!kqf set") {
var hexs string
n, numerr := fmt.Sscanf(chatMessage.Message, "!kqf set %s", &hexs)
if numerr != nil || n != 1 || len(hexs) != 16 {
sendServerChatMessage(s, "Error in command. Format: !kqf set xxxxxxxxxxxxxxxx")
} else {
hexd, _ := hex.DecodeString(hexs)
s.kqf = hexd
s.kqfOverride = true
sendServerChatMessage(s, "KQF set, please switch Land/World")
}
}
} else {
sendDisabledCommandMessage(s, commands["KeyQuest"])
}
}
if strings.HasPrefix(chatMessage.Message, commands["Rights"].Prefix) {
// Set account rights
if commands["Rights"].Enabled {
var v uint32
n, err := fmt.Sscanf(chatMessage.Message, "!rights %d", &v)
if err != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !rights n")
} else {
_, err = s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID)
if err == nil {
sendServerChatMessage(s, fmt.Sprintf("Set rights integer: %d", v))
}
}
} else {
sendDisabledCommandMessage(s, commands["Rights"])
}
}
if strings.HasPrefix(chatMessage.Message, commands["Course"].Prefix) {
if commands["Course"].Enabled {
var name string
n, err := fmt.Sscanf(chatMessage.Message, "!course %s", &name)
if err != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !course <name>")
} else {
name = strings.ToLower(name)
for _, course := range mhfpacket.Courses() {
for _, alias := range course.Aliases {
if strings.ToLower(name) == strings.ToLower(alias) {
if slices.Contains(s.server.erupeConfig.Courses, config.Course{Name: course.Aliases[0], Enabled: true}) {
if s.FindCourse(name).ID != 0 {
ei := slices.IndexFunc(s.courses, func(c mhfpacket.Course) bool {
for _, alias := range c.Aliases {
if strings.ToLower(name) == strings.ToLower(alias) {
return true
}
}
return false
})
if ei != -1 {
s.courses = append(s.courses[:ei], s.courses[ei+1:]...)
sendServerChatMessage(s, fmt.Sprintf(`%s Course disabled`, course.Aliases[0]))
}
} else {
s.courses = append(s.courses, course)
sendServerChatMessage(s, fmt.Sprintf(`%s Course enabled`, course.Aliases[0]))
}
var newInt uint32
for _, course := range s.courses {
newInt += uint32(math.Pow(2, float64(course.ID)))
}
s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", newInt, s.charID)
updateRights(s)
} else {
sendServerChatMessage(s, fmt.Sprintf(`%s Course is locked`, course.Aliases[0]))
}
}
}
}
}
} else {
sendDisabledCommandMessage(s, commands["Course"])
}
}
if strings.HasPrefix(chatMessage.Message, commands["Raviente"].Prefix) {
if commands["Raviente"].Enabled {
if getRaviSemaphore(s) != "" {
s.server.raviente.Lock()
if !strings.HasPrefix(chatMessage.Message, "!ravi ") {
sendServerChatMessage(s, "No Raviente command specified!")
} else {
if strings.HasPrefix(chatMessage.Message, "!ravi start") {
if s.server.raviente.register.startTime == 0 {
s.server.raviente.register.startTime = s.server.raviente.register.postTime
sendServerChatMessage(s, "The Great Slaying will begin in a moment")
s.notifyRavi()
} else {
sendServerChatMessage(s, "The Great Slaying has already begun!")
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi sm") || strings.HasPrefix(chatMessage.Message, "!ravi setmultiplier") {
var num uint16
n, numerr := fmt.Sscanf(chatMessage.Message, "!ravi sm %d", &num)
if numerr != nil || n != 1 {
sendServerChatMessage(s, "Error in command. Format: !ravi sm n")
} else if s.server.raviente.state.damageMultiplier == 1 {
if num > 32 {
sendServerChatMessage(s, "Raviente multiplier too high, defaulting to 32x")
s.server.raviente.state.damageMultiplier = 32
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier set to %dx", num))
s.server.raviente.state.damageMultiplier = uint32(num)
}
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is already set to %dx!", s.server.raviente.state.damageMultiplier))
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi cm") || strings.HasPrefix(chatMessage.Message, "!ravi checkmultiplier") {
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is currently %dx", s.server.raviente.state.damageMultiplier))
} else if strings.HasPrefix(chatMessage.Message, "!ravi sr") || strings.HasPrefix(chatMessage.Message, "!ravi sendres") {
if s.server.raviente.state.stateData[28] > 0 {
sendServerChatMessage(s, "Sending resurrection support!")
s.server.raviente.state.stateData[28] = 0
} else {
sendServerChatMessage(s, "Resurrection support has not been requested!")
}
} else if strings.HasPrefix(chatMessage.Message, "!ravi ss") || strings.HasPrefix(chatMessage.Message, "!ravi sendsed") {
sendServerChatMessage(s, "Sending sedation support if requested!")
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP
} else if strings.HasPrefix(chatMessage.Message, "!ravi rs") || strings.HasPrefix(chatMessage.Message, "!ravi reqsed") {
sendServerChatMessage(s, "Requesting sedation support!")
// Total BerRavi HP
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
s.server.raviente.support.supportData[1] = HP + 12
} else {
sendServerChatMessage(s, "Raviente command not recognised!")
}
}
s.server.raviente.Unlock()
} else {
sendServerChatMessage(s, "No one has joined the Great Slaying!")
}
} else {
sendDisabledCommandMessage(s, commands["Raviente"])
}
}
if strings.HasPrefix(chatMessage.Message, commands["Teleport"].Prefix) {
if commands["Teleport"].Enabled {
var x, y int16
n, err := fmt.Sscanf(chatMessage.Message, "!tele %d %d", &x, &y)
if err != nil || n != 2 {
sendServerChatMessage(s, "Invalid command. Usage:\"!tele 500 500\"")
} else {
sendServerChatMessage(s, fmt.Sprintf("Teleporting to %d %d", x, y))
// Make the inside of the casted binary
payload := byteframe.NewByteFrame()
payload.SetLE()
payload.WriteUint8(2) // SetState type(position == 2)
payload.WriteInt16(x) // X
payload.WriteInt16(y) // Y
payloadBytes := payload.Data()
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
CharID: s.charID,
MessageType: BinaryMessageTypeState,
RawDataPayload: payloadBytes,
})
}
} else {
sendDisabledCommandMessage(s, commands["Teleport"])
}
}
}
} }
func handleMsgSysCastedBinary(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysCastedBinary(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -2,6 +2,7 @@ package channelserver
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"erupe-ce/common/bfutil" "erupe-ce/common/bfutil"
"erupe-ce/common/stringsupport" "erupe-ce/common/stringsupport"
@@ -58,6 +59,7 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error)
} }
defer result.Close() defer result.Close()
if !result.Next() { if !result.Next() {
err = errors.New("no savedata found")
s.logger.Error("No savedata found", zap.Uint32("charID", charID)) s.logger.Error("No savedata found", zap.Uint32("charID", charID))
return nil, err return nil, err
} }

View File

@@ -29,7 +29,9 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
// diffs themselves are also potentially compressed // diffs themselves are also potentially compressed
diff, err := nullcomp.Decompress(pkt.RawDataPayload) diff, err := nullcomp.Decompress(pkt.RawDataPayload)
if err != nil { if err != nil {
s.logger.Fatal("Failed to decompress diff", zap.Error(err)) s.logger.Error("Failed to decompress diff", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} }
// Perform diff. // Perform diff.
s.logger.Info("Diffing...") s.logger.Info("Diffing...")
@@ -39,7 +41,9 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
// Regular blob update. // Regular blob update.
saveData, err := nullcomp.Decompress(pkt.RawDataPayload) saveData, err := nullcomp.Decompress(pkt.RawDataPayload)
if err != nil { if err != nil {
s.logger.Fatal("Failed to decompress savedata from packet", zap.Error(err)) s.logger.Error("Failed to decompress savedata from packet", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} }
s.logger.Info("Updating save with blob") s.logger.Info("Updating save with blob")
characterSaveData.decompSave = saveData characterSaveData.decompSave = saveData
@@ -64,9 +68,9 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
} }
_, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterSaveData.Name, s.charID) _, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterSaveData.Name, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update character name in db", zap.Error(err)) s.logger.Error("Failed to update character name in db", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func grpToGR(n uint32) uint16 { func grpToGR(n uint32) uint16 {
@@ -236,7 +240,7 @@ func dumpSaveData(s *Session, data []byte, suffix string) {
_, err := os.Stat(dir) _, err := os.Stat(dir)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
err = os.Mkdir(dir, os.ModeDir) err = os.Mkdir(dir, os.ModePerm)
if err != nil { if err != nil {
s.logger.Warn("Error dumping savedata, could not create folder") s.logger.Warn("Error dumping savedata, could not create folder")
return return
@@ -288,15 +292,9 @@ func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) {
dumpSaveData(s, pkt.RawDataPayload, "scenario") dumpSaveData(s, pkt.RawDataPayload, "scenario")
_, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE id = $2", pkt.RawDataPayload, s.charID) _, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE id = $2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update scenario data in db", zap.Error(err)) s.logger.Error("Failed to update scenario data in db", zap.Error(err))
} }
// Do this ack manually because it uses a non-(0|1) error code doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
s.QueueSendMHF(&mhfpacket.MsgSysAck{
AckHandle: pkt.AckHandle,
IsBufferResponse: false,
ErrorCode: 0x40,
AckData: []byte{0x00, 0x00, 0x00, 0x40},
})
} }
func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) {
@@ -305,13 +303,10 @@ func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE id = $1", s.charID).Scan(&scenarioData) err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE id = $1", s.charID).Scan(&scenarioData)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get scenario data contents in db", zap.Error(err)) s.logger.Error("Failed to load scenariodata", zap.Error(err))
bf.WriteBytes(make([]byte, 10))
} else { } else {
if len(scenarioData) == 0 { bf.WriteBytes(scenarioData)
bf.WriteUint32(0x00)
} else {
bf.WriteBytes(scenarioData)
}
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }

View File

@@ -94,6 +94,35 @@ func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) {
return return
} }
if len(dist.Data) >= 2 {
distData := byteframe.NewByteFrameFromBytes(dist.Data)
distItems := int(distData.ReadUint16())
for i := 0; i < distItems; i++ {
if len(dist.Data) >= 2+(i*13) {
itemType := distData.ReadUint8()
_ = distData.ReadBytes(6)
quantity := int(distData.ReadUint16())
_ = distData.ReadBytes(4)
switch itemType {
case 17:
_ = addPointNetcafe(s, quantity)
case 19:
s.server.db.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", quantity, s.charID)
case 20:
s.server.db.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", quantity, s.charID)
case 21:
s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", quantity, s.charID)
case 23:
saveData, err := GetCharacterSaveData(s, s.charID)
if err == nil {
saveData.RP += uint16(quantity)
saveData.Save(s)
}
}
}
}
}
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(pkt.DistributionID) bf.WriteUint32(pkt.DistributionID)
bf.WriteBytes(dist.Data) bf.WriteBytes(dist.Data)

View File

@@ -736,7 +736,10 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
// TODO: This doesn't implement blocking, if someone unlocked the same outfit at the same time // TODO: This doesn't implement blocking, if someone unlocked the same outfit at the same time
s.server.db.Exec(`UPDATE guilds SET pugi_outfits=pugi_outfits+$1 WHERE id=$2`, int(math.Pow(float64(pkt.Data1.ReadUint32()), 2)), guild.ID) s.server.db.Exec(`UPDATE guilds SET pugi_outfits=pugi_outfits+$1 WHERE id=$2`, int(math.Pow(float64(pkt.Data1.ReadUint32()), 2)), guild.ID)
case mhfpacket.OPERATE_GUILD_DONATE_EVENT: case mhfpacket.OPERATE_GUILD_DONATE_EVENT:
bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, true)) quantity := uint16(pkt.Data1.ReadUint32())
bf.WriteBytes(handleDonateRP(s, quantity, guild, true))
// TODO: Move this value onto rp_yesterday and reset to 0... daily?
s.server.db.Exec(`UPDATE guild_characters SET rp_today=rp_today+$1 WHERE character_id=$2`, quantity, s.charID)
case mhfpacket.OPERATE_GUILD_EVENT_EXCHANGE: case mhfpacket.OPERATE_GUILD_EVENT_EXCHANGE:
rp := uint16(pkt.Data1.ReadUint32()) rp := uint16(pkt.Data1.ReadUint32())
var balance uint32 var balance uint32
@@ -1443,8 +1446,9 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(0) bf.WriteUint16(0)
} }
for range guildMembers { for _, member := range guildMembers {
bf.WriteUint32(0x00) // Unk bf.WriteUint16(member.RPToday)
bf.WriteUint16(member.RPYesterday)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
@@ -1531,10 +1535,11 @@ func handleMsgMhfEnumerateGuildItem(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
err := s.server.db.QueryRow("SELECT item_box FROM guilds WHERE id = $1", int(pkt.GuildId)).Scan(&boxContents) err := s.server.db.QueryRow("SELECT item_box FROM guilds WHERE id = $1", int(pkt.GuildId)).Scan(&boxContents)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get guild item box contents from db", zap.Error(err)) s.logger.Error("Failed to get guild item box contents from db", zap.Error(err))
bf.WriteBytes(make([]byte, 4))
} else { } else {
if len(boxContents) == 0 { if len(boxContents) == 0 {
bf.WriteUint32(0x00) bf.WriteBytes(make([]byte, 4))
} else { } else {
amount := len(boxContents) / 4 amount := len(boxContents) / 4
bf.WriteUint16(uint16(amount)) bf.WriteUint16(uint16(amount))
@@ -1564,7 +1569,9 @@ func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) {
var oldItems []Item var oldItems []Item
err := s.server.db.QueryRow("SELECT item_box FROM guilds WHERE id = $1", int(pkt.GuildId)).Scan(&boxContents) err := s.server.db.QueryRow("SELECT item_box FROM guilds WHERE id = $1", int(pkt.GuildId)).Scan(&boxContents)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get guild item box contents from db", zap.Error(err)) s.logger.Error("Failed to get guild item box contents from db", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} else { } else {
amount := len(boxContents) / 4 amount := len(boxContents) / 4
oldItems = make([]Item, amount) oldItems = make([]Item, amount)
@@ -1612,7 +1619,7 @@ func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) {
// Upload new item cache // Upload new item cache
_, err = s.server.db.Exec("UPDATE guilds SET item_box = $1 WHERE id = $2", bf.Data(), int(pkt.GuildId)) _, err = s.server.db.Exec("UPDATE guilds SET item_box = $1 WHERE id = $2", bf.Data(), int(pkt.GuildId))
if err != nil { if err != nil {
s.logger.Fatal("Failed to update guild item box contents in db", zap.Error(err)) s.logger.Error("Failed to update guild item box contents in db", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
@@ -1737,7 +1744,8 @@ func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
guild, _ := GetGuildInfoByCharacterId(s, s.charID) guild, _ := GetGuildInfoByCharacterId(s, s.charID)
data, err := s.server.db.Queryx("SELECT id, meal_id, level, expires FROM guild_meals WHERE guild_id = $1", guild.ID) data, err := s.server.db.Queryx("SELECT id, meal_id, level, expires FROM guild_meals WHERE guild_id = $1", guild.ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get guild meals from db", zap.Error(err)) s.logger.Error("Failed to get guild meals from db", zap.Error(err))
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
} }
temp := byteframe.NewByteFrame() temp := byteframe.NewByteFrame()
count := 0 count := 0
@@ -1745,7 +1753,7 @@ func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
mealData := &GuildMeal{} mealData := &GuildMeal{}
err = data.StructScan(&mealData) err = data.StructScan(&mealData)
if err != nil { if err != nil {
s.logger.Fatal("Failed to scan meal data", zap.Error(err)) continue
} }
if mealData.Expires > uint32(Time_Current_Adjusted().Add(-60*time.Minute).Unix()) { if mealData.Expires > uint32(Time_Current_Adjusted().Add(-60*time.Minute).Unix()) {
count++ count++
@@ -1767,12 +1775,12 @@ func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {
if pkt.OverwriteID != 0 { if pkt.OverwriteID != 0 {
_, err := s.server.db.Exec("DELETE FROM guild_meals WHERE id = $1", pkt.OverwriteID) _, err := s.server.db.Exec("DELETE FROM guild_meals WHERE id = $1", pkt.OverwriteID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to delete meal in db", zap.Error(err)) s.logger.Error("Failed to delete meal in db", zap.Error(err))
} }
} }
_, err := s.server.db.Exec("INSERT INTO guild_meals (guild_id, meal_id, level, expires) VALUES ($1, $2, $3, $4)", guild.ID, pkt.MealID, pkt.Success, Time_Current_Adjusted().Add(30*time.Minute).Unix()) _, err := s.server.db.Exec("INSERT INTO guild_meals (guild_id, meal_id, level, expires) VALUES ($1, $2, $3, $4)", guild.ID, pkt.MealID, pkt.Success, Time_Current_Adjusted().Add(30*time.Minute).Unix())
if err != nil { if err != nil {
s.logger.Fatal("Failed to register meal in db", zap.Error(err)) s.logger.Error("Failed to register meal in db", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x01, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x01, 0x00})
} }
@@ -1826,7 +1834,9 @@ func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
msgs, err := s.server.db.Queryx("SELECT post_type, stamp_id, title, body, author_id, (EXTRACT(epoch FROM created_at)::int) as created_at, liked_by FROM guild_posts WHERE guild_id = $1 AND post_type = $2 ORDER BY created_at DESC", guild.ID, int(pkt.BoardType)) msgs, err := s.server.db.Queryx("SELECT post_type, stamp_id, title, body, author_id, (EXTRACT(epoch FROM created_at)::int) as created_at, liked_by FROM guild_posts WHERE guild_id = $1 AND post_type = $2 ORDER BY created_at DESC", guild.ID, int(pkt.BoardType))
if err != nil { if err != nil {
s.logger.Fatal("Failed to get guild messages from db", zap.Error(err)) s.logger.Error("Failed to get guild messages from db", zap.Error(err))
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} }
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
@@ -1836,11 +1846,10 @@ func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
noMsgs = false noMsgs = false
postCount++ postCount++
postData := &MessageBoardPost{} postData := &MessageBoardPost{}
err = msgs.StructScan(&postData) msgs.StructScan(&postData)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get guild messages from db", zap.Error(err)) continue
} }
bf.WriteUint32(postData.Type) bf.WriteUint32(postData.Type)
bf.WriteUint32(postData.AuthorID) bf.WriteUint32(postData.AuthorID)
bf.WriteUint64(postData.Timestamp) bf.WriteUint64(postData.Timestamp)
@@ -1856,7 +1865,7 @@ func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
ps.Uint32(bf, postData.Body, true) ps.Uint32(bf, postData.Body, true)
} }
if noMsgs { if noMsgs {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
} else { } else {
data := byteframe.NewByteFrame() data := byteframe.NewByteFrame()
data.WriteUint32(uint32(postCount)) data.WriteUint32(uint32(postCount))
@@ -1890,19 +1899,20 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
bodyConv = stringsupport.SJISToUTF8(body) bodyConv = stringsupport.SJISToUTF8(body)
_, err := s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, int(stampId), int(postType), titleConv, bodyConv) _, err := s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, int(stampId), int(postType), titleConv, bodyConv)
if err != nil { if err != nil {
s.logger.Fatal("Failed to add new guild message to db", zap.Error(err)) s.logger.Error("Failed to add new guild message to db", zap.Error(err))
} }
// TODO: if there are too many messages, purge excess /* TODO: if there are too many messages, purge excess
_, err = s.server.db.Exec("") _, err = s.server.db.Exec("")
if err != nil { if err != nil {
s.logger.Fatal("Failed to remove excess guild messages from db", zap.Error(err)) s.logger.Fatal("Failed to remove excess guild messages from db", zap.Error(err))
} }
*/
case 1: // Delete message case 1: // Delete message
postType := bf.ReadUint32() postType := bf.ReadUint32()
timestamp := bf.ReadUint64() timestamp := bf.ReadUint64()
_, err := s.server.db.Exec("DELETE FROM guild_posts WHERE post_type = $1 AND (EXTRACT(epoch FROM created_at)::int) = $2 AND guild_id = $3", int(postType), int(timestamp), guild.ID) _, err := s.server.db.Exec("DELETE FROM guild_posts WHERE post_type = $1 AND (EXTRACT(epoch FROM created_at)::int) = $2 AND guild_id = $3", int(postType), int(timestamp), guild.ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to delete guild message from db", zap.Error(err)) s.logger.Error("Failed to delete guild message from db", zap.Error(err))
} }
case 2: // Update message case 2: // Update message
postType := bf.ReadUint32() postType := bf.ReadUint32()
@@ -1915,7 +1925,7 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
bodyConv = stringsupport.SJISToUTF8(body) bodyConv = stringsupport.SJISToUTF8(body)
_, err := s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE post_type = $3 AND (EXTRACT(epoch FROM created_at)::int) = $4 AND guild_id = $5", titleConv, bodyConv, int(postType), int(timestamp), guild.ID) _, err := s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE post_type = $3 AND (EXTRACT(epoch FROM created_at)::int) = $4 AND guild_id = $5", titleConv, bodyConv, int(postType), int(timestamp), guild.ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update guild message in db", zap.Error(err)) s.logger.Error("Failed to update guild message in db", zap.Error(err))
} }
case 3: // Update stamp case 3: // Update stamp
postType := bf.ReadUint32() postType := bf.ReadUint32()
@@ -1923,7 +1933,7 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
stampId := bf.ReadUint32() stampId := bf.ReadUint32()
_, err := s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", int(stampId), int(postType), int(timestamp), guild.ID) _, err := s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", int(stampId), int(postType), int(timestamp), guild.ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update guild message stamp in db", zap.Error(err)) s.logger.Error("Failed to update guild message stamp in db", zap.Error(err))
} }
case 4: // Like message case 4: // Like message
postType := bf.ReadUint32() postType := bf.ReadUint32()
@@ -1932,19 +1942,19 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
var likedBy string var likedBy string
err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE post_type = $1 AND (EXTRACT(epoch FROM created_at)::int) = $2 AND guild_id = $3", int(postType), int(timestamp), guild.ID).Scan(&likedBy) err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE post_type = $1 AND (EXTRACT(epoch FROM created_at)::int) = $2 AND guild_id = $3", int(postType), int(timestamp), guild.ID).Scan(&likedBy)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get guild message like data from db", zap.Error(err)) s.logger.Error("Failed to get guild message like data from db", zap.Error(err))
} else { } else {
if likeState { if likeState {
likedBy = stringsupport.CSVAdd(likedBy, int(s.charID)) likedBy = stringsupport.CSVAdd(likedBy, int(s.charID))
_, err := s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", likedBy, int(postType), int(timestamp), guild.ID) _, err := s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", likedBy, int(postType), int(timestamp), guild.ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to like guild message in db", zap.Error(err)) s.logger.Error("Failed to like guild message in db", zap.Error(err))
} }
} else { } else {
likedBy = stringsupport.CSVRemove(likedBy, int(s.charID)) likedBy = stringsupport.CSVRemove(likedBy, int(s.charID))
_, err := s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", likedBy, int(postType), int(timestamp), guild.ID) _, err := s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE post_type = $2 AND (EXTRACT(epoch FROM created_at)::int) = $3 AND guild_id = $4", likedBy, int(postType), int(timestamp), guild.ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to unlike guild message in db", zap.Error(err)) s.logger.Error("Failed to unlike guild message in db", zap.Error(err))
} }
} }
} }
@@ -1953,15 +1963,15 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
var newPosts int var newPosts int
err := s.server.db.QueryRow("SELECT (EXTRACT(epoch FROM guild_post_checked)::int) FROM characters WHERE id = $1", s.charID).Scan(&timeChecked) err := s.server.db.QueryRow("SELECT (EXTRACT(epoch FROM guild_post_checked)::int) FROM characters WHERE id = $1", s.charID).Scan(&timeChecked)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get last guild post check timestamp from db", zap.Error(err)) s.logger.Error("Failed to get last guild post check timestamp from db", zap.Error(err))
} else { } else {
_, err = s.server.db.Exec("UPDATE characters SET guild_post_checked = $1 WHERE id = $2", time.Now(), s.charID) _, err = s.server.db.Exec("UPDATE characters SET guild_post_checked = $1 WHERE id = $2", time.Now(), s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update guild post check timestamp in db", zap.Error(err)) s.logger.Error("Failed to update guild post check timestamp in db", zap.Error(err))
} else { } else {
err = s.server.db.QueryRow("SELECT COUNT(*) FROM guild_posts WHERE guild_id = $1 AND (EXTRACT(epoch FROM created_at)::int) > $2 AND author_id != $3", guild.ID, timeChecked, s.charID).Scan(&newPosts) err = s.server.db.QueryRow("SELECT COUNT(*) FROM guild_posts WHERE guild_id = $1 AND (EXTRACT(epoch FROM created_at)::int) > $2 AND author_id != $3", guild.ID, timeChecked, s.charID).Scan(&newPosts)
if err != nil { if err != nil {
s.logger.Fatal("Failed to check for new guild posts in db", zap.Error(err)) s.logger.Error("Failed to check for new guild posts in db", zap.Error(err))
} else { } else {
if newPosts > 0 { if newPosts > 0 {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x01})
@@ -1971,7 +1981,7 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
} }
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfEntryRookieGuild(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEntryRookieGuild(s *Session, p mhfpacket.MHFPacket) {

View File

@@ -23,7 +23,9 @@ func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
guild, _ := GetGuildInfoByCharacterId(s, s.charID) guild, _ := GetGuildInfoByCharacterId(s, s.charID)
data, err := s.server.db.Queryx("SELECT id, destination, charge, depart, return, collected_by FROM guild_adventures WHERE guild_id = $1", guild.ID) data, err := s.server.db.Queryx("SELECT id, destination, charge, depart, return, collected_by FROM guild_adventures WHERE guild_id = $1", guild.ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get guild adventures from db", zap.Error(err)) s.logger.Error("Failed to get guild adventures from db", zap.Error(err))
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1))
return
} }
temp := byteframe.NewByteFrame() temp := byteframe.NewByteFrame()
count := 0 count := 0
@@ -32,7 +34,7 @@ func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
adventureData := &GuildAdventure{} adventureData := &GuildAdventure{}
err = data.StructScan(&adventureData) err = data.StructScan(&adventureData)
if err != nil { if err != nil {
s.logger.Fatal("Failed to scan adventure data", zap.Error(err)) continue
} }
temp.WriteUint32(adventureData.ID) temp.WriteUint32(adventureData.ID)
temp.WriteUint32(adventureData.Destination) temp.WriteUint32(adventureData.Destination)
@@ -52,7 +54,7 @@ func handleMsgMhfRegistGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
guild, _ := GetGuildInfoByCharacterId(s, s.charID) guild, _ := GetGuildInfoByCharacterId(s, s.charID)
_, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, depart, return) VALUES ($1, $2, $3, $4)", guild.ID, pkt.Destination, Time_Current_Adjusted().Unix(), Time_Current_Adjusted().Add(6*time.Hour).Unix()) _, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, depart, return) VALUES ($1, $2, $3, $4)", guild.ID, pkt.Destination, Time_Current_Adjusted().Unix(), Time_Current_Adjusted().Add(6*time.Hour).Unix())
if err != nil { if err != nil {
s.logger.Fatal("Failed to register guild adventure", zap.Error(err)) s.logger.Error("Failed to register guild adventure", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
@@ -62,12 +64,12 @@ func handleMsgMhfAcquireGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
var collectedBy string var collectedBy string
err := s.server.db.QueryRow("SELECT collected_by FROM guild_adventures WHERE id = $1", pkt.ID).Scan(&collectedBy) err := s.server.db.QueryRow("SELECT collected_by FROM guild_adventures WHERE id = $1", pkt.ID).Scan(&collectedBy)
if err != nil { if err != nil {
s.logger.Fatal("Error parsing adventure collected by", zap.Error(err)) s.logger.Error("Error parsing adventure collected by", zap.Error(err))
} else { } else {
collectedBy = stringsupport.CSVAdd(collectedBy, int(s.charID)) collectedBy = stringsupport.CSVAdd(collectedBy, int(s.charID))
_, err := s.server.db.Exec("UPDATE guild_adventures SET collected_by = $1 WHERE id = $2", collectedBy, pkt.ID) _, err := s.server.db.Exec("UPDATE guild_adventures SET collected_by = $1 WHERE id = $2", collectedBy, pkt.ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to collect adventure in db", zap.Error(err)) s.logger.Error("Failed to collect adventure in db", zap.Error(err))
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
@@ -77,7 +79,7 @@ func handleMsgMhfChargeGuildAdventure(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfChargeGuildAdventure) pkt := p.(*mhfpacket.MsgMhfChargeGuildAdventure)
_, err := s.server.db.Exec("UPDATE guild_adventures SET charge = charge + $1 WHERE id = $2", pkt.Amount, pkt.ID) _, err := s.server.db.Exec("UPDATE guild_adventures SET charge = charge + $1 WHERE id = $2", pkt.Amount, pkt.ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to charge guild adventure", zap.Error(err)) s.logger.Error("Failed to charge guild adventure", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
@@ -87,7 +89,7 @@ func handleMsgMhfRegistGuildAdventureDiva(s *Session, p mhfpacket.MHFPacket) {
guild, _ := GetGuildInfoByCharacterId(s, s.charID) guild, _ := GetGuildInfoByCharacterId(s, s.charID)
_, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, charge, depart, return) VALUES ($1, $2, $3, $4, $5)", guild.ID, pkt.Destination, pkt.Charge, Time_Current_Adjusted().Unix(), Time_Current_Adjusted().Add(1*time.Hour).Unix()) _, err := s.server.db.Exec("INSERT INTO guild_adventures (guild_id, destination, charge, depart, return) VALUES ($1, $2, $3, $4, $5)", guild.ID, pkt.Destination, pkt.Charge, Time_Current_Adjusted().Unix(), Time_Current_Adjusted().Add(1*time.Hour).Unix())
if err != nil { if err != nil {
s.logger.Fatal("Failed to register guild adventure", zap.Error(err)) s.logger.Error("Failed to register guild adventure", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -73,7 +73,8 @@ func buildAllianceObjectFromDbResult(result *sqlx.Rows, err error, s *Session) (
parentGuild, err := GetGuildInfoByID(s, alliance.ParentGuildID) parentGuild, err := GetGuildInfoByID(s, alliance.ParentGuildID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get parent guild info", zap.Error(err)) s.logger.Error("Failed to get parent guild info", zap.Error(err))
return nil, err
} else { } else {
alliance.ParentGuild = *parentGuild alliance.ParentGuild = *parentGuild
alliance.TotalMembers += parentGuild.MemberCount alliance.TotalMembers += parentGuild.MemberCount
@@ -82,7 +83,8 @@ func buildAllianceObjectFromDbResult(result *sqlx.Rows, err error, s *Session) (
if alliance.SubGuild1ID > 0 { if alliance.SubGuild1ID > 0 {
subGuild1, err := GetGuildInfoByID(s, alliance.SubGuild1ID) subGuild1, err := GetGuildInfoByID(s, alliance.SubGuild1ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get sub guild 1 info", zap.Error(err)) s.logger.Error("Failed to get sub guild 1 info", zap.Error(err))
return nil, err
} else { } else {
alliance.SubGuild1 = *subGuild1 alliance.SubGuild1 = *subGuild1
alliance.TotalMembers += subGuild1.MemberCount alliance.TotalMembers += subGuild1.MemberCount
@@ -92,7 +94,8 @@ func buildAllianceObjectFromDbResult(result *sqlx.Rows, err error, s *Session) (
if alliance.SubGuild2ID > 0 { if alliance.SubGuild2ID > 0 {
subGuild2, err := GetGuildInfoByID(s, alliance.SubGuild2ID) subGuild2, err := GetGuildInfoByID(s, alliance.SubGuild2ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get sub guild 2 info", zap.Error(err)) s.logger.Error("Failed to get sub guild 2 info", zap.Error(err))
return nil, err
} else { } else {
alliance.SubGuild2 = *subGuild2 alliance.SubGuild2 = *subGuild2
alliance.TotalMembers += subGuild2.MemberCount alliance.TotalMembers += subGuild2.MemberCount
@@ -106,7 +109,7 @@ func handleMsgMhfCreateJoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfCreateJoint) pkt := p.(*mhfpacket.MsgMhfCreateJoint)
_, err := s.server.db.Exec("INSERT INTO guild_alliances (name, parent_id) VALUES ($1, $2)", pkt.Name, pkt.GuildID) _, err := s.server.db.Exec("INSERT INTO guild_alliances (name, parent_id) VALUES ($1, $2)", pkt.Name, pkt.GuildID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to create guild alliance in db", zap.Error(err)) s.logger.Error("Failed to create guild alliance in db", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x01, 0x01, 0x01, 0x01}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x01, 0x01, 0x01, 0x01})
} }
@@ -116,11 +119,11 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
guild, err := GetGuildInfoByID(s, pkt.GuildID) guild, err := GetGuildInfoByID(s, pkt.GuildID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get guild info", zap.Error(err)) s.logger.Error("Failed to get guild info", zap.Error(err))
} }
alliance, err := GetAllianceData(s, pkt.AllianceID) alliance, err := GetAllianceData(s, pkt.AllianceID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get alliance info", zap.Error(err)) s.logger.Error("Failed to get alliance info", zap.Error(err))
} }
switch pkt.Action { switch pkt.Action {
@@ -128,7 +131,7 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {
if guild.LeaderCharID == s.charID && alliance.ParentGuildID == guild.ID { if guild.LeaderCharID == s.charID && alliance.ParentGuildID == guild.ID {
_, err = s.server.db.Exec("DELETE FROM guild_alliances WHERE id=$1", alliance.ID) _, err = s.server.db.Exec("DELETE FROM guild_alliances WHERE id=$1", alliance.ID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to disband alliance", zap.Error(err)) s.logger.Error("Failed to disband alliance", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else { } else {

View File

@@ -13,6 +13,8 @@ type GuildMember struct {
CharID uint32 `db:"character_id"` CharID uint32 `db:"character_id"`
JoinedAt *time.Time `db:"joined_at"` JoinedAt *time.Time `db:"joined_at"`
Souls uint32 `db:"souls"` Souls uint32 `db:"souls"`
RPToday uint16 `db:"rp_today"`
RPYesterday uint16 `db:"rp_yesterday"`
Name string `db:"name"` Name string `db:"name"`
IsApplicant bool `db:"is_applicant"` IsApplicant bool `db:"is_applicant"`
OrderIndex uint8 `db:"order_index"` OrderIndex uint8 `db:"order_index"`
@@ -63,6 +65,8 @@ SELECT
g.id as guild_id, g.id as guild_id,
joined_at, joined_at,
coalesce(souls, 0) as souls, coalesce(souls, 0) as souls,
rp_today,
rp_yesterday,
c.name, c.name,
character.character_id, character.character_id,
coalesce(gc.order_index, 0) as order_index, coalesce(gc.order_index, 0) as order_index,

View File

@@ -246,18 +246,12 @@ func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) {
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get preset decorations savedata from db", zap.Error(err)) s.logger.Error("Failed to load decomyset", zap.Error(err))
} }
if len(data) == 0 {
if len(data) > 0 { data = []byte{0x01, 0x00}
doAckBufSucceed(s, pkt.AckHandle, data)
//doAckBufSucceed(s, pkt.AckHandle, data)
} else {
// set first byte to 1 to avoid pop up every time without save
body := make([]byte, 0x226)
body[0] = 1
doAckBufSucceed(s, pkt.AckHandle, body)
} }
doAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
@@ -267,7 +261,7 @@ func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload[1:]) // skip first unk byte bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload[1:]) // skip first unk byte
err := s.server.db.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.charID).Scan(&loadData) err := s.server.db.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.charID).Scan(&loadData)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get preset decorations savedata from db", zap.Error(err)) s.logger.Error("Failed to load decomyset", zap.Error(err))
} else { } else {
numSets := bf.ReadUint8() // sets being written numSets := bf.ReadUint8() // sets being written
// empty save // empty save
@@ -313,7 +307,7 @@ func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
dumpSaveData(s, loadData, "decomyset") dumpSaveData(s, loadData, "decomyset")
_, err := s.server.db.Exec("UPDATE characters SET decomyset=$1 WHERE id=$2", loadData, s.charID) _, err := s.server.db.Exec("UPDATE characters SET decomyset=$1 WHERE id=$2", loadData, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update decomyset savedata in db", zap.Error(err)) s.logger.Error("Failed to save decomyset", zap.Error(err))
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})

View File

@@ -12,7 +12,7 @@ func handleMsgMhfAddKouryouPoint(s *Session, p mhfpacket.MHFPacket) {
var points int var points int
err := s.server.db.QueryRow("UPDATE characters SET kouryou_point=COALESCE(kouryou_point + $1, $1) WHERE id=$2 RETURNING kouryou_point", pkt.KouryouPoints, s.charID).Scan(&points) err := s.server.db.QueryRow("UPDATE characters SET kouryou_point=COALESCE(kouryou_point + $1, $1) WHERE id=$2 RETURNING kouryou_point", pkt.KouryouPoints, s.charID).Scan(&points)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update KouryouPoint in db", zap.Error(err)) s.logger.Error("Failed to update KouryouPoint in db", zap.Error(err))
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(uint32(points)) resp.WriteUint32(uint32(points))
@@ -24,7 +24,7 @@ func handleMsgMhfGetKouryouPoint(s *Session, p mhfpacket.MHFPacket) {
var points int var points int
err := s.server.db.QueryRow("SELECT COALESCE(kouryou_point, 0) FROM characters WHERE id = $1", s.charID).Scan(&points) err := s.server.db.QueryRow("SELECT COALESCE(kouryou_point, 0) FROM characters WHERE id = $1", s.charID).Scan(&points)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get kouryou_point savedata from db", zap.Error(err)) s.logger.Error("Failed to get kouryou_point savedata from db", zap.Error(err))
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(uint32(points)) resp.WriteUint32(uint32(points))
@@ -37,7 +37,7 @@ func handleMsgMhfExchangeKouryouPoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfExchangeKouryouPoint) pkt := p.(*mhfpacket.MsgMhfExchangeKouryouPoint)
err := s.server.db.QueryRow("UPDATE characters SET kouryou_point=kouryou_point - $1 WHERE id=$2 RETURNING kouryou_point", pkt.KouryouPoints, s.charID).Scan(&points) err := s.server.db.QueryRow("UPDATE characters SET kouryou_point=kouryou_point - $1 WHERE id=$2 RETURNING kouryou_point", pkt.KouryouPoints, s.charID).Scan(&points)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update platemyset savedata in db", zap.Error(err)) s.logger.Error("Failed to update platemyset savedata in db", zap.Error(err))
} }
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(uint32(points)) resp.WriteUint32(uint32(points))

View File

@@ -392,24 +392,29 @@ func handleMsgMhfSendMail(s *Session, p mhfpacket.MHFPacket) {
if pkt.RecipientID == 0 { // Guild mail if pkt.RecipientID == 0 { // Guild mail
g, err := GetGuildInfoByCharacterId(s, s.charID) g, err := GetGuildInfoByCharacterId(s, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get guild info for mail") s.logger.Error("Failed to get guild info for mail")
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} }
gm, err := GetGuildMembers(s, g.ID, false) gm, err := GetGuildMembers(s, g.ID, false)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get guild members for mail") s.logger.Error("Failed to get guild members for mail")
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} }
for i := 0; i < len(gm); i++ { for i := 0; i < len(gm); i++ {
_, err := s.server.db.Exec(query, s.charID, gm[i].CharID, pkt.Subject, pkt.Body, 0, 0, false) _, err := s.server.db.Exec(query, s.charID, gm[i].CharID, pkt.Subject, pkt.Body, 0, 0, false)
if err != nil { if err != nil {
s.logger.Fatal("Failed to send mail") s.logger.Error("Failed to send mail")
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} }
} }
} else { } else {
_, err := s.server.db.Exec(query, s.charID, pkt.RecipientID, pkt.Subject, pkt.Body, pkt.ItemID, pkt.Quantity, false) _, err := s.server.db.Exec(query, s.charID, pkt.RecipientID, pkt.Subject, pkt.Body, pkt.ItemID, pkt.Quantity, false)
if err != nil { if err != nil {
s.logger.Fatal("Failed to send mail") s.logger.Error("Failed to send mail")
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }

View File

@@ -11,115 +11,96 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"time"
) )
// THERE ARE [PARTENER] [MERCENARY] [OTOMO AIRU]
///////////////////////////////////////////
/// PARTENER //
///////////////////////////////////////////
func handleMsgMhfLoadPartner(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadPartner(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadPartner) pkt := p.(*mhfpacket.MsgMhfLoadPartner)
// load partner from database
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT partner FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT partner FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if len(data) == 0 {
s.logger.Fatal("Failed to get partner savedata from db", zap.Error(err)) s.logger.Error("Failed to load partner", zap.Error(err))
data = make([]byte, 9)
} }
if len(data) > 0 { doAckBufSucceed(s, pkt.AckHandle, data)
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
}
// TODO(Andoryuuta): Figure out unusual double ack. One sized, one not.
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfSavePartner(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePartner(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavePartner) pkt := p.(*mhfpacket.MsgMhfSavePartner)
dumpSaveData(s, pkt.RawDataPayload, "partner") dumpSaveData(s, pkt.RawDataPayload, "partner")
_, err := s.server.db.Exec("UPDATE characters SET partner=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err := s.server.db.Exec("UPDATE characters SET partner=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update partner savedata in db", zap.Error(err)) s.logger.Error("Failed to save partner", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadLegendDispatch) pkt := p.(*mhfpacket.MsgMhfLoadLegendDispatch)
data := []byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x01, 0x8d, 0x40, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x02, 0xde, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x04, 0x30, 0x40} bf := byteframe.NewByteFrame()
doAckBufSucceed(s, pkt.AckHandle, data) legendDispatch := []struct {
Unk uint32
Timestamp uint32
}{
{0, uint32(Time_Current_Midnight().Add(-12 * time.Hour).Unix())},
{0, uint32(Time_Current_Midnight().Add(12 * time.Hour).Unix())},
{0, uint32(Time_Current_Midnight().Add(36 * time.Hour).Unix())},
}
bf.WriteUint8(uint8(len(legendDispatch)))
for _, dispatch := range legendDispatch {
bf.WriteUint32(dispatch.Unk)
bf.WriteUint32(dispatch.Timestamp)
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadHunterNavi) pkt := p.(*mhfpacket.MsgMhfLoadHunterNavi)
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if len(data) == 0 {
s.logger.Fatal("Failed to get hunter navigation savedata from db", zap.Error(err)) s.logger.Error("Failed to load hunternavi", zap.Error(err))
} data = make([]byte, 0x226)
if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
// set first byte to 1 to avoid pop up every time without save
body := make([]byte, 0x226)
body[0] = 1
doAckBufSucceed(s, pkt.AckHandle, body)
} }
doAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveHunterNavi) pkt := p.(*mhfpacket.MsgMhfSaveHunterNavi)
dumpSaveData(s, pkt.RawDataPayload, "hunternavi")
if pkt.IsDataDiff { if pkt.IsDataDiff {
var data []byte var data []byte
// Load existing save // Load existing save
err := s.server.db.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT hunternavi FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get hunternavi savedata from db", zap.Error(err)) s.logger.Error("Failed to load hunternavi", zap.Error(err))
} }
// Check if we actually had any hunternavi data, using a blank buffer if not. // Check if we actually had any hunternavi data, using a blank buffer if not.
// This is requried as the client will try to send a diff after character creation without a prior MsgMhfSaveHunterNavi packet. // This is requried as the client will try to send a diff after character creation without a prior MsgMhfSaveHunterNavi packet.
if len(data) == 0 { if len(data) == 0 {
data = make([]byte, 0x226) data = make([]byte, 0x226)
data[0] = 1 // set first byte to 1 to avoid pop up every time without save
} }
// Perform diff and compress it to write back to db // Perform diff and compress it to write back to db
s.logger.Info("Diffing...") s.logger.Info("Diffing...")
saveOutput := deltacomp.ApplyDataDiff(pkt.RawDataPayload, data) saveOutput := deltacomp.ApplyDataDiff(pkt.RawDataPayload, data)
_, err = s.server.db.Exec("UPDATE characters SET hunternavi=$1 WHERE id=$2", saveOutput, s.charID) _, err = s.server.db.Exec("UPDATE characters SET hunternavi=$1 WHERE id=$2", saveOutput, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update hunternavi savedata in db", zap.Error(err)) s.logger.Error("Failed to save hunternavi", zap.Error(err))
} }
s.logger.Info("Wrote recompressed hunternavi back to DB")
s.logger.Info("Wrote recompressed hunternavi back to DB.")
} else { } else {
dumpSaveData(s, pkt.RawDataPayload, "hunternavi") dumpSaveData(s, pkt.RawDataPayload, "hunternavi")
// simply update database, no extra processing // simply update database, no extra processing
_, err := s.server.db.Exec("UPDATE characters SET hunternavi=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err := s.server.db.Exec("UPDATE characters SET hunternavi=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update hunternavi savedata in db", zap.Error(err)) s.logger.Error("Failed to save hunternavi", zap.Error(err))
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
///////////////////////////////////////////
///////////////////////////////////////////
/// MERCENARY //
///////////////////////////////////////////
func handleMsgMhfMercenaryHuntdata(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfMercenaryHuntdata(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfMercenaryHuntdata) pkt := p.(*mhfpacket.MsgMhfMercenaryHuntdata)
if pkt.Unk0 == 1 { if pkt.Unk0 == 1 {
@@ -149,15 +130,11 @@ func handleMsgMhfEnumerateMercenaryLog(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfCreateMercenary(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfCreateMercenary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfCreateMercenary) pkt := p.(*mhfpacket.MsgMhfCreateMercenary)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var nextID uint32 var nextID uint32
s.server.db.QueryRow("SELECT nextval('rasta_id_seq')").Scan(&nextID) _ = s.server.db.QueryRow("SELECT nextval('rasta_id_seq')").Scan(&nextID)
s.server.db.Exec("UPDATE characters SET rasta_id=$1 WHERE id=$2", nextID, s.charID)
bf.WriteUint32(nextID) // New MercID bf.WriteUint32(nextID)
bf.WriteUint32(0xDEADBEEF) // Unk
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} }
@@ -165,29 +142,66 @@ func handleMsgMhfSaveMercenary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveMercenary) pkt := p.(*mhfpacket.MsgMhfSaveMercenary)
dumpSaveData(s, pkt.MercData, "mercenary") dumpSaveData(s, pkt.MercData, "mercenary")
if len(pkt.MercData) > 0 { if len(pkt.MercData) > 0 {
s.server.db.Exec("UPDATE characters SET savemercenary=$1 WHERE id=$2", pkt.MercData, s.charID) temp := byteframe.NewByteFrameFromBytes(pkt.MercData)
s.server.db.Exec("UPDATE characters SET savemercenary=$1, rasta_id=$2 WHERE id=$3", pkt.MercData, temp.ReadUint32(), s.charID)
} }
s.server.db.Exec("UPDATE characters SET gcp=$1 WHERE id=$2", pkt.GCP, s.charID) s.server.db.Exec("UPDATE characters SET gcp=$1, pact_id=$2 WHERE id=$3", pkt.GCP, pkt.PactMercID, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfReadMercenaryW) pkt := p.(*mhfpacket.MsgMhfReadMercenaryW)
if pkt.Unk0 { if pkt.Op > 0 {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2)) bf := byteframe.NewByteFrame()
var pactID uint32
var name string
var cid uint32
s.server.db.QueryRow("SELECT pact_id FROM characters WHERE id=$1", s.charID).Scan(&pactID)
if pactID > 0 {
s.server.db.QueryRow("SELECT name, id FROM characters WHERE rasta_id = $1", pactID).Scan(&name, &cid)
bf.WriteUint8(1) // numLends
bf.WriteUint32(pactID)
bf.WriteUint32(cid)
bf.WriteBool(false) // ?
bf.WriteUint32(uint32(Time_Current_Adjusted().Add(time.Hour * 24 * -8).Unix()))
bf.WriteUint32(uint32(Time_Current_Adjusted().Add(time.Hour * 24 * -1).Unix()))
bf.WriteBytes(stringsupport.PaddedString(name, 18, true))
} else {
bf.WriteUint8(0)
}
if pkt.Op < 2 {
var loans uint8
temp := byteframe.NewByteFrame()
rows, _ := s.server.db.Query("SELECT name, id, pact_id FROM characters WHERE pact_id=(SELECT rasta_id FROM characters WHERE id=$1)", s.charID)
for rows.Next() {
loans++
rows.Scan(&name, &cid, &pactID)
temp.WriteUint32(pactID)
temp.WriteUint32(cid)
temp.WriteUint32(uint32(Time_Current_Adjusted().Add(time.Hour * 24 * -8).Unix()))
temp.WriteUint32(uint32(Time_Current_Adjusted().Add(time.Hour * 24 * -1).Unix()))
temp.WriteBytes(stringsupport.PaddedString(name, 18, true))
}
bf.WriteUint8(loans)
bf.WriteBytes(temp.Data())
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
return return
} }
var data []byte var data []byte
var gcp uint32 var gcp uint32
s.server.db.QueryRow("SELECT savemercenary FROM characters WHERE id = $1", s.charID).Scan(&data) s.server.db.QueryRow("SELECT savemercenary FROM characters WHERE id=$1", s.charID).Scan(&data)
s.server.db.QueryRow("SELECT COALESCE(gcp, 0) FROM characters WHERE id = $1", s.charID).Scan(&gcp) s.server.db.QueryRow("SELECT COALESCE(gcp, 0) FROM characters WHERE id=$1", s.charID).Scan(&gcp)
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint16(0)
if len(data) == 0 { if len(data) == 0 {
resp.WriteBytes(make([]byte, 3)) resp.WriteBool(false)
} else { } else {
resp.WriteBytes(data[1:]) resp.WriteBool(true)
resp.WriteUint32(0) // Unk resp.WriteBytes(data)
} }
resp.WriteUint32(gcp) resp.WriteUint32(gcp)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) doAckBufSucceed(s, pkt.AckHandle, resp.Data())
@@ -201,31 +215,33 @@ func handleMsgMhfReadMercenaryM(s *Session, p mhfpacket.MHFPacket) {
if len(data) == 0 { if len(data) == 0 {
resp.WriteBool(false) resp.WriteBool(false)
} else { } else {
resp.WriteBytes(data[4:]) resp.WriteBytes(data)
} }
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) doAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfContractMercenary(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfContractMercenary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfContractMercenary)
/////////////////////////////////////////// switch pkt.Op {
case 0:
/////////////////////////////////////////// s.server.db.Exec("UPDATE characters SET pact_id=$1 WHERE id=$2", pkt.PactMercID, s.charID)
/// OTOMO AIRU // case 1: // Cancel lend
/////////////////////////////////////////// s.server.db.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", s.charID)
case 2: // Cancel loan
s.server.db.Exec("UPDATE characters SET pact_id=0 WHERE id=$1", pkt.CID)
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfLoadOtomoAirou(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadOtomoAirou) pkt := p.(*mhfpacket.MsgMhfLoadOtomoAirou)
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT otomoairou FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT otomoairou FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if len(data) == 0 {
s.logger.Fatal("Failed to get partnyaa savedata from db", zap.Error(err)) s.logger.Error("Failed to load otomoairou", zap.Error(err))
} data = make([]byte, 10)
if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
} }
doAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
@@ -411,5 +427,3 @@ func GetCatDetails(bf *byteframe.ByteFrame) []CatDefinition {
} }
return cats return cats
} }
///////////////////////////////////////////

View File

@@ -12,28 +12,23 @@ func handleMsgMhfLoadPlateData(s *Session, p mhfpacket.MHFPacket) {
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT platedata FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT platedata FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if err != nil {
s.logger.Error("Failed to get plate data savedata from db", zap.Error(err)) s.logger.Error("Failed to load platedata", zap.Error(err))
}
if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
doAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavePlateData) pkt := p.(*mhfpacket.MsgMhfSavePlateData)
dumpSaveData(s, pkt.RawDataPayload, "platedata")
if pkt.IsDataDiff { if pkt.IsDataDiff {
var data []byte var data []byte
// Load existing save // Load existing save
err := s.server.db.QueryRow("SELECT platedata FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT platedata FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get platedata savedata from db", zap.Error(err)) s.logger.Error("Failed to load platedata", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return
} }
if len(data) > 0 { if len(data) > 0 {
@@ -41,7 +36,9 @@ func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) {
s.logger.Info("Decompressing...") s.logger.Info("Decompressing...")
data, err = nullcomp.Decompress(data) data, err = nullcomp.Decompress(data)
if err != nil { if err != nil {
s.logger.Fatal("Failed to decompress savedata from db", zap.Error(err)) s.logger.Error("Failed to decompress platedata", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return
} }
} else { } else {
// create empty save if absent // create empty save if absent
@@ -52,20 +49,25 @@ func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) {
s.logger.Info("Diffing...") s.logger.Info("Diffing...")
saveOutput, err := nullcomp.Compress(deltacomp.ApplyDataDiff(pkt.RawDataPayload, data)) saveOutput, err := nullcomp.Compress(deltacomp.ApplyDataDiff(pkt.RawDataPayload, data))
if err != nil { if err != nil {
s.logger.Fatal("Failed to diff and compress platedata savedata", zap.Error(err)) s.logger.Error("Failed to diff and compress platedata", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return
} }
_, err = s.server.db.Exec("UPDATE characters SET platedata=$1 WHERE id=$2", saveOutput, s.charID) _, err = s.server.db.Exec("UPDATE characters SET platedata=$1 WHERE id=$2", saveOutput, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update platedata savedata in db", zap.Error(err)) s.logger.Error("Failed to save platedata", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return
} }
s.logger.Info("Wrote recompressed platedata back to DB.") s.logger.Info("Wrote recompressed platedata back to DB")
} else { } else {
dumpSaveData(s, pkt.RawDataPayload, "platedata")
// simply update database, no extra processing // simply update database, no extra processing
_, err := s.server.db.Exec("UPDATE characters SET platedata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err := s.server.db.Exec("UPDATE characters SET platedata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update platedata savedata in db", zap.Error(err)) s.logger.Error("Failed to save platedata", zap.Error(err))
} }
} }
@@ -77,28 +79,23 @@ func handleMsgMhfLoadPlateBox(s *Session, p mhfpacket.MHFPacket) {
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT platebox FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT platebox FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if err != nil {
s.logger.Error("Failed to get sigil box savedata from db", zap.Error(err)) s.logger.Error("Failed to load platebox", zap.Error(err))
}
if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
doAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSavePlateBox) pkt := p.(*mhfpacket.MsgMhfSavePlateBox)
dumpSaveData(s, pkt.RawDataPayload, "platebox")
if pkt.IsDataDiff { if pkt.IsDataDiff {
var data []byte var data []byte
// Load existing save // Load existing save
err := s.server.db.QueryRow("SELECT platebox FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT platebox FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get sigil box savedata from db", zap.Error(err)) s.logger.Error("Failed to load platebox", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return
} }
// Decompress // Decompress
@@ -107,7 +104,9 @@ func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) {
s.logger.Info("Decompressing...") s.logger.Info("Decompressing...")
data, err = nullcomp.Decompress(data) data, err = nullcomp.Decompress(data)
if err != nil { if err != nil {
s.logger.Fatal("Failed to decompress savedata from db", zap.Error(err)) s.logger.Error("Failed to decompress platebox", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return
} }
} else { } else {
// create empty save if absent // create empty save if absent
@@ -118,20 +117,25 @@ func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) {
s.logger.Info("Diffing...") s.logger.Info("Diffing...")
saveOutput, err := nullcomp.Compress(deltacomp.ApplyDataDiff(pkt.RawDataPayload, data)) saveOutput, err := nullcomp.Compress(deltacomp.ApplyDataDiff(pkt.RawDataPayload, data))
if err != nil { if err != nil {
s.logger.Fatal("Failed to diff and compress savedata", zap.Error(err)) s.logger.Error("Failed to diff and compress platebox", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return
} }
_, err = s.server.db.Exec("UPDATE characters SET platebox=$1 WHERE id=$2", saveOutput, s.charID) _, err = s.server.db.Exec("UPDATE characters SET platebox=$1 WHERE id=$2", saveOutput, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update platebox savedata in db", zap.Error(err)) s.logger.Error("Failed to save platebox", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
return
} }
s.logger.Info("Wrote recompressed platebox back to DB.") s.logger.Info("Wrote recompressed platebox back to DB")
} else { } else {
dumpSaveData(s, pkt.RawDataPayload, "platebox")
// simply update database, no extra processing // simply update database, no extra processing
_, err := s.server.db.Exec("UPDATE characters SET platebox=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err := s.server.db.Exec("UPDATE characters SET platebox=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update platedata savedata in db", zap.Error(err)) s.logger.Error("Failed to save platebox", zap.Error(err))
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
@@ -141,16 +145,11 @@ func handleMsgMhfLoadPlateMyset(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadPlateMyset) pkt := p.(*mhfpacket.MsgMhfLoadPlateMyset)
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT platemyset FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT platemyset FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if len(data) == 0 {
s.logger.Fatal("Failed to get presets sigil savedata from db", zap.Error(err)) s.logger.Error("Failed to load platemyset", zap.Error(err))
} data = make([]byte, 0x780)
if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
blankData := make([]byte, 0x780)
doAckBufSucceed(s, pkt.AckHandle, blankData)
} }
doAckBufSucceed(s, pkt.AckHandle, data)
} }
func handleMsgMhfSavePlateMyset(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePlateMyset(s *Session, p mhfpacket.MHFPacket) {
@@ -159,7 +158,7 @@ func handleMsgMhfSavePlateMyset(s *Session, p mhfpacket.MHFPacket) {
dumpSaveData(s, pkt.RawDataPayload, "platemyset") dumpSaveData(s, pkt.RawDataPayload, "platemyset")
_, err := s.server.db.Exec("UPDATE characters SET platemyset=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err := s.server.db.Exec("UPDATE characters SET platemyset=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update platemyset savedata in db", zap.Error(err)) s.logger.Error("Failed to save platemyset", zap.Error(err))
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }

File diff suppressed because one or more lines are too long

View File

@@ -21,7 +21,7 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint8(1) resp.WriteUint8(1)
resp.WriteUint8(dest) resp.WriteUint8(dest)
ref := &s.server.raviente.state.stateData[dest] ref := &s.server.raviente.state.stateData[dest]
damageMultiplier := s.server.raviente.state.damageMultiplier damageMultiplier := s.server.raviente.GetRaviMultiplier(s.server)
switch op { switch op {
case 2: case 2:
resp.WriteUint32(*ref) resp.WriteUint32(*ref)
@@ -252,21 +252,21 @@ func (s *Session) notifyRavi() {
raviNotif.WriteUint16(uint16(temp.Opcode())) raviNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(raviNotif, s.clientContext) temp.Build(raviNotif, s.clientContext)
raviNotif.WriteUint16(0x0010) // End it. raviNotif.WriteUint16(0x0010) // End it.
sema := getRaviSemaphore(s) sema := getRaviSemaphore(s.server)
if sema != "" { if sema != nil {
for session := range s.server.semaphore[sema].clients { for session := range sema.clients {
session.QueueSend(raviNotif.Data()) session.QueueSend(raviNotif.Data())
} }
} }
} }
func getRaviSemaphore(s *Session) string { func getRaviSemaphore(s *Server) *Semaphore {
for _, semaphore := range s.server.semaphore { for _, semaphore := range s.semaphore {
if strings.HasPrefix(semaphore.id_semaphore, "hs_l0u3B5") && strings.HasSuffix(semaphore.id_semaphore, "4") { if strings.HasPrefix(semaphore.id_semaphore, "hs_l0u3B5") && strings.HasSuffix(semaphore.id_semaphore, "3") {
return semaphore.id_semaphore return semaphore
} }
} }
return "" return nil
} }
func resetRavi(s *Session) { func resetRavi(s *Session) {
@@ -278,7 +278,6 @@ func resetRavi(s *Session) {
s.server.raviente.register.ravienteType = 0 s.server.raviente.register.ravienteType = 0
s.server.raviente.register.maxPlayers = 0 s.server.raviente.register.maxPlayers = 0
s.server.raviente.register.carveQuest = 0 s.server.raviente.register.carveQuest = 0
s.server.raviente.state.damageMultiplier = 1
s.server.raviente.register.register = []uint32{0, 0, 0, 0, 0} s.server.raviente.register.register = []uint32{0, 0, 0, 0, 0}
s.server.raviente.state.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} s.server.raviente.state.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
s.server.raviente.support.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} s.server.raviente.support.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

View File

@@ -19,7 +19,9 @@ func handleMsgMhfSaveRengokuData(s *Session, p mhfpacket.MHFPacket) {
dumpSaveData(s, pkt.RawDataPayload, "rengoku") dumpSaveData(s, pkt.RawDataPayload, "rengoku")
_, err := s.server.db.Exec("UPDATE characters SET rengokudata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) _, err := s.server.db.Exec("UPDATE characters SET rengokudata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update rengokudata savedata in db", zap.Error(err)) s.logger.Error("Failed to save rengokudata", zap.Error(err))
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
return
} }
bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
bf.Seek(71, 0) bf.Seek(71, 0)
@@ -34,7 +36,7 @@ func handleMsgMhfSaveRengokuData(s *Session, p mhfpacket.MHFPacket) {
s.server.db.Exec("INSERT INTO rengoku_score (character_id) VALUES ($1)", s.charID) 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) 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, make([]byte, 4))
} }
func handleMsgMhfLoadRengokuData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadRengokuData(s *Session, p mhfpacket.MHFPacket) {
@@ -42,7 +44,7 @@ func handleMsgMhfLoadRengokuData(s *Session, p mhfpacket.MHFPacket) {
var data []byte var data []byte
err := s.server.db.QueryRow("SELECT rengokudata FROM characters WHERE id = $1", s.charID).Scan(&data) err := s.server.db.QueryRow("SELECT rengokudata FROM characters WHERE id = $1", s.charID).Scan(&data)
if err != nil { if err != nil {
s.logger.Fatal("Failed to get rengokudata savedata from db", zap.Error(err)) s.logger.Error("Failed to load rengokudata", zap.Error(err))
} }
if len(data) > 0 { if len(data) > 0 {
doAckBufSucceed(s, pkt.AckHandle, data) doAckBufSucceed(s, pkt.AckHandle, data)

View File

@@ -43,7 +43,3 @@ func handleMsgMhfAcquireMonthlyReward(s *Session, p mhfpacket.MHFPacket) {
} }
func handleMsgMhfAcceptReadReward(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfAcceptReadReward(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetBreakSeibatuLevelReward(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetWeeklySeibatuRankingReward(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -58,6 +58,42 @@ func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
// if the game gets bad responses for this it breaks the ability to save
pkt := p.(*mhfpacket.MsgMhfGetTenrouirai)
var data []byte
var err error
if pkt.Unk0 == 1 {
data, err = hex.DecodeString("0A218EAD000000000000000000000001010000000000060010")
} else if pkt.Unk2 == 4 {
data, err = hex.DecodeString("0A218EAD0000000000000000000000210101005000000202010102020104001000000202010102020106003200000202010002020104000C003202020101020201030032000002020101020202059C4000000202010002020105C35000320202010102020201003C00000202010102020203003200000201010001020203002800320201010101020204000C00000201010101020206002800000201010001020101003C00320201020101020105C35000000301020101020106003200000301020001020104001000320301020101020105C350000003010201010202030028000003010200010201030032003203010201010202059C4000000301020101010206002800000301020001010201003C00320301020101010206003200000301020101010204000C000003010200010101010050003203010201010101059C40000003010201010101030032000003010200010101040010003203010001010101060032000003010001010102030028000003010001010101010050003203010000010102059C4000000301000001010206002800000301000001010010")
} else {
data = []byte{0x00, 0x00, 0x00, 0x00}
s.logger.Info("GET_TENROUIRAI request for unknown type")
}
if err != nil {
panic(err)
}
doAckBufSucceed(s, pkt.AckHandle, data)
}
func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPostTenrouirai)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
}
func handleMsgMhfGetBreakSeibatuLevelReward(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetWeeklySeibatuRankingReward(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetWeeklySeibatuRankingReward)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfPresentBox(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfPresentBox)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetGemInfo) pkt := p.(*mhfpacket.MsgMhfGetGemInfo)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))

View File

@@ -92,8 +92,7 @@ type RavienteRegister struct {
} }
type RavienteState struct { type RavienteState struct {
damageMultiplier uint32 stateData []uint32
stateData []uint32
} }
type RavienteSupport struct { type RavienteSupport struct {
@@ -111,9 +110,7 @@ func NewRaviente() *Raviente {
maxPlayers: 0, maxPlayers: 0,
carveQuest: 0, carveQuest: 0,
} }
ravienteState := &RavienteState{ ravienteState := &RavienteState{}
damageMultiplier: 1,
}
ravienteSupport := &RavienteSupport{} ravienteSupport := &RavienteSupport{}
ravienteRegister.register = []uint32{0, 0, 0, 0, 0} ravienteRegister.register = []uint32{0, 0, 0, 0, 0}
ravienteState.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} ravienteState.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
@@ -127,6 +124,23 @@ func NewRaviente() *Raviente {
return raviente return raviente
} }
func (r *Raviente) GetRaviMultiplier(s *Server) uint32 {
raviSema := getRaviSemaphore(s)
if raviSema != nil {
var minPlayers uint32
if r.register.maxPlayers > 8 {
minPlayers = 24
} else {
minPlayers = 4
}
if uint32(len(raviSema.clients)) > minPlayers {
return 1
}
return minPlayers / uint32(len(raviSema.clients))
}
return 0
}
// NewServer creates a new Server type. // NewServer creates a new Server type.
func NewServer(config *Config) *Server { func NewServer(config *Config) *Server {
s := &Server{ s := &Server{

View File

@@ -6,6 +6,32 @@ func getLangStrings(s *Server) map[string]string {
case "jp": case "jp":
strings["language"] = "日本語" strings["language"] = "日本語"
strings["cafeReset"] = "%d/%dにリセット" strings["cafeReset"] = "%d/%dにリセット"
strings["commandDisabled"] = "%sのコマンドは無効です"
strings["commandReload"] = "リロードします"
strings["commandKqfGet"] = "現在のキークエストフラグ:%x"
strings["commandKqfSetError"] = "キークエコマンドエラー 例:%s set xxxxxxxxxxxxxxxx"
strings["commandKqfSetSuccess"] = "キークエストのフラグが更新されました。ワールド/ランドを移動してください"
strings["commandRightsError"] = "コース更新コマンドエラー 例:%s x"
strings["commandRightsSuccess"] = "コース情報を更新しました:%d"
strings["commandCourseError"] = "コース確認コマンドエラー 例:%s <name>"
strings["commandCourseDisabled"] = "%sコースは無効です"
strings["commandCourseEnabled"] = "%sコースは有効です"
strings["commandCourseLocked"] = "%sコースはロックされています"
strings["commandTeleportError"] = "テレポートコマンドエラー 構文:%s x y"
strings["commandTeleportSuccess"] = "%d %dにテレポート"
strings["commandRaviNoCommand"] = "ラヴィコマンドが指定されていません"
strings["commandRaviStartSuccess"] = "大討伐を開始します"
strings["commandRaviStartError"] = "大討伐は既に開催されています"
strings["commandRaviMultiplier"] = "ラヴィダメージ倍率:x%d"
strings["commandRaviResSuccess"] = "復活支援を実行します"
strings["commandRaviResError"] = "復活支援は実行されませんでした"
strings["commandRaviSedSuccess"] = "鎮静支援を実行します"
strings["commandRaviRequest"] = "鎮静支援を要請します"
strings["commandRaviError"] = "ラヴィコマンドが認識されません"
strings["commandRaviNoPlayers"] = "誰も大討伐に参加していません"
strings["ravienteBerserk"] = "<大討伐:猛狂期>が開催されました!" strings["ravienteBerserk"] = "<大討伐:猛狂期>が開催されました!"
strings["ravienteExtreme"] = "<大討伐:猛狂期【極】>が開催されました!" strings["ravienteExtreme"] = "<大討伐:猛狂期【極】>が開催されました!"
strings["ravienteExtremeLimited"] = "<大討伐:猛狂期【極】(制限付)>が開催されました!" strings["ravienteExtremeLimited"] = "<大討伐:猛狂期【極】(制限付)>が開催されました!"
@@ -28,6 +54,32 @@ func getLangStrings(s *Server) map[string]string {
default: default:
strings["language"] = "English" strings["language"] = "English"
strings["cafeReset"] = "Resets on %d/%d" strings["cafeReset"] = "Resets on %d/%d"
strings["commandDisabled"] = "%s command is disabled"
strings["commandReload"] = "Reloading players..."
strings["commandKqfGet"] = "KQF: %x"
strings["commandKqfSetError"] = "Error in command. Format: %s set xxxxxxxxxxxxxxxx"
strings["commandKqfSetSuccess"] = "KQF set, please switch Land/World"
strings["commandRightsError"] = "Error in command. Format: %s x"
strings["commandRightsSuccess"] = "Set rights integer: %d"
strings["commandCourseError"] = "Error in command. Format: %s <name>"
strings["commandCourseDisabled"] = "%s Course disabled"
strings["commandCourseEnabled"] = "%s Course enabled"
strings["commandCourseLocked"] = "%s Course is locked"
strings["commandTeleportError"] = "Error in command. Format: %s x y"
strings["commandTeleportSuccess"] = "Teleporting to %d %d"
strings["commandRaviNoCommand"] = "No Raviente command specified!"
strings["commandRaviStartSuccess"] = "The Great Slaying will begin in a moment"
strings["commandRaviStartError"] = "The Great Slaying has already begun!"
strings["commandRaviMultiplier"] = "Raviente multiplier is currently %dx"
strings["commandRaviResSuccess"] = "Sending resurrection support!"
strings["commandRaviResError"] = "Resurrection support has not been requested!"
strings["commandRaviSedSuccess"] = "Sending sedation support if requested!"
strings["commandRaviRequest"] = "Requesting sedation support!"
strings["commandRaviError"] = "Raviente command not recognised!"
strings["commandRaviNoPlayers"] = "No one has joined the Great Slaying!"
strings["ravienteBerserk"] = "<Great Slaying: Berserk> is being held!" strings["ravienteBerserk"] = "<Great Slaying: Berserk> is being held!"
strings["ravienteExtreme"] = "<Great Slaying: Extreme> is being held!" strings["ravienteExtreme"] = "<Great Slaying: Extreme> is being held!"
strings["ravienteExtremeLimited"] = "<Great Slaying: Extreme (Limited)> is being held!" strings["ravienteExtremeLimited"] = "<Great Slaying: Extreme (Limited)> is being held!"