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
type MsgMhfAcquireUdItem struct{
type MsgMhfAcquireUdItem struct {
AckHandle uint32
// Valid field size(s), not sure about the types.
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.
@@ -25,9 +36,12 @@ func (m *MsgMhfAcquireUdItem) Opcode() network.PacketID {
func (m *MsgMhfAcquireUdItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
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 errors.New("NOT IMPLEMENTED")
}
// Build builds a binary packet from the current data.

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -9,7 +9,10 @@ import (
)
// 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.
func (m *MsgMhfAddGuildWeeklyBonusExceptionalUser) Opcode() network.PacketID {
@@ -18,7 +21,9 @@ func (m *MsgMhfAddGuildWeeklyBonusExceptionalUser) Opcode() network.PacketID {
// Parse parses the packet from binary
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.

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -11,22 +11,25 @@ import (
type EnumerateGuildType uint8
const (
_ = iota
ENUMERATE_GUILD_TYPE_NAME
//Numbers correspond to order in guild search menu
ENUMERATE_GUILD_TYPE_6
ENUMERATE_GUILD_TYPE_LEADER_ID
ENUMERATE_GUILD_TYPE_3
ENUMERATE_GUILD_TYPE_2
ENUMERATE_GUILD_TYPE_7
ENUMERATE_GUILD_TYPE_8
ENUMERATE_GUILD_TYPE_NEW
ENUMERATE_GUILD_TYPE_GUILD_NAME = 0x01
ENUMERATE_GUILD_TYPE_LEADER_NAME = 0x02
ENUMERATE_GUILD_TYPE_LEADER_ID = 0x03
ENUMERATE_GUILD_TYPE_ORDER_MEMBERS = 0x04
ENUMERATE_GUILD_TYPE_ORDER_REGISTRATION = 0x05
ENUMERATE_GUILD_TYPE_ORDER_RANK = 0x06
ENUMERATE_GUILD_TYPE_MOTTO = 0x07
ENUMERATE_GUILD_TYPE_RECRUITING = 0x08
ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME = 0x09
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
type MsgMhfEnumerateGuild struct {
AckHandle uint32
Type uint8
Type EnumerateGuildType
RawDataPayload []byte
}
@@ -38,9 +41,9 @@ func (m *MsgMhfEnumerateGuild) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfEnumerateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Type = bf.ReadUint8()
m.Type = EnumerateGuildType(bf.ReadUint8())
m.RawDataPayload = bf.DataFromCurrent()
bf.Seek(int64(len(bf.Data()) - 2), 0)
return nil
}

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -11,6 +11,8 @@ import (
// MsgMhfEnumerateGuildItem represents the MSG_MHF_ENUMERATE_GUILD_ITEM
type MsgMhfEnumerateGuildItem struct {
AckHandle uint32
GuildId uint32
Unk0 uint16
}
// 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
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
}

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
type MsgMhfEnumerateUnionItem struct{}
type MsgMhfEnumerateUnionItem struct {
AckHandle uint32
Unk0 uint16
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfEnumerateUnionItem) Opcode() network.PacketID {
@@ -18,7 +21,10 @@ func (m *MsgMhfEnumerateUnionItem) Opcode() network.PacketID {
// Parse parses the packet from binary
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.

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -10,10 +10,9 @@ import (
// MsgMhfGetAchievement represents the MSG_MHF_GET_ACHIEVEMENT
type MsgMhfGetAchievement struct{
AckHandle uint32
Unk0 uint16 // id?
AckHandle uint32
Unk0 uint32 // id?
Unk1 uint32 // char?
Unk2 uint32 // pad?
}
// 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
func (m *MsgMhfGetAchievement) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint16()
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint32()
m.Unk1 = bf.ReadUint32()
m.Unk2 = bf.ReadUint32()
return nil
}

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -11,6 +11,7 @@ import (
// MsgMhfGetUdRanking represents the MSG_MHF_GET_UD_RANKING
type MsgMhfGetUdRanking struct{
AckHandle uint32
Unk0 uint8
}
// 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
func (m *MsgMhfGetUdRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
return nil
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8()
return nil
}
// Build builds a binary packet from the current data.

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -9,7 +9,10 @@ import (
)
// 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.
func (m *MsgMhfGetUdTacticsRanking) Opcode() network.PacketID {
@@ -18,7 +21,9 @@ func (m *MsgMhfGetUdTacticsRanking) Opcode() network.PacketID {
// Parse parses the packet from binary
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.

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -11,6 +11,7 @@ import (
// MsgMhfListMail represents the MSG_MHF_LIST_MAIL
type MsgMhfListMail struct {
AckHandle uint32
Unk0 uint32
}
// 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
func (m *MsgMhfListMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint32()
return nil
}

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -11,14 +11,29 @@ import (
type OperateGuildAction uint8
const (
OPERATE_GUILD_ACTION_DISBAND = 0x01
OPERATE_GUILD_ACTION_APPLY = 0x02
OPERATE_GUILD_ACTION_LEAVE = 0x03
OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE = 0x07
OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE = 0x08
OPERATE_GUILD_ACTION_UPDATE_COMMENT = 0x09
OPERATE_GUILD_ACTION_DONATE = 0x0a
OPERATE_GUILD_ACTION_UPDATE_MOTTO = 0x0b
OPERATE_GUILD_DISBAND = 0x01
OPERATE_GUILD_APPLY = 0x02
OPERATE_GUILD_LEAVE = 0x03
OPERATE_GUILD_RESIGN = 0x04
OPERATE_GUILD_SET_APPLICATION_DENY = 0x05
OPERATE_GUILD_SET_APPLICATION_ALLOW = 0x06
OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE = 0x07
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
@@ -40,7 +55,7 @@ func (m *MsgMhfOperateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien
m.GuildID = bf.ReadUint32()
m.Action = OperateGuildAction(bf.ReadUint8())
m.UnkData = bf.DataFromCurrent()
bf.Seek(int64(len(bf.Data()) - 2), 0)
return nil
}

View File

@@ -1,15 +1,29 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"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
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.
func (m *MsgMhfOperateJoint) Opcode() network.PacketID {
@@ -18,7 +32,13 @@ func (m *MsgMhfOperateJoint) Opcode() network.PacketID {
// Parse parses the packet from binary
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.

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -11,15 +11,20 @@ import (
type OperateMailOperation uint8
const (
OperateMailOperationDelete OperateMailOperation = 0x01
OPERATE_MAIL_DELETE = 0x01
OPERATE_MAIL_ACQUIRE_ITEM = 0x05
)
// MsgMhfOprtMail represents the MSG_MHF_OPRT_MAIL
type MsgMhfOprtMail struct {
AckHandle uint32
AckHandle uint32
AccIndex uint8
Index uint8
Operation uint8
Operation OperateMailOperation
Unk0 uint8
Data []byte
Amount uint16
ItemID uint16
}
// 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
func (m *MsgMhfOprtMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.AckHandle = bf.ReadUint32()
m.AccIndex = 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
}

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -19,6 +19,7 @@ type MsgMhfReadMail struct {
// This is the index within the current mail list
Index uint8
Unk0 uint16
}
// 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.AccIndex = bf.ReadUint8()
m.Index = bf.ReadUint8()
m.Unk0 = bf.ReadUint16()
return nil
}

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -9,7 +9,16 @@ import (
)
// 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.
func (m *MsgMhfSendMail) Opcode() network.PacketID {
@@ -18,7 +27,15 @@ func (m *MsgMhfSendMail) Opcode() network.PacketID {
// Parse parses the packet from binary
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.

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -9,7 +9,10 @@ import (
)
// 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.
func (m *MsgMhfSetGuildMissionTarget) Opcode() network.PacketID {
@@ -18,7 +21,9 @@ func (m *MsgMhfSetGuildMissionTarget) Opcode() network.PacketID {
// Parse parses the packet from binary
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.

View File

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

View File

@@ -1,15 +1,28 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
type Item struct{
Unk0 uint32
ItemId uint16
Amount uint16
Unk1 uint32
}
// 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.
func (m *MsgMhfUpdateGuildItem) Opcode() network.PacketID {
@@ -18,7 +31,20 @@ func (m *MsgMhfUpdateGuildItem) Opcode() network.PacketID {
// Parse parses the packet from binary
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.

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

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -9,7 +9,12 @@ import (
)
// 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.
func (m *MsgMhfUpdateUnionItem) Opcode() network.PacketID {
@@ -18,7 +23,19 @@ func (m *MsgMhfUpdateUnionItem) Opcode() network.PacketID {
// Parse parses the packet from binary
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.

View File

@@ -1,27 +1 @@
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")
}
package mhfpacket

View File

@@ -1,36 +1 @@
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")
}
package mhfpacket

View File

@@ -1,7 +1,7 @@
package mhfpacket
import (
"errors"
import (
"errors"
"github.com/Solenataris/Erupe/network/clientctx"
"github.com/Solenataris/Erupe/network"
@@ -9,7 +9,12 @@ import (
)
// 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.
func (m *MsgSysReserve205) Opcode() network.PacketID {
@@ -18,7 +23,11 @@ func (m *MsgSysReserve205) Opcode() network.PacketID {
// Parse parses the packet from binary
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.

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -3,6 +3,7 @@ package channelserver
import (
"bytes"
"encoding/hex"
"encoding/binary"
"io/ioutil"
"math/bits"
"math/rand"
@@ -74,16 +75,7 @@ func doAckSimpleFail(s *Session, ackHandle uint32, data []byte) {
func updateRights(s *Session) {
update := &mhfpacket.MsgSysUpdateRight{
ClientRespAckHandle: 0,
Unk1: 0x0E, //0e with normal sub 4e when having premium it's probably a bitfield?
// 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
Unk1: s.rights,
Rights: []mhfpacket.ClientRight{
{
ID: 1,
@@ -143,10 +135,25 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysLogin)
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.Lock()
s.Name = name
s.charID = pkt.CharID0
s.rights = rights
s.Unlock()
bf := byteframe.NewByteFrame()
bf.WriteUint32(uint32(Time_Current_Adjusted().Unix())) // Unix timestamp
@@ -158,11 +165,11 @@ 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 {
panic(err)
}
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
}
@@ -191,6 +198,46 @@ func logoutPlayer(s *Session) {
}
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) {}
@@ -208,6 +255,8 @@ func handleMsgSysTime(s *Session, p mhfpacket.MHFPacket) {
Timestamp: uint32(Time_Current_Adjusted().Unix()), // JP timezone
}
s.QueueSendMHF(resp)
s.notifyticker()
}
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 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) {
pkt := p.(*mhfpacket.MsgMhfAcquireCafeItem)

View File

@@ -2,8 +2,8 @@ package channelserver
import (
"fmt"
"math"
"strings"
"math"
"github.com/Andoryuuta/byteframe"
"github.com/Solenataris/Erupe/network/binpacket"
@@ -22,6 +22,7 @@ const (
const (
BroadcastTypeTargeted = 0x01
BroadcastTypeStage = 0x03
BroadcastTypeRavi = 0x06
BroadcastTypeWorld = 0x0a
)
@@ -51,15 +52,14 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysCastBinary)
if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x03 && len(pkt.RawDataPayload) == 0x10 {
tmp := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
if tmp.ReadUint16() == 0x0002 && tmp.ReadUint8() == 0x18 {
_ = tmp.ReadBytes(9)
tmp.SetLE()
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))
}
tmp := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
if tmp.ReadUint16() == 0x0002 && tmp.ReadUint8() == 0x18 {
_ = tmp.ReadBytes(9)
tmp.SetLE()
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))
}
}
// Parse out the real casted binary payload
var realPayload []byte
@@ -93,6 +93,11 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
s.server.BroadcastMHF(resp, s)
case BroadcastTypeStage:
s.stage.BroadcastMHF(resp, s)
case BroadcastTypeRavi:
if pkt.MessageType == 1 {
session := s.server.semaphore["hs_l0u3B51J9k3"]
(*session).BroadcastMHF(resp, s)
}
case BroadcastTypeTargeted:
for _, targetID := range (*msgBinTargeted).TargetCharIDs {
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)
}
// 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 ") {
var x, y int16
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())
}
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) {}

View File

@@ -2,6 +2,7 @@ package channelserver
import (
"encoding/hex"
"encoding/binary"
"fmt"
"io/ioutil"
"os"
@@ -54,21 +55,46 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
}
s.logger.Info("Wrote recompressed savedata back to DB.")
dumpSaveData(s, pkt.RawDataPayload, "")
// Temporary server launcher response stuff
// 0x1F715 Weapon Class
// 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)
_, err = s.server.db.Exec("UPDATE characters SET weapon_type=$1 WHERE id=$2", uint16(decompressedData[128789]), s.charID)
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 {
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]))
_, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterName, s.charID)
if err != nil {
@@ -77,6 +103,53 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
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) {
if !s.server.erupeConfig.DevModeOptions.SaveDumps.Enabled {
return

View File

@@ -196,7 +196,10 @@ func handleMsgMhfAcquireUdItem(s *Session, p mhfpacket.MHFPacket) {
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) {
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"`
AvoidLeadership bool `db:"avoid_leadership"`
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 {
@@ -53,7 +56,10 @@ SELECT g.id as guild_id,
coalesce(gc.order_index, 0) as order_index,
c.last_login,
coalesce(gc.avoid_leadership, false) as avoid_leadership,
c.exp,
c.hrp,
c.gr,
c.weapon_id,
c.weapon_type,
character.is_applicant,
CASE WHEN g.leader_id = c.id THEN 1 ELSE 0 END as is_leader
FROM (

View File

@@ -61,7 +61,7 @@ func (m *Mail) Send(s *Session, transaction *sql.Tx) error {
func (m *Mail) MarkRead(s *Session) error {
_, err := s.server.db.Exec(`
UPDATE mail SET read = true WHERE id = $1
UPDATE mail SET read = true WHERE id = $1
`, m.ID)
if err != nil {
@@ -78,7 +78,7 @@ func (m *Mail) MarkRead(s *Session) error {
func (m *Mail) MarkDeleted(s *Session) error {
_, err := s.server.db.Exec(`
UPDATE mail SET deleted = true WHERE id = $1
UPDATE mail SET deleted = true WHERE id = $1
`, m.ID)
if err != nil {
@@ -93,22 +93,40 @@ func (m *Mail) MarkDeleted(s *Session) error {
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) {
rows, err := s.server.db.Queryx(`
SELECT
SELECT
m.id,
m.sender_id,
m.recipient_id,
m.subject,
m.read,
m.attached_item_received,
m.attached_item,
m.attached_item_amount,
m.created_at,
m.is_guild_invite,
m.deleted,
c.name as sender_name
FROM mail m
JOIN characters c ON c.id = m.sender_id
FROM mail m
JOIN characters c ON c.id = m.sender_id
WHERE recipient_id = $1 AND deleted = false
ORDER BY m.created_at DESC, id DESC
LIMIT 32
@@ -140,21 +158,22 @@ func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
func GetMailByID(s *Session, ID int) (*Mail, error) {
row := s.server.db.QueryRowx(`
SELECT
SELECT
m.id,
m.sender_id,
m.recipient_id,
m.subject,
m.read,
m.body,
m.attached_item_received,
m.attached_item,
m.attached_item_amount,
m.created_at,
m.is_guild_invite,
m.deleted,
c.name as sender_name
FROM mail m
JOIN characters c ON c.id = m.sender_id
FROM mail m
JOIN characters c ON c.id = m.sender_id
WHERE m.id = $1
LIMIT 1
`, ID)
@@ -235,9 +254,11 @@ func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {
_ = mail.MarkRead(s)
bf := byteframe.NewByteFrame()
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) {
@@ -295,10 +316,10 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
msg.WriteUint8(flags)
msg.WriteBool(itemAttached)
msg.WriteUint8(uint8(len(subjectBytes)))
msg.WriteUint8(uint8(len(senderNameBytes)))
msg.WriteBytes(subjectBytes)
msg.WriteBytes(senderNameBytes)
msg.WriteUint8(uint8(len(subjectBytes)+1))
msg.WriteUint8(uint8(len(senderNameBytes)+1))
msg.WriteNullTerminatedBytes(subjectBytes)
msg.WriteNullTerminatedBytes(senderNameBytes)
if itemAttached {
msg.WriteInt16(m.AttachedItemAmount)
@@ -320,9 +341,14 @@ func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {
}
switch mhfpacket.OperateMailOperation(pkt.Operation) {
case mhfpacket.OperateMailOperationDelete:
case mhfpacket.OPERATE_MAIL_DELETE:
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 {
doAckSimpleFail(s, pkt.AckHandle, nil)
panic(err)
@@ -332,4 +358,34 @@ func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {
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) {
//pkt := p.(*mhfpacket.MsgSysDeleteSemaphore)
s.semaphore.Lock()
pkt := p.(*mhfpacket.MsgSysDeleteSemaphore)
sem := pkt.AckHandle
if s.server.semaphore != nil {
s.server.semaphoreLock.Lock()
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) {
@@ -49,11 +71,33 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
s.logger.Info("IS ALREADY EXIST !")
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x1D})
} else if uint16(len(newSemaphore.reservedClientSlots)) < newSemaphore.maxPlayers {
newSemaphore.reservedClientSlots[s.charID] = nil
s.Lock()
s.semaphore = newSemaphore
s.Unlock()
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x1D})
switch SemaphoreID {
case "hs_l0u3B51J9k3":
newSemaphore.reservedClientSlots[s.charID] = nil
newSemaphore.clients[s] = s.charID
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 {
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) {
//pkt := p.(*mhfpacket.MsgSysReleaseSemaphore)
for _, session := range s.server.sessions {
session.semaphore.Lock()
for id := range session.server.semaphore {
delete(s.server.semaphore[id].reservedClientSlots, s.charID)
if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists {
reset := len(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots)
if reset == 0 {
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) {

View File

@@ -429,8 +429,8 @@ func init() {
handlerTable[network.MSG_SYS_reserve19F] = handleMsgSysReserve19F
handlerTable[network.MSG_MHF_UPDATE_FORCE_GUILD_RANK] = handleMsgMhfUpdateForceGuildRank
handlerTable[network.MSG_MHF_RESET_TITLE] = handleMsgMhfResetTitle
handlerTable[network.MSG_SYS_reserve202] = handleMsgSysReserve202
handlerTable[network.MSG_SYS_reserve203] = handleMsgSysReserve203
handlerTable[network.MSG_MHF_ENUMERATE_GUILD_MESSAGE_BOARD] = handleMsgMhfEnumerateGuildMessageBoard
handlerTable[network.MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD] = handleMsgMhfUpdateGuildMessageBoard
handlerTable[network.MSG_SYS_reserve204] = handleMsgSysReserve204
handlerTable[network.MSG_SYS_reserve205] = handleMsgSysReserve205
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 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) {}

View File

@@ -1,6 +1,9 @@
package channelserver
import (
"github.com/Andoryuuta/byteframe"
"github.com/Solenataris/Erupe/network/mhfpacket"
"sync"
)
@@ -11,6 +14,10 @@ type Semaphore struct {
// Stage ID 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.
reservedClientSlots map[uint32]interface{}
@@ -22,8 +29,46 @@ type Semaphore struct {
func NewSemaphore(ID string, MaxPlayers uint16) *Semaphore {
s := &Semaphore{
id_semaphore: ID,
clients: make(map[*Session]uint32),
reservedClientSlots: make(map[uint32]interface{}),
maxPlayers: MaxPlayers,
}
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.
charID uint32
logKey []byte
sessionStart int64
rights uint32
semaphore *Semaphore // Required for the stateful MsgSysUnreserveStage packet.
@@ -62,6 +64,7 @@ func NewSession(server *Server, conn net.Conn) *Session {
Encoding: japanese.ShiftJIS,
},
},
sessionStart: Time_Current_Adjusted().Unix(),
stageMoveStack: stringstack.New(),
}
return s
@@ -177,6 +180,7 @@ func (s *Session) handlePacketGroup(pktGroup []byte) {
opcode != network.MSG_SYS_PING &&
opcode != network.MSG_SYS_NOP &&
opcode != network.MSG_SYS_TIME &&
opcode != network.MSG_SYS_POSITION_OBJECT &&
opcode != network.MSG_SYS_EXTEND_THRESHOLD {
fmt.Printf("[%s] send to Server\n", s.Name)
fmt.Printf("Opcode: %s\n", opcode)

View File

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

View File

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

View File

@@ -71,12 +71,21 @@
<p class="lbl">Important Updates</p>
</div>
<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>
<div class="date">2022-04-24</div>
<div class="body">
<a
href="javascript:toggleModal('openLink',&quot;https://discord.com/channels/368424389416583169/929509970624532511/964339905364918272&quot;);"
onclick="soundOk()">Launcher Patch v1.0 Released!
href="javascript:toggleModal('openLink',&quot;https://discord.com/channels/368424389416583169/929509970624532511/969286397301248050&quot;);"
onclick="soundOk()">Launcher Patch V1.0 Released!
</a>
</div>
</li>
@@ -92,7 +101,7 @@
<div class="body">
<a
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>
</div>
</li>

View File

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