Raviente Patch

This commit is contained in:
wishu
2022-05-04 04:38:10 +10:00
parent 50d46b47c8
commit 4faf8cf9b1
44 changed files with 3375 additions and 595 deletions

View File

@@ -9,11 +9,22 @@ import (
) )
// MsgMhfAcquireUdItem represents the MSG_MHF_ACQUIRE_UD_ITEM // MsgMhfAcquireUdItem represents the MSG_MHF_ACQUIRE_UD_ITEM
type MsgMhfAcquireUdItem struct{ type MsgMhfAcquireUdItem struct {
AckHandle uint32 AckHandle uint32
// Valid field size(s), not sure about the types.
Unk0 uint8 Unk0 uint8
Unk1 uint32 // from gal
// daily = 0
// personal = 1
// personal rank = 2
// guild rank = 3
// gcp = 4
// from cat
// treasure achievement = 5
// personal achievement = 6
// guild achievement = 7
RewardType uint8
Unk2 uint8 // Number of uint32s to read?
Unk3 []byte
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -25,9 +36,12 @@ func (m *MsgMhfAcquireUdItem) Opcode() network.PacketID {
func (m *MsgMhfAcquireUdItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfAcquireUdItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8() m.Unk0 = bf.ReadUint8()
m.Unk1 = bf.ReadUint32() m.RewardType = bf.ReadUint8()
m.Unk2 = bf.ReadUint8()
for i := uint8(0); i < m.Unk2; i++ {
bf.ReadUint32()
}
return nil return nil
//return errors.New("NOT IMPLEMENTED")
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -9,7 +9,10 @@ import (
) )
// MsgMhfAddGuildWeeklyBonusExceptionalUser represents the MSG_MHF_ADD_GUILD_WEEKLY_BONUS_EXCEPTIONAL_USER // MsgMhfAddGuildWeeklyBonusExceptionalUser represents the MSG_MHF_ADD_GUILD_WEEKLY_BONUS_EXCEPTIONAL_USER
type MsgMhfAddGuildWeeklyBonusExceptionalUser struct{} type MsgMhfAddGuildWeeklyBonusExceptionalUser struct {
AckHandle uint32
NumUsers uint8
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfAddGuildWeeklyBonusExceptionalUser) Opcode() network.PacketID { func (m *MsgMhfAddGuildWeeklyBonusExceptionalUser) Opcode() network.PacketID {
@@ -18,7 +21,9 @@ func (m *MsgMhfAddGuildWeeklyBonusExceptionalUser) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfAddGuildWeeklyBonusExceptionalUser) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfAddGuildWeeklyBonusExceptionalUser) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.NumUsers = bf.ReadUint8()
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -11,22 +11,25 @@ import (
type EnumerateGuildType uint8 type EnumerateGuildType uint8
const ( const (
_ = iota ENUMERATE_GUILD_TYPE_GUILD_NAME = 0x01
ENUMERATE_GUILD_TYPE_NAME ENUMERATE_GUILD_TYPE_LEADER_NAME = 0x02
//Numbers correspond to order in guild search menu ENUMERATE_GUILD_TYPE_LEADER_ID = 0x03
ENUMERATE_GUILD_TYPE_6 ENUMERATE_GUILD_TYPE_ORDER_MEMBERS = 0x04
ENUMERATE_GUILD_TYPE_LEADER_ID ENUMERATE_GUILD_TYPE_ORDER_REGISTRATION = 0x05
ENUMERATE_GUILD_TYPE_3 ENUMERATE_GUILD_TYPE_ORDER_RANK = 0x06
ENUMERATE_GUILD_TYPE_2 ENUMERATE_GUILD_TYPE_MOTTO = 0x07
ENUMERATE_GUILD_TYPE_7 ENUMERATE_GUILD_TYPE_RECRUITING = 0x08
ENUMERATE_GUILD_TYPE_8 ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME = 0x09
ENUMERATE_GUILD_TYPE_NEW ENUMERATE_ALLIANCE_TYPE_LEADER_NAME = 0x0A
ENUMERATE_ALLIANCE_TYPE_LEADER_ID = 0x0B
ENUMERATE_ALLIANCE_TYPE_ORDER_MEMBERS = 0x0C
ENUMERATE_ALLIANCE_TYPE_ORDER_REGISTRATION = 0x0D
) )
// MsgMhfEnumerateGuild represents the MSG_MHF_ENUMERATE_GUILD // MsgMhfEnumerateGuild represents the MSG_MHF_ENUMERATE_GUILD
type MsgMhfEnumerateGuild struct { type MsgMhfEnumerateGuild struct {
AckHandle uint32 AckHandle uint32
Type uint8 Type EnumerateGuildType
RawDataPayload []byte RawDataPayload []byte
} }
@@ -38,9 +41,9 @@ func (m *MsgMhfEnumerateGuild) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfEnumerateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfEnumerateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Type = bf.ReadUint8() m.Type = EnumerateGuildType(bf.ReadUint8())
m.RawDataPayload = bf.DataFromCurrent() m.RawDataPayload = bf.DataFromCurrent()
bf.Seek(int64(len(bf.Data()) - 2), 0)
return nil return nil
} }

View File

@@ -11,6 +11,8 @@ import (
// MsgMhfEnumerateGuildItem represents the MSG_MHF_ENUMERATE_GUILD_ITEM // MsgMhfEnumerateGuildItem represents the MSG_MHF_ENUMERATE_GUILD_ITEM
type MsgMhfEnumerateGuildItem struct { type MsgMhfEnumerateGuildItem struct {
AckHandle uint32 AckHandle uint32
GuildId uint32
Unk0 uint16
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -20,8 +22,9 @@ func (m *MsgMhfEnumerateGuildItem) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfEnumerateGuildItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfEnumerateGuildItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.GuildId = bf.ReadUint32()
m.Unk0 = bf.ReadUint16()
return nil return nil
} }

View File

@@ -0,0 +1,37 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfEnumerateGuildMessageBoard represents the MSG_MHF_ENUMERATE_GUILD_MESSAGE_BOARD
type MsgMhfEnumerateGuildMessageBoard struct{
AckHandle uint32
Unk0 uint32
MaxPosts uint32 // always 100, even on news (00000064)
// returning more than 4 news posts WILL softlock
BoardType uint32 // 0 => message, 1 => news
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfEnumerateGuildMessageBoard) Opcode() network.PacketID {
return network.MSG_MHF_ENUMERATE_GUILD_MESSAGE_BOARD
}
// Parse parses the packet from binary
func (m *MsgMhfEnumerateGuildMessageBoard) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint32()
m.MaxPosts = bf.ReadUint32()
m.BoardType = bf.ReadUint32()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfEnumerateGuildMessageBoard) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -9,7 +9,10 @@ import (
) )
// MsgMhfEnumerateUnionItem represents the MSG_MHF_ENUMERATE_UNION_ITEM // MsgMhfEnumerateUnionItem represents the MSG_MHF_ENUMERATE_UNION_ITEM
type MsgMhfEnumerateUnionItem struct{} type MsgMhfEnumerateUnionItem struct {
AckHandle uint32
Unk0 uint16
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfEnumerateUnionItem) Opcode() network.PacketID { func (m *MsgMhfEnumerateUnionItem) Opcode() network.PacketID {
@@ -18,7 +21,10 @@ func (m *MsgMhfEnumerateUnionItem) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfEnumerateUnionItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfEnumerateUnionItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint16()
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -10,10 +10,9 @@ import (
// MsgMhfGetAchievement represents the MSG_MHF_GET_ACHIEVEMENT // MsgMhfGetAchievement represents the MSG_MHF_GET_ACHIEVEMENT
type MsgMhfGetAchievement struct{ type MsgMhfGetAchievement struct{
AckHandle uint32 AckHandle uint32
Unk0 uint16 // id? Unk0 uint32 // id?
Unk1 uint32 // char? Unk1 uint32 // char?
Unk2 uint32 // pad?
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -23,10 +22,9 @@ func (m *MsgMhfGetAchievement) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfGetAchievement) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfGetAchievement) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint16() m.Unk0 = bf.ReadUint32()
m.Unk1 = bf.ReadUint32() m.Unk1 = bf.ReadUint32()
m.Unk2 = bf.ReadUint32()
return nil return nil
} }

View File

@@ -11,6 +11,7 @@ import (
// MsgMhfGetUdRanking represents the MSG_MHF_GET_UD_RANKING // MsgMhfGetUdRanking represents the MSG_MHF_GET_UD_RANKING
type MsgMhfGetUdRanking struct{ type MsgMhfGetUdRanking struct{
AckHandle uint32 AckHandle uint32
Unk0 uint8
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -20,8 +21,9 @@ func (m *MsgMhfGetUdRanking) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfGetUdRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfGetUdRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
return nil m.Unk0 = bf.ReadUint8()
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -9,7 +9,10 @@ import (
) )
// MsgMhfGetUdTacticsRanking represents the MSG_MHF_GET_UD_TACTICS_RANKING // MsgMhfGetUdTacticsRanking represents the MSG_MHF_GET_UD_TACTICS_RANKING
type MsgMhfGetUdTacticsRanking struct{} type MsgMhfGetUdTacticsRanking struct {
AckHandle uint32
GuildID uint32
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfGetUdTacticsRanking) Opcode() network.PacketID { func (m *MsgMhfGetUdTacticsRanking) Opcode() network.PacketID {
@@ -18,7 +21,9 @@ func (m *MsgMhfGetUdTacticsRanking) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfGetUdTacticsRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfGetUdTacticsRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.GuildID = bf.ReadUint32()
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -11,6 +11,7 @@ import (
// MsgMhfListMail represents the MSG_MHF_LIST_MAIL // MsgMhfListMail represents the MSG_MHF_LIST_MAIL
type MsgMhfListMail struct { type MsgMhfListMail struct {
AckHandle uint32 AckHandle uint32
Unk0 uint32
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -21,6 +22,7 @@ func (m *MsgMhfListMail) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfListMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfListMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint32()
return nil return nil
} }

View File

@@ -11,14 +11,29 @@ import (
type OperateGuildAction uint8 type OperateGuildAction uint8
const ( const (
OPERATE_GUILD_ACTION_DISBAND = 0x01 OPERATE_GUILD_DISBAND = 0x01
OPERATE_GUILD_ACTION_APPLY = 0x02 OPERATE_GUILD_APPLY = 0x02
OPERATE_GUILD_ACTION_LEAVE = 0x03 OPERATE_GUILD_LEAVE = 0x03
OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE = 0x07 OPERATE_GUILD_RESIGN = 0x04
OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE = 0x08 OPERATE_GUILD_SET_APPLICATION_DENY = 0x05
OPERATE_GUILD_ACTION_UPDATE_COMMENT = 0x09 OPERATE_GUILD_SET_APPLICATION_ALLOW = 0x06
OPERATE_GUILD_ACTION_DONATE = 0x0a OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE = 0x07
OPERATE_GUILD_ACTION_UPDATE_MOTTO = 0x0b OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE = 0x08
OPERATE_GUILD_UPDATE_COMMENT = 0x09
OPERATE_GUILD_DONATE_RANK = 0x0a
OPERATE_GUILD_UPDATE_MOTTO = 0x0b
OPERATE_GUILD_RENAME_PUGI_1 = 0x0c
OPERATE_GUILD_RENAME_PUGI_2 = 0x0d
OPERATE_GUILD_RENAME_PUGI_3 = 0x0e
OPERATE_GUILD_CHANGE_PUGI_1 = 0x0f
OPERATE_GUILD_CHANGE_PUGI_2 = 0x10
OPERATE_GUILD_CHANGE_PUGI_3 = 0x11
// pugi something
OPERATE_GUILD_DONATE_EVENT = 0x15
// pugi something
OPERATE_GUILD_CHANGE_DIVA_PUGI_1 = 0x19
OPERATE_GUILD_CHANGE_DIVA_PUGI_2 = 0x1a
OPERATE_GUILD_CHANGE_DIVA_PUGI_3 = 0x1b
) )
// MsgMhfOperateGuild represents the MSG_MHF_OPERATE_GUILD // MsgMhfOperateGuild represents the MSG_MHF_OPERATE_GUILD
@@ -40,7 +55,7 @@ func (m *MsgMhfOperateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien
m.GuildID = bf.ReadUint32() m.GuildID = bf.ReadUint32()
m.Action = OperateGuildAction(bf.ReadUint8()) m.Action = OperateGuildAction(bf.ReadUint8())
m.UnkData = bf.DataFromCurrent() m.UnkData = bf.DataFromCurrent()
bf.Seek(int64(len(bf.Data()) - 2), 0)
return nil return nil
} }

View File

@@ -8,8 +8,22 @@ import (
"github.com/Andoryuuta/byteframe" "github.com/Andoryuuta/byteframe"
) )
type OperateJointAction uint8
const (
OPERATE_JOINT_DISBAND = 0x01
OPERATE_JOINT_LEAVE = 0x03
OPERATE_JOINT_KICK = 0x09
)
// MsgMhfOperateJoint represents the MSG_MHF_OPERATE_JOINT // MsgMhfOperateJoint represents the MSG_MHF_OPERATE_JOINT
type MsgMhfOperateJoint struct{} type MsgMhfOperateJoint struct {
AckHandle uint32
AllianceID uint32
GuildID uint32
Action OperateJointAction
UnkData []byte
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfOperateJoint) Opcode() network.PacketID { func (m *MsgMhfOperateJoint) Opcode() network.PacketID {
@@ -18,7 +32,13 @@ func (m *MsgMhfOperateJoint) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfOperateJoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfOperateJoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.AllianceID = bf.ReadUint32()
m.GuildID = bf.ReadUint32()
m.Action = OperateJointAction(bf.ReadUint8())
m.UnkData = bf.DataFromCurrent()
bf.Seek(int64(len(bf.Data()) - 2), 0)
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -11,15 +11,20 @@ import (
type OperateMailOperation uint8 type OperateMailOperation uint8
const ( const (
OperateMailOperationDelete OperateMailOperation = 0x01 OPERATE_MAIL_DELETE = 0x01
OPERATE_MAIL_ACQUIRE_ITEM = 0x05
) )
// MsgMhfOprtMail represents the MSG_MHF_OPRT_MAIL // MsgMhfOprtMail represents the MSG_MHF_OPRT_MAIL
type MsgMhfOprtMail struct { type MsgMhfOprtMail struct {
AckHandle uint32 AckHandle uint32
AccIndex uint8 AccIndex uint8
Index uint8 Index uint8
Operation uint8 Operation OperateMailOperation
Unk0 uint8
Data []byte
Amount uint16
ItemID uint16
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -29,10 +34,16 @@ func (m *MsgMhfOprtMail) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfOprtMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfOprtMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.AccIndex = bf.ReadUint8() m.AccIndex = bf.ReadUint8()
m.Index = bf.ReadUint8() m.Index = bf.ReadUint8()
m.Operation = bf.ReadUint8() m.Operation = OperateMailOperation(bf.ReadUint8())
m.Unk0 = bf.ReadUint8()
switch m.Operation {
case OPERATE_MAIL_ACQUIRE_ITEM:
m.Amount = bf.ReadUint16()
m.ItemID = bf.ReadUint16()
}
return nil return nil
} }

View File

@@ -19,6 +19,7 @@ type MsgMhfReadMail struct {
// This is the index within the current mail list // This is the index within the current mail list
Index uint8 Index uint8
Unk0 uint16
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -31,6 +32,7 @@ func (m *MsgMhfReadMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientCon
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.AccIndex = bf.ReadUint8() m.AccIndex = bf.ReadUint8()
m.Index = bf.ReadUint8() m.Index = bf.ReadUint8()
m.Unk0 = bf.ReadUint16()
return nil return nil
} }

View File

@@ -9,7 +9,16 @@ import (
) )
// MsgMhfSendMail represents the MSG_MHF_SEND_MAIL // MsgMhfSendMail represents the MSG_MHF_SEND_MAIL
type MsgMhfSendMail struct{} type MsgMhfSendMail struct {
AckHandle uint32
RecipientID uint32
SubjectLength uint16
BodyLength uint16
Quantity uint32
ItemID uint16
Subject []byte
Body []byte
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfSendMail) Opcode() network.PacketID { func (m *MsgMhfSendMail) Opcode() network.PacketID {
@@ -18,7 +27,15 @@ func (m *MsgMhfSendMail) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfSendMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfSendMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.RecipientID = bf.ReadUint32()
m.SubjectLength = bf.ReadUint16()
m.BodyLength = bf.ReadUint16()
m.Quantity = bf.ReadUint32()
m.ItemID = bf.ReadUint16()
m.Subject = bf.ReadNullTerminatedBytes()
m.Body = bf.ReadNullTerminatedBytes()
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -9,7 +9,10 @@ import (
) )
// MsgMhfSetGuildMissionTarget represents the MSG_MHF_SET_GUILD_MISSION_TARGET // MsgMhfSetGuildMissionTarget represents the MSG_MHF_SET_GUILD_MISSION_TARGET
type MsgMhfSetGuildMissionTarget struct{} type MsgMhfSetGuildMissionTarget struct {
AckHandle uint32
MissionID uint32
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfSetGuildMissionTarget) Opcode() network.PacketID { func (m *MsgMhfSetGuildMissionTarget) Opcode() network.PacketID {
@@ -18,7 +21,9 @@ func (m *MsgMhfSetGuildMissionTarget) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfSetGuildMissionTarget) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfSetGuildMissionTarget) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.MissionID = bf.ReadUint32()
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -11,11 +11,12 @@ import (
type GuildIconMsgPart struct { type GuildIconMsgPart struct {
Index uint16 Index uint16
ID uint16 ID uint16
Unk0 uint8 Page uint8
Size uint8 Size uint8
Rotation uint8 Rotation uint8
Unk1 uint8 Red uint8
Unk2 uint16 Green uint8
Blue uint8
PosX uint16 PosX uint16
PosY uint16 PosY uint16
} }
@@ -47,11 +48,12 @@ func (m *MsgMhfUpdateGuildIcon) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cl
m.IconParts[i] = GuildIconMsgPart{ m.IconParts[i] = GuildIconMsgPart{
Index: bf.ReadUint16(), Index: bf.ReadUint16(),
ID: bf.ReadUint16(), ID: bf.ReadUint16(),
Unk0: bf.ReadUint8(), Page: bf.ReadUint8(),
Size: bf.ReadUint8(), Size: bf.ReadUint8(),
Rotation: bf.ReadUint8(), Rotation: bf.ReadUint8(),
Unk1: bf.ReadUint8(), Red: bf.ReadUint8(),
Unk2: bf.ReadUint16(), Green: bf.ReadUint8(),
Blue: bf.ReadUint8(),
PosX: bf.ReadUint16(), PosX: bf.ReadUint16(),
PosY: bf.ReadUint16(), PosY: bf.ReadUint16(),
} }

View File

@@ -8,8 +8,21 @@ import (
"github.com/Andoryuuta/byteframe" "github.com/Andoryuuta/byteframe"
) )
type Item struct{
Unk0 uint32
ItemId uint16
Amount uint16
Unk1 uint32
}
// MsgMhfUpdateGuildItem represents the MSG_MHF_UPDATE_GUILD_ITEM // MsgMhfUpdateGuildItem represents the MSG_MHF_UPDATE_GUILD_ITEM
type MsgMhfUpdateGuildItem struct{} type MsgMhfUpdateGuildItem struct{
AckHandle uint32
GuildId uint32
Amount uint16
Unk1 uint16 // 0x00 0x00
Items []Item // Array of updated item IDs
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfUpdateGuildItem) Opcode() network.PacketID { func (m *MsgMhfUpdateGuildItem) Opcode() network.PacketID {
@@ -18,7 +31,20 @@ func (m *MsgMhfUpdateGuildItem) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfUpdateGuildItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfUpdateGuildItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.GuildId = bf.ReadUint32()
m.Amount = bf.ReadUint16()
m.Unk1 = bf.ReadUint16()
m.Items = make([]Item, int(m.Amount))
for i := 0; i < int(m.Amount); i++ {
m.Items[i].Unk0 = bf.ReadUint32()
m.Items[i].ItemId = bf.ReadUint16()
m.Items[i].Amount = bf.ReadUint16()
m.Items[i].Unk1 = bf.ReadUint32()
}
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -0,0 +1,37 @@
package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgMhfUpdateGuildMessageBoard represents the MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD
type MsgMhfUpdateGuildMessageBoard struct {
AckHandle uint32
MessageOp uint32
Request []byte
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfUpdateGuildMessageBoard) Opcode() network.PacketID {
return network.MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD
}
// Parse parses the packet from binary
func (m *MsgMhfUpdateGuildMessageBoard) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.MessageOp = bf.ReadUint32()
if m.MessageOp != 5 {
m.Request = bf.DataFromCurrent()
bf.Seek(int64(len(bf.Data()) - 2), 0)
}
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgMhfUpdateGuildMessageBoard) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -9,7 +9,12 @@ import (
) )
// MsgMhfUpdateUnionItem represents the MSG_MHF_UPDATE_UNION_ITEM // MsgMhfUpdateUnionItem represents the MSG_MHF_UPDATE_UNION_ITEM
type MsgMhfUpdateUnionItem struct{} type MsgMhfUpdateUnionItem struct {
AckHandle uint32
Amount uint16
Unk1 uint16 // 0x00 0x00
Items []Item // Array of updated item IDs
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgMhfUpdateUnionItem) Opcode() network.PacketID { func (m *MsgMhfUpdateUnionItem) Opcode() network.PacketID {
@@ -18,7 +23,19 @@ func (m *MsgMhfUpdateUnionItem) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfUpdateUnionItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfUpdateUnionItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") m.AckHandle = bf.ReadUint32()
m.Amount = bf.ReadUint16()
m.Unk1 = bf.ReadUint16()
m.Items = make([]Item, int(m.Amount))
for i := 0; i < int(m.Amount); i++ {
m.Items[i].Unk0 = bf.ReadUint32()
m.Items[i].ItemId = bf.ReadUint16()
m.Items[i].Amount = bf.ReadUint16()
m.Items[i].Unk1 = 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,27 +1 @@
package mhfpacket package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// MsgSysReserve202 represents the MSG_SYS_reserve202
type MsgSysReserve202 struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgSysReserve202) Opcode() network.PacketID {
return network.MSG_SYS_reserve202
}
// Parse parses the packet from binary
func (m *MsgSysReserve202) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.
func (m *MsgSysReserve202) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -1,36 +1 @@
package mhfpacket package mhfpacket
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// TODO(Andoryuuta): Make up a name for this packet, not reserved anymore. Called "Is_update_guild_msg_board"
// MsgSysReserve203 represents the MSG_SYS_reserve203
type MsgSysReserve203 struct {
AckHandle uint32
Unk0 uint16 // Hardcoded 0x0000 in the binary
Unk1 uint16 // Hardcoded 0x0500 in the binary.
}
// Opcode returns the ID associated with this packet type.
func (m *MsgSysReserve203) Opcode() network.PacketID {
return network.MSG_SYS_reserve203
}
// Parse parses the packet from binary
func (m *MsgSysReserve203) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint16()
m.Unk1 = bf.ReadUint16()
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgSysReserve203) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -9,7 +9,12 @@ import (
) )
// MsgSysReserve205 represents the MSG_SYS_reserve205 // MsgSysReserve205 represents the MSG_SYS_reserve205
type MsgSysReserve205 struct{} type MsgSysReserve205 struct {
AckHandle uint32
Unk0 uint32
Unk1 uint32
Unk2 uint32
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgSysReserve205) Opcode() network.PacketID { func (m *MsgSysReserve205) Opcode() network.PacketID {
@@ -18,7 +23,11 @@ func (m *MsgSysReserve205) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgSysReserve205) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgSysReserve205) 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()
return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -841,10 +841,10 @@ func FromOpcode(opcode network.PacketID) MHFPacket {
return &MsgMhfUpdateForceGuildRank{} return &MsgMhfUpdateForceGuildRank{}
case network.MSG_MHF_RESET_TITLE: case network.MSG_MHF_RESET_TITLE:
return &MsgMhfResetTitle{} return &MsgMhfResetTitle{}
case network.MSG_SYS_reserve202: case network.MSG_MHF_ENUMERATE_GUILD_MESSAGE_BOARD:
return &MsgSysReserve202{} return &MsgMhfEnumerateGuildMessageBoard{}
case network.MSG_SYS_reserve203: case network.MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD:
return &MsgSysReserve203{} return &MsgMhfUpdateGuildMessageBoard{}
case network.MSG_SYS_reserve204: case network.MSG_SYS_reserve204:
return &MsgSysReserve204{} return &MsgSysReserve204{}
case network.MSG_SYS_reserve205: case network.MSG_SYS_reserve205:

View File

@@ -423,8 +423,8 @@ const (
MSG_SYS_reserve19F MSG_SYS_reserve19F
MSG_MHF_UPDATE_FORCE_GUILD_RANK MSG_MHF_UPDATE_FORCE_GUILD_RANK
MSG_MHF_RESET_TITLE MSG_MHF_RESET_TITLE
MSG_SYS_reserve202 MSG_MHF_ENUMERATE_GUILD_MESSAGE_BOARD
MSG_SYS_reserve203 MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD
MSG_SYS_reserve204 MSG_SYS_reserve204
MSG_SYS_reserve205 MSG_SYS_reserve205
MSG_SYS_reserve206 MSG_SYS_reserve206

File diff suppressed because one or more lines are too long

View File

@@ -3,6 +3,7 @@ package channelserver
import ( import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"encoding/binary"
"io/ioutil" "io/ioutil"
"math/bits" "math/bits"
"math/rand" "math/rand"
@@ -74,16 +75,7 @@ func doAckSimpleFail(s *Session, ackHandle uint32, data []byte) {
func updateRights(s *Session) { func updateRights(s *Session) {
update := &mhfpacket.MsgSysUpdateRight{ update := &mhfpacket.MsgSysUpdateRight{
ClientRespAckHandle: 0, ClientRespAckHandle: 0,
Unk1: 0x0E, //0e with normal sub 4e when having premium it's probably a bitfield? Unk1: s.rights,
// 01 = Character can take quests at allows
// 02 = Hunter Life, normal quests core sub
// 03 = Extra Course, extra quests, town boxes, QOL course, core sub
// 06 = Premium Course, standard 'premium' which makes ranking etc. faster
// some connection to unk1 above for these maybe?
// 06 0A 0B = Boost Course, just actually 3 subs combined
// 08 09 1E = N Course, gives you the benefits of being in a netcafe (extra quests, N Points, daily freebies etc.) minimal and pointless
// no timestamp after 08 or 1E while active
// 0C = N Boost course, ultra luxury course that ruins the game if in use but also gives a
Rights: []mhfpacket.ClientRight{ Rights: []mhfpacket.ClientRight{
{ {
ID: 1, ID: 1,
@@ -143,10 +135,25 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysLogin) pkt := p.(*mhfpacket.MsgSysLogin)
name := "" name := ""
rights := uint32(0x0E)
// 0e with normal sub 4e when having premium
// 01 = Character can take quests at allows
// 02 = Hunter Life, normal quests core sub
// 03 = Extra Course, extra quests, town boxes, QOL course, core sub
// 06 = Premium Course, standard 'premium' which makes ranking etc. faster
// 06 0A 0B = Boost Course, just actually 3 subs combined
// 08 09 1E = N Course, gives you the benefits of being in a netcafe (extra quests, N Points, daily freebies etc.) minimal and pointless
// 0C = N Boost course, ultra luxury course that ruins the game if in use
err := s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", pkt.CharID0).Scan(&rights)
if err != nil {
panic(err)
}
s.server.db.QueryRow("SELECT name FROM characters WHERE id = $1", pkt.CharID0).Scan(&name) s.server.db.QueryRow("SELECT name FROM characters WHERE id = $1", pkt.CharID0).Scan(&name)
s.Lock() s.Lock()
s.Name = name s.Name = name
s.charID = pkt.CharID0 s.charID = pkt.CharID0
s.rights = rights
s.Unlock() s.Unlock()
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint32(uint32(Time_Current_Adjusted().Unix())) // Unix timestamp bf.WriteUint32(uint32(Time_Current_Adjusted().Unix())) // Unix timestamp
@@ -158,7 +165,7 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
} }
} }
_, err := s.server.db.Exec("UPDATE characters SET last_login=$1 WHERE id=$2", Time_Current().Unix(), s.charID) _, err = s.server.db.Exec("UPDATE characters SET last_login=$1 WHERE id=$2", Time_Current().Unix(), s.charID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -191,6 +198,46 @@ func logoutPlayer(s *Session) {
} }
removeSessionFromStage(s) removeSessionFromStage(s)
if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists {
if _, ok := s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots[s.charID]; ok {
removeSessionFromSemaphore(s)
}
}
var timePlayed int
err := s.server.db.QueryRow("SELECT time_played FROM characters WHERE id = $1", s.charID).Scan(&timePlayed)
timePlayed = (int(Time_Current_Adjusted().Unix()) - int(s.sessionStart)) + timePlayed
var rpGained int
if s.rights == 0x08091e4e || s.rights == 0x08091e0e { // N Course
rpGained = timePlayed / 900
timePlayed = timePlayed % 900
} else {
rpGained = timePlayed / 1800
timePlayed = timePlayed % 1800
}
_, err = s.server.db.Exec("UPDATE characters SET time_played = $1 WHERE id = $2", timePlayed, s.charID)
if err != nil {
panic(err)
}
saveData, err := GetCharacterSaveData(s, s.charID)
if err != nil {
panic(err)
}
saveData.RP += uint16(rpGained)
transaction, err := s.server.db.Begin()
err = saveData.Save(s, transaction)
if err != nil {
transaction.Rollback()
panic(err)
} else {
transaction.Commit()
}
} }
func handleMsgSysSetStatus(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysSetStatus(s *Session, p mhfpacket.MHFPacket) {}
@@ -208,6 +255,8 @@ func handleMsgSysTime(s *Session, p mhfpacket.MHFPacket) {
Timestamp: uint32(Time_Current_Adjusted().Unix()), // JP timezone Timestamp: uint32(Time_Current_Adjusted().Unix()), // JP timezone
} }
s.QueueSendMHF(resp) s.QueueSendMHF(resp)
s.notifyticker()
} }
func handleMsgSysIssueLogkey(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysIssueLogkey(s *Session, p mhfpacket.MHFPacket) {
@@ -356,15 +405,92 @@ func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfEnumerateUnionItem(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfEnumerateUnionItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateUnionItem)
var boxContents []byte
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)
if err != nil {
s.logger.Fatal("Failed to get shared item box contents from db", zap.Error(err))
} else {
if len(boxContents) == 0 {
bf.WriteUint32(0x00)
} else {
amount := len(boxContents) / 4
bf.WriteUint16(uint16(amount))
bf.WriteUint32(0x00)
bf.WriteUint16(0x00)
for i := 0; i < amount; i++ {
bf.WriteUint32(binary.BigEndian.Uint32(boxContents[i*4 : i*4+4]))
if i+1 != amount {
bf.WriteUint64(0x00)
}
}
}
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
func handleMsgMhfUpdateUnionItem(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfUpdateUnionItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateUnionItem)
// Get item cache from DB
var boxContents []byte
var oldItems []Item
func handleMsgMhfCreateJoint(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)
if err != nil {
s.logger.Fatal("Failed to get shared item box contents from db", zap.Error(err))
} else {
amount := len(boxContents) / 4
oldItems = make([]Item, amount)
for i := 0; i < amount; i++ {
oldItems[i].ItemId = binary.BigEndian.Uint16(boxContents[i*4 : i*4+2])
oldItems[i].Amount = binary.BigEndian.Uint16(boxContents[i*4+2 : i*4+4])
}
}
func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {} // Update item stacks
newItems := make([]Item, len(oldItems))
copy(newItems, oldItems)
for i := 0; i < int(pkt.Amount); i++ {
for j := 0; j <= len(oldItems); j++ {
if j == len(oldItems) {
var newItem Item
newItem.ItemId = pkt.Items[i].ItemId
newItem.Amount = pkt.Items[i].Amount
newItems = append(newItems, newItem)
break
}
if pkt.Items[i].ItemId == oldItems[j].ItemId {
newItems[j].Amount = pkt.Items[i].Amount
break
}
}
}
func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {} // Delete empty item stacks
for i := len(newItems) - 1; i >= 0; i-- {
if int(newItems[i].Amount) == 0 {
copy(newItems[i:], newItems[i+1:])
newItems[len(newItems)-1] = make([]Item, 1)[0]
newItems = newItems[:len(newItems)-1]
}
}
// Create new item cache
bf := byteframe.NewByteFrame()
for i := 0; i < len(newItems); i++ {
bf.WriteUint16(newItems[i].ItemId)
bf.WriteUint16(newItems[i].Amount)
}
// 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))
if err != nil {
s.logger.Fatal("Failed to update shared item box contents in db", zap.Error(err))
}
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
func handleMsgMhfAcquireCafeItem(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireCafeItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireCafeItem) pkt := p.(*mhfpacket.MsgMhfAcquireCafeItem)

View File

@@ -2,8 +2,8 @@ package channelserver
import ( import (
"fmt" "fmt"
"math"
"strings" "strings"
"math"
"github.com/Andoryuuta/byteframe" "github.com/Andoryuuta/byteframe"
"github.com/Solenataris/Erupe/network/binpacket" "github.com/Solenataris/Erupe/network/binpacket"
@@ -22,6 +22,7 @@ const (
const ( const (
BroadcastTypeTargeted = 0x01 BroadcastTypeTargeted = 0x01
BroadcastTypeStage = 0x03 BroadcastTypeStage = 0x03
BroadcastTypeRavi = 0x06
BroadcastTypeWorld = 0x0a BroadcastTypeWorld = 0x0a
) )
@@ -51,15 +52,14 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysCastBinary) pkt := p.(*mhfpacket.MsgSysCastBinary)
if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x03 && len(pkt.RawDataPayload) == 0x10 { if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x03 && len(pkt.RawDataPayload) == 0x10 {
tmp := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) tmp := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
if tmp.ReadUint16() == 0x0002 && tmp.ReadUint8() == 0x18 {
if tmp.ReadUint16() == 0x0002 && tmp.ReadUint8() == 0x18 { _ = tmp.ReadBytes(9)
_ = tmp.ReadBytes(9) tmp.SetLE()
tmp.SetLE() frame := tmp.ReadUint32()
frame := tmp.ReadUint32() sendServerChatMessage(s, fmt.Sprintf("TIME : %d'%d.%03d (%dframe)", frame/30/60, frame/30%60, int(math.Round(float64(frame%30*100)/3)), frame))
sendServerChatMessage(s, fmt.Sprintf("TIME : %d'%d.%03d (%dframe)", frame/30/60, frame/30%60, int(math.Round(float64(frame%30*100)/3)), frame))
}
} }
}
// Parse out the real casted binary payload // Parse out the real casted binary payload
var realPayload []byte var realPayload []byte
@@ -93,6 +93,11 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
s.server.BroadcastMHF(resp, s) s.server.BroadcastMHF(resp, s)
case BroadcastTypeStage: case BroadcastTypeStage:
s.stage.BroadcastMHF(resp, s) s.stage.BroadcastMHF(resp, s)
case BroadcastTypeRavi:
if pkt.MessageType == 1 {
session := s.server.semaphore["hs_l0u3B51J9k3"]
(*session).BroadcastMHF(resp, s)
}
case BroadcastTypeTargeted: case BroadcastTypeTargeted:
for _, targetID := range (*msgBinTargeted).TargetCharIDs { for _, targetID := range (*msgBinTargeted).TargetCharIDs {
char := s.server.FindSessionByCharID(targetID) char := s.server.FindSessionByCharID(targetID)
@@ -129,6 +134,114 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
s.server.discordSession.ChannelMessageSend(s.server.erupeConfig.Discord.ChannelID, message) s.server.discordSession.ChannelMessageSend(s.server.erupeConfig.Discord.ChannelID, message)
} }
// RAVI COMMANDS
if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists {
s.server.semaphoreLock.Lock()
getSemaphore := s.server.semaphore["hs_l0u3B51J9k3"]
s.server.semaphoreLock.Unlock()
if _, exists := getSemaphore.reservedClientSlots[s.charID]; exists {
if strings.HasPrefix(chatMessage.Message, "!ravistart") {
row := s.server.db.QueryRow("SELECT raviposttime, ravistarted FROM raviregister WHERE refid = 12")
var raviPosted, raviStarted uint32
err := row.Scan(&raviPosted, &raviStarted)
if err != nil {
panic(err)
return
}
if raviStarted == 0 {
sendServerChatMessage(s, fmt.Sprintf("Raviente will start in less than 10 seconds"))
s.server.db.Exec("UPDATE raviregister SET ravistarted = $1", raviPosted)
} else {
sendServerChatMessage(s, fmt.Sprintf("Raviente has already started"))
}
}
if strings.HasPrefix(chatMessage.Message, "!bressend") {
row := s.server.db.QueryRow("SELECT unknown20 FROM ravistate WHERE refid = 29")
var berserkRes uint32
err := row.Scan(&berserkRes)
if err != nil {
panic(err)
return
}
if berserkRes > 0 {
sendServerChatMessage(s, fmt.Sprintf("Sending ressurection support"))
s.server.db.Exec("UPDATE ravistate SET unknown20 = $1", 0)
} else {
sendServerChatMessage(s, fmt.Sprintf("Ressurection support has not been requested"))
}
}
if strings.HasPrefix(chatMessage.Message, "!bsedsend") {
hprow := s.server.db.QueryRow("SELECT phase1hp, phase2hp, phase3hp, phase4hp, phase5hp FROM ravistate WHERE refid = 29")
var phase1HP, phase2HP, phase3HP, phase4HP, phase5HP uint32
hperr := hprow.Scan(&phase1HP, &phase2HP, &phase3HP, &phase4HP, &phase5HP)
if hperr != nil {
panic(hperr)
return
}
row := s.server.db.QueryRow("SELECT support2 FROM ravisupport WHERE refid = 25")
var berserkTranq uint32
err := row.Scan(&berserkTranq)
if err != nil {
panic(err)
return
}
sendServerChatMessage(s, fmt.Sprintf("Sending sedation support if requested"))
s.server.db.Exec("UPDATE ravisupport SET support2 = $1", (phase1HP + phase2HP + phase3HP + phase4HP + phase5HP))
}
if strings.HasPrefix(chatMessage.Message, "!bsedreq") {
hprow := s.server.db.QueryRow("SELECT phase1hp, phase2hp, phase3hp, phase4hp, phase5hp FROM ravistate WHERE refid = 29")
var phase1HP, phase2HP, phase3HP, phase4HP, phase5HP uint32
hperr := hprow.Scan(&phase1HP, &phase2HP, &phase3HP, &phase4HP, &phase5HP)
if hperr != nil {
panic(hperr)
return
}
row := s.server.db.QueryRow("SELECT support2 FROM ravisupport WHERE refid = 25")
var berserkTranq uint32
err := row.Scan(&berserkTranq)
if err != nil {
panic(err)
return
}
sendServerChatMessage(s, fmt.Sprintf("Requesting sedation support"))
s.server.db.Exec("UPDATE ravisupport SET support2 = $1", ((phase1HP + phase2HP + phase3HP + phase4HP + phase5HP) + 12))
}
if strings.HasPrefix(chatMessage.Message, "!setmultiplier ") {
var num uint8
n, numerr := fmt.Sscanf(chatMessage.Message, "!setmultiplier %d", &num)
row := s.server.db.QueryRow("SELECT damagemultiplier FROM ravistate WHERE refid = 29")
var damageMultiplier uint32
err := row.Scan(&damageMultiplier)
if err != nil {
panic(err)
return
}
if numerr != nil || n != 1 {
sendServerChatMessage(s, fmt.Sprintf("Please use the format !setmultiplier x"))
} else if damageMultiplier == 1 {
if num > 20 {
sendServerChatMessage(s, fmt.Sprintf("Max multiplier for Ravi is 20, setting to this value"))
s.server.db.Exec("UPDATE ravistate SET damagemultiplier = $1", 20)
} else {
sendServerChatMessage(s, fmt.Sprintf("Setting Ravi damage multiplier to %d", num))
s.server.db.Exec("UPDATE ravistate SET damagemultiplier = $1", num)
}
} else {
sendServerChatMessage(s, fmt.Sprintf("Multiplier can only be set once, please restart Ravi to set again"))
}
}
if strings.HasPrefix(chatMessage.Message, "!checkmultiplier") {
var damageMultiplier uint32
row := s.server.db.QueryRow("SELECT damagemultiplier FROM ravistate WHERE refid = 29").Scan(&damageMultiplier)
if row != nil {
return
}
sendServerChatMessage(s, fmt.Sprintf("Ravi's current damage multiplier is %d", damageMultiplier))
}
}
}
// END OF RAVI COMMANDS
if strings.HasPrefix(chatMessage.Message, "!tele ") { if strings.HasPrefix(chatMessage.Message, "!tele ") {
var x, y int16 var x, y int16
n, err := fmt.Sscanf(chatMessage.Message, "!tele %d %d", &x, &y) n, err := fmt.Sscanf(chatMessage.Message, "!tele %d %d", &x, &y)

View File

@@ -59,7 +59,11 @@ func handleMsgMhfListMember(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) doAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
func handleMsgMhfOprMember(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfOprMember(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfListMember)
// TODO: add targetid(uint32) to charid(uint32)'s database under new field
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfShutClient(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfShutClient(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -2,6 +2,7 @@ package channelserver
import ( import (
"encoding/hex" "encoding/hex"
"encoding/binary"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@@ -54,21 +55,46 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
} }
s.logger.Info("Wrote recompressed savedata back to DB.") s.logger.Info("Wrote recompressed savedata back to DB.")
dumpSaveData(s, pkt.RawDataPayload, "") dumpSaveData(s, pkt.RawDataPayload, "")
// Temporary server launcher response stuff
// 0x1F715 Weapon Class _, err = s.server.db.Exec("UPDATE characters SET weapon_type=$1 WHERE id=$2", uint16(decompressedData[128789]), s.charID)
// 0x1FDF6 HR (small_gr_level)
// 0x88 Character Name
_, err = s.server.db.Exec("UPDATE characters SET weapon=$1 WHERE id=$2", uint16(decompressedData[128789]), s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to character weapon in db", zap.Error(err)) s.logger.Fatal("Failed to character weapon type in db", zap.Error(err))
}
isMale := uint8(decompressedData[80]) // 0x50
if isMale == 1 {
_, err = s.server.db.Exec("UPDATE characters SET is_female=true WHERE id=$1", s.charID)
} else {
_, err = s.server.db.Exec("UPDATE characters SET is_female=false WHERE id=$1", s.charID)
} }
gr := uint16(decompressedData[130550])<<8 | uint16(decompressedData[130551])
s.logger.Info("Setting db field", zap.Uint16("gr_override_level", gr))
// We have to use `gr_override_level` (uint16), not `small_gr_level` (uint8) to store this.
_, err = s.server.db.Exec("UPDATE characters SET gr_override_mode=true, gr_override_level=$1 WHERE id=$2", gr, s.charID)
if err != nil { if err != nil {
s.logger.Fatal("Failed to update character gr_override_level in db", zap.Error(err)) s.logger.Fatal("Failed to character gender in db", zap.Error(err))
} }
weaponId := binary.LittleEndian.Uint16(decompressedData[128522:128524]) // 0x1F60A
_, err = s.server.db.Exec("UPDATE characters SET weapon_id=$1 WHERE id=$2", weaponId, s.charID)
if err != nil {
s.logger.Fatal("Failed to update character weapon id in db", zap.Error(err))
}
hrp := binary.LittleEndian.Uint16(decompressedData[130550:130552]) // 0x1FDF6
_, err = s.server.db.Exec("UPDATE characters SET hrp=$1 WHERE id=$2", hrp, s.charID)
if err != nil {
s.logger.Fatal("Failed to update character hrp in db", zap.Error(err))
}
grp := binary.LittleEndian.Uint32(decompressedData[130556:130560]) // 0x1FDFC
var gr uint16
if grp > 0 {
gr = grpToGR(grp)
} else {
gr = 0
}
_, err = s.server.db.Exec("UPDATE characters SET gr=$1 WHERE id=$2", gr, s.charID)
if err != nil {
s.logger.Fatal("Failed to update character gr in db", zap.Error(err))
}
characterName := s.clientContext.StrConv.MustDecode(bfutil.UpToNull(decompressedData[88:100])) characterName := s.clientContext.StrConv.MustDecode(bfutil.UpToNull(decompressedData[88:100]))
_, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterName, s.charID) _, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterName, s.charID)
if err != nil { if err != nil {
@@ -77,6 +103,53 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func grpToGR(n uint32) uint16 {
var gr uint16
gr = 1
switch grp := int(n); {
case grp < 208750: // Up to 50
i := 0
for {
grp -= 500
if grp <= 500 {
if grp < 0 {
i--
}
break
} else {
i++
for j := 0; j < i; j++ {
grp -= 150
}
}
}
gr = uint16(i + 2); break
case grp < 593400: // 51-99
grp -= 208750; i := 51; for { if grp < 7850 {break}; i++; grp -= 7850 }; gr = uint16(i); break
case grp < 993400: // 100-149
grp -= 593400; i := 100; for { if grp < 8000 {break}; i++; grp -= 8000 }; gr = uint16(i); break
case grp < 1400900: // 150-199
grp -= 993400; i := 150; for { if grp < 8150 {break}; i++; grp -= 8150 }; gr = uint16(i); break
case grp < 2315900: // 200-299
grp -= 1400900; i := 200; for { if grp < 9150 {break}; i++; grp -= 9150 }; gr = uint16(i); break
case grp < 3340900: // 300-399
grp -= 2315900; i := 300; for { if grp < 10250 {break}; i++; grp -= 10250 }; gr = uint16(i); break
case grp < 4505900: // 400-499
grp -= 3340900; i := 400; for { if grp < 11650 {break}; i++; grp -= 11650 }; gr = uint16(i); break
case grp < 5850900: // 500-599
grp -= 4505900; i := 500; for { if grp < 13450 {break}; i++; grp -= 13450 }; gr = uint16(i); break
case grp < 7415900: // 600-699
grp -= 5850900; i := 600; for { if grp < 15650 {break}; i++; grp -= 15650 }; gr = uint16(i); break
case grp < 9230900: // 700-799
grp -= 7415900; i := 700; for { if grp < 18150 {break}; i++; grp -= 18150 }; gr = uint16(i); break
case grp < 11345900: // 800-899
grp -= 9230900; i := 800; for { if grp < 21150 {break}; i++; grp -= 21150 }; gr = uint16(i); break
default: // 900+
grp -= 11345900; i := 900; for { if grp < 23950 {break}; i++; grp -= 23950 }; gr = uint16(i); break
}
return gr
}
func dumpSaveData(s *Session, data []byte, suffix string) { func dumpSaveData(s *Session, data []byte, suffix string) {
if !s.server.erupeConfig.DevModeOptions.SaveDumps.Enabled { if !s.server.erupeConfig.DevModeOptions.SaveDumps.Enabled {
return return

View File

@@ -196,7 +196,10 @@ func handleMsgMhfAcquireUdItem(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
func handleMsgMhfGetUdRanking(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetUdRanking(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdRanking)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
func handleMsgMhfGetUdMyRanking(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdMyRanking(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdMyRanking) pkt := p.(*mhfpacket.MsgMhfGetUdMyRanking)

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,10 @@ type GuildMember struct {
LastLogin uint32 `db:"last_login"` LastLogin uint32 `db:"last_login"`
AvoidLeadership bool `db:"avoid_leadership"` AvoidLeadership bool `db:"avoid_leadership"`
IsLeader bool `db:"is_leader"` IsLeader bool `db:"is_leader"`
Exp uint16 `db:"exp"` HRP uint16 `db:"hrp"`
GR uint16 `db:"gr"`
WeaponID uint16 `db:"weapon_id"`
WeaponType uint16 `db:"weapon_type"`
} }
func (gm *GuildMember) IsSubLeader() bool { func (gm *GuildMember) IsSubLeader() bool {
@@ -53,7 +56,10 @@ SELECT g.id as guild_id,
coalesce(gc.order_index, 0) as order_index, coalesce(gc.order_index, 0) as order_index,
c.last_login, c.last_login,
coalesce(gc.avoid_leadership, false) as avoid_leadership, coalesce(gc.avoid_leadership, false) as avoid_leadership,
c.exp, c.hrp,
c.gr,
c.weapon_id,
c.weapon_type,
character.is_applicant, character.is_applicant,
CASE WHEN g.leader_id = c.id THEN 1 ELSE 0 END as is_leader CASE WHEN g.leader_id = c.id THEN 1 ELSE 0 END as is_leader
FROM ( FROM (

View File

@@ -93,6 +93,23 @@ func (m *Mail) MarkDeleted(s *Session) error {
return nil return nil
} }
func (m *Mail) MarkAcquired(s *Session) error {
_, err := s.server.db.Exec(`
UPDATE mail SET attached_item_received = true WHERE id = $1
`, m.ID)
if err != nil {
s.logger.Error(
"failed to mark mail item as claimed",
zap.Error(err),
zap.Int("mailID", m.ID),
)
return err
}
return nil
}
func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) { func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
rows, err := s.server.db.Queryx(` rows, err := s.server.db.Queryx(`
SELECT SELECT
@@ -101,6 +118,7 @@ func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
m.recipient_id, m.recipient_id,
m.subject, m.subject,
m.read, m.read,
m.attached_item_received,
m.attached_item, m.attached_item,
m.attached_item_amount, m.attached_item_amount,
m.created_at, m.created_at,
@@ -147,6 +165,7 @@ func GetMailByID(s *Session, ID int) (*Mail, error) {
m.subject, m.subject,
m.read, m.read,
m.body, m.body,
m.attached_item_received,
m.attached_item, m.attached_item,
m.attached_item_amount, m.attached_item_amount,
m.created_at, m.created_at,
@@ -235,9 +254,11 @@ func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {
_ = mail.MarkRead(s) _ = mail.MarkRead(s)
bf := byteframe.NewByteFrame()
bodyBytes, _ := stringsupport.ConvertUTF8ToShiftJIS(mail.Body) bodyBytes, _ := stringsupport.ConvertUTF8ToShiftJIS(mail.Body)
bf.WriteNullTerminatedBytes(bodyBytes)
doAckBufSucceed(s, pkt.AckHandle, bodyBytes) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
@@ -295,10 +316,10 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
msg.WriteUint8(flags) msg.WriteUint8(flags)
msg.WriteBool(itemAttached) msg.WriteBool(itemAttached)
msg.WriteUint8(uint8(len(subjectBytes))) msg.WriteUint8(uint8(len(subjectBytes)+1))
msg.WriteUint8(uint8(len(senderNameBytes))) msg.WriteUint8(uint8(len(senderNameBytes)+1))
msg.WriteBytes(subjectBytes) msg.WriteNullTerminatedBytes(subjectBytes)
msg.WriteBytes(senderNameBytes) msg.WriteNullTerminatedBytes(senderNameBytes)
if itemAttached { if itemAttached {
msg.WriteInt16(m.AttachedItemAmount) msg.WriteInt16(m.AttachedItemAmount)
@@ -320,9 +341,14 @@ func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {
} }
switch mhfpacket.OperateMailOperation(pkt.Operation) { switch mhfpacket.OperateMailOperation(pkt.Operation) {
case mhfpacket.OperateMailOperationDelete: case mhfpacket.OPERATE_MAIL_DELETE:
err = mail.MarkDeleted(s) err = mail.MarkDeleted(s)
if err != nil {
doAckSimpleFail(s, pkt.AckHandle, nil)
panic(err)
}
case mhfpacket.OPERATE_MAIL_ACQUIRE_ITEM:
err = mail.MarkAcquired(s)
if err != nil { if err != nil {
doAckSimpleFail(s, pkt.AckHandle, nil) doAckSimpleFail(s, pkt.AckHandle, nil)
panic(err) panic(err)
@@ -332,4 +358,34 @@ func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleSucceed(s, pkt.AckHandle, nil) doAckSimpleSucceed(s, pkt.AckHandle, nil)
} }
func handleMsgMhfSendMail(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfSendMail(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSendMail)
query := `
INSERT INTO mail (sender_id, recipient_id, subject, body, attached_item, attached_item_amount, is_guild_invite)
VALUES ($1, $2, $3, $4, $5, $6, $7)
`
if pkt.RecipientID == 0 { // Guild mail
g, err := GetGuildInfoByCharacterId(s, s.charID)
if err != nil {
s.logger.Fatal("Failed to get guild info for mail")
}
gm, err := GetGuildMembers(s, g.ID, false)
if err != nil {
s.logger.Fatal("Failed to get guild members for mail")
}
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)
if err != nil {
s.logger.Fatal("Failed to send mail")
}
}
} else {
_, err := s.server.db.Exec(query, s.charID, pkt.RecipientID, pkt.Subject, pkt.Body, pkt.ItemID, pkt.Quantity, false)
if err != nil {
s.logger.Fatal("Failed to send mail")
}
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,13 +12,35 @@ func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) {
} }
func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) {
//pkt := p.(*mhfpacket.MsgSysDeleteSemaphore) pkt := p.(*mhfpacket.MsgSysDeleteSemaphore)
sem := pkt.AckHandle
s.semaphore.Lock() if s.server.semaphore != nil {
s.server.semaphoreLock.Lock()
for id := range s.server.semaphore { for id := range s.server.semaphore {
delete(s.server.semaphore[id].reservedClientSlots, s.charID) switch sem {
case 917533:
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k3" {
delete(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots, s.charID)
delete(s.server.semaphore["hs_l0u3B51J9k3"].clients, s)
}
case 851997:
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k4" {
delete(s.server.semaphore["hs_l0u3B51J9k4"].reservedClientSlots, s.charID)
}
case 786461:
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k5" {
delete(s.server.semaphore["hs_l0u3B51J9k5"].reservedClientSlots, s.charID)
}
default:
if len(s.server.semaphore[id].reservedClientSlots) != 0 {
if s.server.semaphore[id].id_semaphore != "hs_l0u3B51J9k3" && s.server.semaphore[id].id_semaphore != "hs_l0u3B51J9k4" && s.server.semaphore[id].id_semaphore != "hs_l0u3B51J9k5" {
delete(s.server.semaphore[id].reservedClientSlots, s.charID)
}
}
}
}
s.server.semaphoreLock.Unlock()
} }
s.semaphore.Unlock()
} }
func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
@@ -49,11 +71,33 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
s.logger.Info("IS ALREADY EXIST !") s.logger.Info("IS ALREADY EXIST !")
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x1D}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x1D})
} else if uint16(len(newSemaphore.reservedClientSlots)) < newSemaphore.maxPlayers { } else if uint16(len(newSemaphore.reservedClientSlots)) < newSemaphore.maxPlayers {
newSemaphore.reservedClientSlots[s.charID] = nil switch SemaphoreID {
s.Lock() case "hs_l0u3B51J9k3":
s.semaphore = newSemaphore newSemaphore.reservedClientSlots[s.charID] = nil
s.Unlock() newSemaphore.clients[s] = s.charID
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x1D}) s.Lock()
s.semaphore = newSemaphore
s.Unlock()
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0E, 0x00, 0x1D})
case "hs_l0u3B51J9k4":
newSemaphore.reservedClientSlots[s.charID] = nil
s.Lock()
s.semaphore = newSemaphore
s.Unlock()
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0D, 0x00, 0x1D})
case "hs_l0u3B51J9k5":
newSemaphore.reservedClientSlots[s.charID] = nil
s.Lock()
s.semaphore = newSemaphore
s.Unlock()
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0C, 0x00, 0x1D})
default:
newSemaphore.reservedClientSlots[s.charID] = nil
s.Lock()
s.semaphore = newSemaphore
s.Unlock()
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x25})
}
} else { } else {
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} }
@@ -65,15 +109,26 @@ func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
func handleMsgSysReleaseSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysReleaseSemaphore(s *Session, p mhfpacket.MHFPacket) {
//pkt := p.(*mhfpacket.MsgSysReleaseSemaphore) //pkt := p.(*mhfpacket.MsgSysReleaseSemaphore)
for _, session := range s.server.sessions { if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists {
session.semaphore.Lock() reset := len(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots)
for id := range session.server.semaphore { if reset == 0 {
delete(s.server.semaphore[id].reservedClientSlots, s.charID) s.server.db.Exec("CALL ravireset($1)", 0)
} }
session.semaphore.Unlock()
} }
//data, _ := hex.DecodeString("000180e703000d443b37ff006d00131809000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010627426400a936a93600000100cf330600cc31cc31d431000025000000000000000000010218330600bd3cbd3cbd3c01032c280600ee3dee3da9360104f3300600d231a936a93601054a310600e23ae23ae23a00000d0000000000004d814c0000000003008501d723b7334001e7038b3fd437d516113505000000e7030001000002000203000000000000fafafafafafafafafafafafafafa000000000000ecb2000060da0000000000000000000000000000000000000000000000000000000000000000000000000000181818187e2d00003b31702d662d402e000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000") }
//doAckBufSucceed(s, pkt.AckHandle, data)
func removeSessionFromSemaphore(s *Session) {
s.server.semaphoreLock.Lock()
for id := range s.server.semaphore {
delete(s.server.semaphore[id].reservedClientSlots, s.charID)
if id == "hs_l0u3B51J9k3" {
delete(s.server.semaphore[id].clients, s)
} else {
continue
}
}
s.server.semaphoreLock.Unlock()
} }
func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) {

View File

@@ -429,8 +429,8 @@ func init() {
handlerTable[network.MSG_SYS_reserve19F] = handleMsgSysReserve19F handlerTable[network.MSG_SYS_reserve19F] = handleMsgSysReserve19F
handlerTable[network.MSG_MHF_UPDATE_FORCE_GUILD_RANK] = handleMsgMhfUpdateForceGuildRank handlerTable[network.MSG_MHF_UPDATE_FORCE_GUILD_RANK] = handleMsgMhfUpdateForceGuildRank
handlerTable[network.MSG_MHF_RESET_TITLE] = handleMsgMhfResetTitle handlerTable[network.MSG_MHF_RESET_TITLE] = handleMsgMhfResetTitle
handlerTable[network.MSG_SYS_reserve202] = handleMsgSysReserve202 handlerTable[network.MSG_MHF_ENUMERATE_GUILD_MESSAGE_BOARD] = handleMsgMhfEnumerateGuildMessageBoard
handlerTable[network.MSG_SYS_reserve203] = handleMsgSysReserve203 handlerTable[network.MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD] = handleMsgMhfUpdateGuildMessageBoard
handlerTable[network.MSG_SYS_reserve204] = handleMsgSysReserve204 handlerTable[network.MSG_SYS_reserve204] = handleMsgSysReserve204
handlerTable[network.MSG_SYS_reserve205] = handleMsgSysReserve205 handlerTable[network.MSG_SYS_reserve205] = handleMsgSysReserve205
handlerTable[network.MSG_SYS_reserve206] = handleMsgSysReserve206 handlerTable[network.MSG_SYS_reserve206] = handleMsgSysReserve206

View File

@@ -48,7 +48,12 @@ func handleMsgMhfGetUdTacticsFirstQuestBonus(s *Session, p mhfpacket.MHFPacket)
func handleMsgMhfGetUdTacticsRemainingPoint(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetUdTacticsRemainingPoint(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetUdTacticsRanking(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfGetUdTacticsRanking(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetUdTacticsRanking)
// Temporary canned response
data, _ := hex.DecodeString("00000515000005150000CEB4000003CE000003CE0000CEB44D49444E494748542D414E47454C0000000000000000000000")
doAckBufSucceed(s, pkt.AckHandle, data)
}
func handleMsgMhfSetUdTacticsFollower(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfSetUdTacticsFollower(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -1,6 +1,9 @@
package channelserver package channelserver
import ( import (
"github.com/Andoryuuta/byteframe"
"github.com/Solenataris/Erupe/network/mhfpacket"
"sync" "sync"
) )
@@ -11,6 +14,10 @@ type Semaphore struct {
// Stage ID string // Stage ID string
id_semaphore string id_semaphore string
// Map of session -> charID.
// These are clients that are CURRENTLY in the stage
clients map[*Session]uint32
// Map of charID -> interface{}, only the key is used, value is always nil. // Map of charID -> interface{}, only the key is used, value is always nil.
reservedClientSlots map[uint32]interface{} reservedClientSlots map[uint32]interface{}
@@ -22,8 +29,46 @@ type Semaphore struct {
func NewSemaphore(ID string, MaxPlayers uint16) *Semaphore { func NewSemaphore(ID string, MaxPlayers uint16) *Semaphore {
s := &Semaphore{ s := &Semaphore{
id_semaphore: ID, id_semaphore: ID,
clients: make(map[*Session]uint32),
reservedClientSlots: make(map[uint32]interface{}), reservedClientSlots: make(map[uint32]interface{}),
maxPlayers: MaxPlayers, maxPlayers: MaxPlayers,
} }
return s return s
} }
func (s *Semaphore) BroadcastRavi(pkt mhfpacket.MHFPacket) {
// Broadcast the data.
for session := range s.clients {
// Make the header
bf := byteframe.NewByteFrame()
bf.WriteUint16(uint16(pkt.Opcode()))
// Build the packet onto the byteframe.
pkt.Build(bf, session.clientContext)
// Enqueue in a non-blocking way that drops the packet if the connections send buffer channel is full.
session.QueueSendNonBlocking(bf.Data())
}
}
// BroadcastMHF queues a MHFPacket to be sent to all sessions in the stage.
func (s *Semaphore) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
// Broadcast the data.
for session := range s.clients {
if session == ignoredSession {
continue
}
// Make the header
bf := byteframe.NewByteFrame()
bf.WriteUint16(uint16(pkt.Opcode()))
// Build the packet onto the byteframe.
pkt.Build(bf, session.clientContext)
// Enqueue in a non-blocking way that drops the packet if the connections send buffer channel is full.
session.QueueSendNonBlocking(bf.Data())
}
}

View File

@@ -32,6 +32,8 @@ type Session struct {
reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet. reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet.
charID uint32 charID uint32
logKey []byte logKey []byte
sessionStart int64
rights uint32
semaphore *Semaphore // Required for the stateful MsgSysUnreserveStage packet. semaphore *Semaphore // Required for the stateful MsgSysUnreserveStage packet.
@@ -62,6 +64,7 @@ func NewSession(server *Server, conn net.Conn) *Session {
Encoding: japanese.ShiftJIS, Encoding: japanese.ShiftJIS,
}, },
}, },
sessionStart: Time_Current_Adjusted().Unix(),
stageMoveStack: stringstack.New(), stageMoveStack: stringstack.New(),
} }
return s return s
@@ -177,6 +180,7 @@ func (s *Session) handlePacketGroup(pktGroup []byte) {
opcode != network.MSG_SYS_PING && opcode != network.MSG_SYS_PING &&
opcode != network.MSG_SYS_NOP && opcode != network.MSG_SYS_NOP &&
opcode != network.MSG_SYS_TIME && opcode != network.MSG_SYS_TIME &&
opcode != network.MSG_SYS_POSITION_OBJECT &&
opcode != network.MSG_SYS_EXTEND_THRESHOLD { opcode != network.MSG_SYS_EXTEND_THRESHOLD {
fmt.Printf("[%s] send to Server\n", s.Name) fmt.Printf("[%s] send to Server\n", s.Name)
fmt.Printf("Opcode: %s\n", opcode) fmt.Printf("Opcode: %s\n", opcode)

View File

@@ -26,9 +26,9 @@ func (s *Server) newUserChara(username string) error {
_, err = s.db.Exec(` _, err = s.db.Exec(`
INSERT INTO characters ( INSERT INTO characters (
user_id, is_female, is_new_character, small_gr_level, gr_override_mode, name, unk_desc_string, user_id, is_female, is_new_character, name, unk_desc_string,
gr_override_level, gr_override_unk0, gr_override_unk1, exp, weapon, last_login) hrp, gr, weapon_type, last_login)
VALUES($1, False, True, 0, True, '', '', 0, 0, 0, 0, 0, $2)`, VALUES($1, False, True, '', '', 1, 0, 0, $2)`,
id, id,
uint32(time.Now().Unix()), uint32(time.Now().Unix()),
) )
@@ -60,9 +60,9 @@ func (s *Server) registerDBAccount(username string, password string) error {
// Create a base new character. // Create a base new character.
_, err = s.db.Exec(` _, err = s.db.Exec(`
INSERT INTO characters ( INSERT INTO characters (
user_id, is_female, is_new_character, small_gr_level, gr_override_mode, name, unk_desc_string, user_id, is_female, is_new_character, name, unk_desc_string,
gr_override_level, gr_override_unk0, gr_override_unk1, exp, weapon, last_login) hrp, gr, weapon_type, last_login)
VALUES($1, False, True, 0, True, '', '', 0, 0, 0, 0, 0, $2)`, VALUES($1, False, True, '', '', 1, 0, 0, $2)`,
id, id,
uint32(time.Now().Unix()), uint32(time.Now().Unix()),
) )
@@ -77,21 +77,17 @@ type character struct {
ID uint32 `db:"id"` ID uint32 `db:"id"`
IsFemale bool `db:"is_female"` IsFemale bool `db:"is_female"`
IsNewCharacter bool `db:"is_new_character"` IsNewCharacter bool `db:"is_new_character"`
SmallGRLevel uint8 `db:"small_gr_level"`
GROverrideMode bool `db:"gr_override_mode"`
Name string `db:"name"` Name string `db:"name"`
UnkDescString string `db:"unk_desc_string"` UnkDescString string `db:"unk_desc_string"`
GROverrideLevel uint16 `db:"gr_override_level"` HRP uint16 `db:"hrp"`
GROverrideUnk0 uint8 `db:"gr_override_unk0"` GR uint16 `db:"gr"`
GROverrideUnk1 uint8 `db:"gr_override_unk1"` WeaponType uint16 `db:"weapon_type"`
Exp uint16 `db:"exp"`
Weapon uint16 `db:"weapon"`
LastLogin uint32 `db:"last_login"` LastLogin uint32 `db:"last_login"`
} }
func (s *Server) getCharactersForUser(uid int) ([]character, error) { func (s *Server) getCharactersForUser(uid int) ([]character, error) {
characters := []character{} characters := []character{}
err := s.db.Select(&characters, "SELECT id, is_female, is_new_character, small_gr_level, gr_override_mode, name, unk_desc_string, gr_override_level, gr_override_unk0, gr_override_unk1, exp, weapon, last_login FROM characters WHERE user_id = $1", uid) err := s.db.Select(&characters, "SELECT id, is_female, is_new_character, name, unk_desc_string, hrp, gr, weapon_type, last_login FROM characters WHERE user_id = $1", uid)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -2,6 +2,8 @@ package signserver
import ( import (
"fmt" "fmt"
"math/rand"
"time"
"github.com/Andoryuuta/byteframe" "github.com/Andoryuuta/byteframe"
"go.uber.org/zap" "go.uber.org/zap"
@@ -32,6 +34,15 @@ func makeSignInFailureResp(respID RespID) []byte {
return bf.Data() return bf.Data()
} }
func randSeq(n int) string {
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
func (s *Session) makeSignInResp(uid int) []byte { func (s *Session) makeSignInResp(uid int) []byte {
// Get the characters from the DB. // Get the characters from the DB.
chars, err := s.server.getCharactersForUser(uid) chars, err := s.server.getCharactersForUser(uid)
@@ -39,14 +50,18 @@ func (s *Session) makeSignInResp(uid int) []byte {
s.logger.Warn("Error getting characters from DB", zap.Error(err)) s.logger.Warn("Error getting characters from DB", zap.Error(err))
} }
rand.Seed(time.Now().UnixNano())
token := randSeq(16)
// TODO: register token to db, users table
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint8(1) // resp_code bf.WriteUint8(1) // resp_code
bf.WriteUint8(0) // file/patch server count bf.WriteUint8(0) // file/patch server count
bf.WriteUint8(4) // entrance server count bf.WriteUint8(4) // entrance server count
bf.WriteUint8(uint8(len(chars))) // character count bf.WriteUint8(uint8(len(chars))) // character count
bf.WriteUint32(0xFFFFFFFF) // login_token_number bf.WriteUint32(0xFFFFFFFF) // login_token_number
bf.WriteBytes(paddedString("logintokenstrng", 16)) // login_token (16 byte padded string) bf.WriteBytes(paddedString(token, 16)) // login_token (16 byte padded string)
bf.WriteUint32(1576761190) bf.WriteUint32(1576761190)
uint8PascalString(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.HostIP, s.server.erupeConfig.Entrance.Port)) uint8PascalString(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.HostIP, s.server.erupeConfig.Entrance.Port))
uint8PascalString(bf, "") uint8PascalString(bf, "")
@@ -60,24 +75,18 @@ func (s *Session) makeSignInResp(uid int) []byte {
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.MaxLauncherHR { if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.MaxLauncherHR {
bf.WriteUint16(999) bf.WriteUint16(999)
} else { } else {
bf.WriteUint16(char.Exp) bf.WriteUint16(char.HRP)
} }
bf.WriteUint16(char.WeaponType) // Weapon, 0-13.
bf.WriteUint16(char.Weapon) // Weapon, 0-13.
bf.WriteUint32(char.LastLogin) // Last login date, unix timestamp in seconds. bf.WriteUint32(char.LastLogin) // Last login date, unix timestamp in seconds.
bf.WriteBool(char.IsFemale) // Sex, 0=male, 1=female. bf.WriteBool(char.IsFemale) // Sex, 0=male, 1=female.
bf.WriteBool(char.IsNewCharacter) // Is new character, 1 replaces character name with ?????. bf.WriteBool(char.IsNewCharacter) // Is new character, 1 replaces character name with ?????.
bf.WriteUint8(char.SmallGRLevel) // GR level if grMode == 0 bf.WriteUint8(0) // Old GR
bf.WriteBool(char.GROverrideMode) // GR mode. bf.WriteBool(true) // Use uint16 GR, no reason not to
bf.WriteBytes(paddedString(char.Name, 16)) // Character name bf.WriteBytes(paddedString(char.Name, 16)) // Character name
bf.WriteBytes(paddedString(char.UnkDescString, 32)) // unk str bf.WriteBytes(paddedString(char.UnkDescString, 32)) // unk str
if char.GROverrideMode { bf.WriteUint16(char.GR)
bf.SetLE() bf.WriteUint16(0) // Unk
bf.WriteUint16(char.GROverrideLevel) // GR level override.
bf.SetBE()
bf.WriteUint8(char.GROverrideUnk0) // unk
bf.WriteUint8(char.GROverrideUnk1) // unk
}
} }
bf.WriteUint8(0) // friends_list_count bf.WriteUint8(0) // friends_list_count

View File

@@ -71,12 +71,21 @@
<p class="lbl">Important Updates</p> <p class="lbl">Important Updates</p>
</div> </div>
<ul class="article"> <ul class="article">
<li>
<div class="date">2022-05-03</div>
<div class="body">
<a
href="javascript:toggleModal('openLink',&quot;https://discord.com/channels/368424389416583169/929509970624532511/969305400795078656&quot;);"
onclick="soundOk()">Eng 2.0 &amp; Ravi Patch Released!
</a>
</div>
</li>
<li> <li>
<div class="date">2022-04-24</div> <div class="date">2022-04-24</div>
<div class="body"> <div class="body">
<a <a
href="javascript:toggleModal('openLink',&quot;https://discord.com/channels/368424389416583169/929509970624532511/964339905364918272&quot;);" href="javascript:toggleModal('openLink',&quot;https://discord.com/channels/368424389416583169/929509970624532511/969286397301248050&quot;);"
onclick="soundOk()">Launcher Patch v1.0 Released! onclick="soundOk()">Launcher Patch V1.0 Released!
</a> </a>
</div> </div>
</li> </li>
@@ -92,7 +101,7 @@
<div class="body"> <div class="body">
<a <a
href="javascript:toggleModal('openLink',&quot;https://discord.gg/CFnzbhQ&quot;);" href="javascript:toggleModal('openLink',&quot;https://discord.gg/CFnzbhQ&quot;);"
onclick="soundOk()">Join the community discord for updates! onclick="soundOk()">Join the community Discord for updates!
</a> </a>
</div> </div>
</li> </li>

View File

@@ -108,7 +108,7 @@ function createCharItem(name, uid, weapon, hr, gr, date, sex) {
icon = 'img/icons/ss.png'; icon = 'img/icons/ss.png';
break; break;
case '双剣': case '双剣':
weapon = 'Dual Blades'; weapon = 'Dual Swords';
icon = 'img/icons/db.png'; icon = 'img/icons/db.png';
break; break;
case '大剣': case '大剣':
@@ -116,7 +116,7 @@ function createCharItem(name, uid, weapon, hr, gr, date, sex) {
icon = 'img/icons/gs.png'; icon = 'img/icons/gs.png';
break; break;
case '太刀': case '太刀':
weapon = 'Long Sword'; weapon = 'Longsword';
icon = 'img/icons/ls.png'; icon = 'img/icons/ls.png';
break; break;
case 'ハンマー': case 'ハンマー':
@@ -139,7 +139,7 @@ function createCharItem(name, uid, weapon, hr, gr, date, sex) {
weapon = 'Tonfa'; weapon = 'Tonfa';
icon = 'img/icons/tf.png'; icon = 'img/icons/tf.png';
break; break;
case 'スラッシュアックスF': case 'スラッシュアックス':
weapon = 'Switch Axe F'; weapon = 'Switch Axe F';
icon = 'img/icons/sa.png'; icon = 'img/icons/sa.png';
break; break;
@@ -272,7 +272,7 @@ function doLogin(option) {
addLog('Creating new character...', 'normal'); addLog('Creating new character...', 'normal');
window.external.loginCog(username+'+', password, password); window.external.loginCog(username+'+', password, password);
} else { } else {
window.external.loginCog(username, password, password); window.external.loginCog(username, password, 'test');
} }
} catch (e) { } catch (e) {
addLog('Error on loginCog: '+e, 'error'); addLog('Error on loginCog: '+e, 'error');