Merge pull request #5 from ZeruLight/feature/myseries

my series patch
This commit is contained in:
wish
2022-07-26 21:30:20 +10:00
committed by GitHub
23 changed files with 979 additions and 973 deletions

View File

@@ -2,33 +2,45 @@ package stringstack
import ( import (
"errors" "errors"
"sync"
) )
// StringStack is a basic LIFO "stack" for storing strings. // StringStack is a basic LIFO "stack" for storing strings.
type StringStack struct { type StringStack struct {
sync.Mutex Locked bool
stack []string stack []string
} }
// New creates a new instance of StringStack // New creates a new instance of StringStack
func New() *StringStack { func New() *StringStack {
return &StringStack{} return &StringStack{Locked: false}
}
// Set sets up a new StringStack
func (s *StringStack) Set(v string) {
s.stack = []string{v}
}
// Lock freezes the StringStack
func (s *StringStack) Lock() {
if !s.Locked {
s.Locked = true
}
}
// Unlock unfreezes the StringStack
func (s *StringStack) Unlock() {
if s.Locked {
s.Locked = false
}
} }
// Push pushes a string onto the stack. // Push pushes a string onto the stack.
func (s *StringStack) Push(v string) { func (s *StringStack) Push(v string) {
s.Lock()
defer s.Unlock()
s.stack = append(s.stack, v) s.stack = append(s.stack, v)
} }
// Pop pops a string from the stack. // Pop pops a string from the stack.
func (s *StringStack) Pop() (string, error) { func (s *StringStack) Pop() (string, error) {
s.Lock()
defer s.Unlock()
if len(s.stack) == 0 { if len(s.stack) == 0 {
return "", errors.New("no items on stack") return "", errors.New("no items on stack")
} }

View File

@@ -8,6 +8,7 @@
"maxlauncherhr": true, "maxlauncherhr": true,
"LogInboundMessages": false, "LogInboundMessages": false,
"LogOutboundMessages": false, "LogOutboundMessages": false,
"MaxHexdumpLength": 256,
"Event": 0, "Event": 0,
"DivaEvent": 0, "DivaEvent": 0,
"FestaEvent": 0, "FestaEvent": 0,

View File

@@ -29,6 +29,7 @@ type DevModeOptions struct {
FixedStageID bool // Causes all move_stage to use the ID sl1Ns200p0a0u0 to get you into all stages FixedStageID bool // Causes all move_stage to use the ID sl1Ns200p0a0u0 to get you into all stages
LogInboundMessages bool // Log all messages sent to the server LogInboundMessages bool // Log all messages sent to the server
LogOutboundMessages bool // Log all messages sent to the clients LogOutboundMessages bool // Log all messages sent to the clients
MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled
DivaEvent int // Diva Defense event status DivaEvent int // Diva Defense event status
FestaEvent int // Hunter's Festa event status FestaEvent int // Hunter's Festa event status
TournamentEvent int // VS Tournament event status TournamentEvent int // VS Tournament event status

26
Erupe/gook.sql Normal file
View File

@@ -0,0 +1,26 @@
BEGIN;
ALTER TABLE IF EXISTS public.gook
DROP COLUMN IF EXISTS gook0status;
ALTER TABLE IF EXISTS public.gook
DROP COLUMN IF EXISTS gook1status;
ALTER TABLE IF EXISTS public.gook
DROP COLUMN IF EXISTS gook2status;
ALTER TABLE IF EXISTS public.gook
DROP COLUMN IF EXISTS gook3status;
ALTER TABLE IF EXISTS public.gook
DROP COLUMN IF EXISTS gook4status;
ALTER TABLE IF EXISTS public.gook
DROP COLUMN IF EXISTS gook5status;
ALTER TABLE IF EXISTS public.gook
DROP COLUMN IF EXISTS gook5;
UPDATE public.gook SET gook1=NULL, gook2=NULL, gook3=NULL, gook4=NULL;
END;

View File

@@ -2,6 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
"erupe-ce/common/stringsupport"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/network" "erupe-ce/network"
@@ -14,7 +15,7 @@ type MsgMhfEnumerateHouse struct {
CharID uint32 CharID uint32
Method uint8 Method uint8
Unk uint16 Unk uint16
Name []byte Name string
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -29,7 +30,7 @@ func (m *MsgMhfEnumerateHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli
m.Method = bf.ReadUint8() m.Method = bf.ReadUint8()
m.Unk = bf.ReadUint16() m.Unk = bf.ReadUint16()
_ = bf.ReadUint8() // len _ = bf.ReadUint8() // len
m.Name = bf.ReadNullTerminatedBytes() m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
return nil return nil
} }

View File

@@ -1,17 +1,17 @@
package mhfpacket package mhfpacket
import ( import (
"errors" "errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
) )
// MsgMhfEnumerateTitle represents the MSG_MHF_ENUMERATE_TITLE // MsgMhfEnumerateTitle represents the MSG_MHF_ENUMERATE_TITLE
type MsgMhfEnumerateTitle struct { type MsgMhfEnumerateTitle struct {
AckHandle uint32 AckHandle uint32
Unk0 uint32 CharID uint32
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -21,9 +21,9 @@ func (m *MsgMhfEnumerateTitle) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgMhfEnumerateTitle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfEnumerateTitle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint32() m.CharID = bf.ReadUint32()
return nil return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.

View File

@@ -1,29 +1,23 @@
package mhfpacket package mhfpacket
import ( import (
"errors" "errors"
"erupe-ce/common/stringsupport"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
) )
// MsgMhfLoadHouse represents the MSG_MHF_LOAD_HOUSE // MsgMhfLoadHouse represents the MSG_MHF_LOAD_HOUSE
type MsgMhfLoadHouse struct { type MsgMhfLoadHouse struct {
AckHandle uint32 AckHandle uint32
CharID uint32 CharID uint32
// dest? Destination uint8
// 0x3 = house // False if already in hosts My Series, in case host updates PW
// 0x4 = bookshelf CheckPass bool
// 0x5 = gallery Unk3 uint16 // Hardcoded 0 in binary
// 0x8 = tore Password string
// 0x9 = own house
// 0xA = garden
Unk1 uint8
// bool inMezSquare?
Unk2 uint8
Unk3 uint16 // Hardcoded 0 in binary
Password []byte
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -35,11 +29,11 @@ func (m *MsgMhfLoadHouse) Opcode() network.PacketID {
func (m *MsgMhfLoadHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfLoadHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.CharID = bf.ReadUint32() m.CharID = bf.ReadUint32()
m.Unk1 = bf.ReadUint8() m.Destination = bf.ReadUint8()
m.Unk2 = bf.ReadUint8() m.CheckPass = bf.ReadBool()
_ = bf.ReadUint16() _ = bf.ReadUint16()
_ = bf.ReadUint8() // Password length _ = bf.ReadUint8() // Password length
m.Password = bf.ReadNullTerminatedBytes() m.Password = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
return nil return nil
} }

View File

@@ -1,42 +1,20 @@
package mhfpacket package mhfpacket
import ( import (
"errors" "errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
) )
// GuacotUpdateEntry represents an entry inside the MsgMhfUpdateGuacot packet. type Gook struct {
type GuacotUpdateEntry struct { Exists bool
Unk0 uint32 Index uint32
Unk1 uint16 Type uint16
Unk2 uint16 Data []byte
Unk3 uint16 NameLen uint8
Unk4 uint16 Name []byte
Unk5 uint16
Unk6 uint16
Unk7 uint16
Unk8 uint16
Unk9 uint16
Unk10 uint16
Unk11 uint16
Unk12 uint16
Unk13 uint16
Unk14 uint16
Unk15 uint16
Unk16 uint16
Unk17 uint16
Unk18 uint16
Unk19 uint16
Unk20 uint16
Unk21 uint16
Unk22 uint16
Unk23 uint32
Unk24 uint32
DataSize uint8
RawDataPayload []byte
} }
// MsgMhfUpdateGuacot represents the MSG_MHF_UPDATE_GUACOT // MsgMhfUpdateGuacot represents the MSG_MHF_UPDATE_GUACOT
@@ -44,7 +22,7 @@ type MsgMhfUpdateGuacot struct {
AckHandle uint32 AckHandle uint32
EntryCount uint16 EntryCount uint16
Unk0 uint16 // Hardcoded 0 in binary Unk0 uint16 // Hardcoded 0 in binary
Entries []*GuacotUpdateEntry Gooks []Gook
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -58,38 +36,18 @@ func (m *MsgMhfUpdateGuacot) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien
m.EntryCount = bf.ReadUint16() m.EntryCount = bf.ReadUint16()
m.Unk0 = bf.ReadUint16() m.Unk0 = bf.ReadUint16()
for i := 0; i < int(m.EntryCount); i++ { for i := 0; i < int(m.EntryCount); i++ {
// Yikes. e := Gook{}
e := &GuacotUpdateEntry{} e.Index = bf.ReadUint32()
e.Type = bf.ReadUint16()
e.Unk0 = bf.ReadUint32() e.Data = bf.ReadBytes(50)
e.Unk1 = bf.ReadUint16() e.NameLen = bf.ReadUint8()
e.Unk2 = bf.ReadUint16() e.Name = bf.ReadBytes(uint(e.NameLen))
e.Unk3 = bf.ReadUint16() if e.Type > 0 {
e.Unk4 = bf.ReadUint16() e.Exists = true
e.Unk5 = bf.ReadUint16() } else {
e.Unk6 = bf.ReadUint16() e.Exists = false
e.Unk7 = bf.ReadUint16() }
e.Unk8 = bf.ReadUint16() m.Gooks = append(m.Gooks, e)
e.Unk9 = bf.ReadUint16()
e.Unk10 = bf.ReadUint16()
e.Unk11 = bf.ReadUint16()
e.Unk12 = bf.ReadUint16()
e.Unk13 = bf.ReadUint16()
e.Unk14 = bf.ReadUint16()
e.Unk15 = bf.ReadUint16()
e.Unk16 = bf.ReadUint16()
e.Unk17 = bf.ReadUint16()
e.Unk18 = bf.ReadUint16()
e.Unk19 = bf.ReadUint16()
e.Unk20 = bf.ReadUint16()
e.Unk21 = bf.ReadUint16()
e.Unk22 = bf.ReadUint16()
e.Unk23 = bf.ReadUint32()
e.Unk24 = bf.ReadUint32()
e.DataSize = bf.ReadUint8()
e.RawDataPayload = bf.ReadBytes(uint(e.DataSize))
m.Entries = append(m.Entries, e)
} }
return nil return nil
} }
@@ -98,36 +56,3 @@ func (m *MsgMhfUpdateGuacot) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien
func (m *MsgMhfUpdateGuacot) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgMhfUpdateGuacot) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED") return errors.New("NOT IMPLEMENTED")
} }
func (m *MsgMhfUpdateGuacot) GuacotUpdateEntryToBytes(Entry *GuacotUpdateEntry) []byte {
resp:= byteframe.NewByteFrame()
resp.WriteUint32(Entry.Unk0)
resp.WriteUint16(Entry.Unk1)
resp.WriteUint16(Entry.Unk1)
resp.WriteUint16(Entry.Unk2)
resp.WriteUint16(Entry.Unk3)
resp.WriteUint16(Entry.Unk4)
resp.WriteUint16(Entry.Unk5)
resp.WriteUint16(Entry.Unk6)
resp.WriteUint16(Entry.Unk7)
resp.WriteUint16(Entry.Unk8)
resp.WriteUint16(Entry.Unk9)
resp.WriteUint16(Entry.Unk10)
resp.WriteUint16(Entry.Unk11)
resp.WriteUint16(Entry.Unk12)
resp.WriteUint16(Entry.Unk13)
resp.WriteUint16(Entry.Unk14)
resp.WriteUint16(Entry.Unk15)
resp.WriteUint16(Entry.Unk16)
resp.WriteUint16(Entry.Unk17)
resp.WriteUint16(Entry.Unk18)
resp.WriteUint16(Entry.Unk19)
resp.WriteUint16(Entry.Unk20)
resp.WriteUint16(Entry.Unk21)
resp.WriteUint16(Entry.Unk22)
resp.WriteUint32(Entry.Unk23)
resp.WriteUint32(Entry.Unk24)
resp.WriteUint8(Entry.DataSize)
resp.WriteBytes(Entry.RawDataPayload)
return resp.Data()
}

View File

@@ -2,6 +2,7 @@ package mhfpacket
import ( import (
"errors" "errors"
"erupe-ce/common/stringsupport"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/network" "erupe-ce/network"
@@ -11,15 +12,10 @@ import (
// MsgMhfUpdateHouse represents the MSG_MHF_UPDATE_HOUSE // MsgMhfUpdateHouse represents the MSG_MHF_UPDATE_HOUSE
type MsgMhfUpdateHouse struct { type MsgMhfUpdateHouse struct {
AckHandle uint32 AckHandle uint32
// 01 = closed State uint8
// 02 = open anyone Unk1 uint8 // Always 0x01
// 03 = open friends Unk2 uint16 // Always 0x0000
// 04 = open guild Password string
// 05 = open friends guild
State uint8
Unk1 uint8 // Always 0x01
Unk2 uint16 // Always 0x0000
Password string
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -33,8 +29,8 @@ func (m *MsgMhfUpdateHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client
m.State = bf.ReadUint8() m.State = bf.ReadUint8()
m.Unk1 = bf.ReadUint8() m.Unk1 = bf.ReadUint8()
m.Unk2 = bf.ReadUint16() m.Unk2 = bf.ReadUint16()
_ = bf.ReadUint8() _ = bf.ReadUint8() // Password length
m.Password = string(bf.ReadNullTerminatedBytes()) m.Password = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
return nil return nil
} }

View File

@@ -11,7 +11,7 @@ import (
// MsgSysOperateRegister represents the MSG_SYS_OPERATE_REGISTER // MsgSysOperateRegister represents the MSG_SYS_OPERATE_REGISTER
type MsgSysOperateRegister struct { type MsgSysOperateRegister struct {
AckHandle uint32 AckHandle uint32
RegisterID uint32 SemaphoreID uint32
fixedZero uint16 fixedZero uint16
RawDataPayload []byte RawDataPayload []byte
} }
@@ -24,7 +24,7 @@ func (m *MsgSysOperateRegister) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgSysOperateRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgSysOperateRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.RegisterID = bf.ReadUint32() m.SemaphoreID = bf.ReadUint32()
m.fixedZero = bf.ReadUint16() m.fixedZero = bf.ReadUint16()
if m.fixedZero != 0 { if m.fixedZero != 0 {
@@ -39,7 +39,7 @@ func (m *MsgSysOperateRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cl
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.
func (m *MsgSysOperateRegister) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgSysOperateRegister) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
bf.WriteUint32(m.AckHandle) bf.WriteUint32(m.AckHandle)
bf.WriteUint32(m.RegisterID) bf.WriteUint32(m.SemaphoreID)
bf.WriteUint16(0) bf.WriteUint16(0)
bf.WriteUint16(uint16(len(m.RawDataPayload))) bf.WriteUint16(uint16(len(m.RawDataPayload)))
bf.WriteBytes(m.RawDataPayload) bf.WriteBytes(m.RawDataPayload)

View File

@@ -4,8 +4,8 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/bits" "math/bits"
"math/rand" "math/rand"
@@ -579,125 +579,51 @@ func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {}
func getGookData(s *Session, cid uint32) (uint16, []byte) {
var data []byte
var count uint16
bf := byteframe.NewByteFrame()
for i := 0; i < 5; i++ {
err := s.server.db.QueryRow(fmt.Sprintf("SELECT gook%d FROM gook WHERE id=$1", i), cid).Scan(&data)
if err == nil && data != nil {
count++
if s.charID == cid && count == 1 {
gook := byteframe.NewByteFrameFromBytes(data)
bf.WriteBytes(gook.ReadBytes(4))
d := gook.ReadBytes(2)
bf.WriteBytes(d)
bf.WriteBytes(d)
bf.WriteBytes(gook.DataFromCurrent())
} else {
bf.WriteBytes(data)
}
}
}
return count, bf.Data()
}
func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateGuacot) pkt := p.(*mhfpacket.MsgMhfEnumerateGuacot)
var data bool bf := byteframe.NewByteFrame()
err := s.server.db.QueryRow("SELECT gook0status FROM gook WHERE id = $1", s.charID).Scan(&data) count, data := getGookData(s, s.charID)
if err == nil { bf.WriteUint16(count)
tempresp := byteframe.NewByteFrame() bf.WriteBytes(data)
count := uint16(0) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
var gook0 []byte
var gook1 []byte
var gook2 []byte
var gook3 []byte
var gook4 []byte
var gook5 []byte
var gook0status bool
var gook1status bool
var gook2status bool
var gook3status bool
var gook4status bool
var gook5status bool
_ = s.server.db.QueryRow("SELECT gook0 FROM gook WHERE id = $1", s.charID).Scan(&gook0)
_ = s.server.db.QueryRow("SELECT gook1 FROM gook WHERE id = $1", s.charID).Scan(&gook1)
_ = s.server.db.QueryRow("SELECT gook2 FROM gook WHERE id = $1", s.charID).Scan(&gook2)
_ = s.server.db.QueryRow("SELECT gook3 FROM gook WHERE id = $1", s.charID).Scan(&gook3)
_ = s.server.db.QueryRow("SELECT gook4 FROM gook WHERE id = $1", s.charID).Scan(&gook4)
_ = s.server.db.QueryRow("SELECT gook5 FROM gook WHERE id = $1", s.charID).Scan(&gook5)
_ = s.server.db.QueryRow("SELECT gook0status FROM gook WHERE id = $1", s.charID).Scan(&gook0status)
_ = s.server.db.QueryRow("SELECT gook1status FROM gook WHERE id = $1", s.charID).Scan(&gook1status)
_ = s.server.db.QueryRow("SELECT gook2status FROM gook WHERE id = $1", s.charID).Scan(&gook2status)
_ = s.server.db.QueryRow("SELECT gook3status FROM gook WHERE id = $1", s.charID).Scan(&gook3status)
_ = s.server.db.QueryRow("SELECT gook4status FROM gook WHERE id = $1", s.charID).Scan(&gook4status)
_ = s.server.db.QueryRow("SELECT gook5status FROM gook WHERE id = $1", s.charID).Scan(&gook5status)
if gook0status == true {
count++
tempresp.WriteBytes(gook0)
}
if gook1status == true {
count++
tempresp.WriteBytes(gook1)
}
if gook2status == true {
count++
tempresp.WriteBytes(gook2)
}
if gook3status == true {
count++
tempresp.WriteBytes(gook3)
}
if gook4status == true {
count++
tempresp.WriteBytes(gook4)
}
if gook5status == true {
count++
tempresp.WriteBytes(gook5)
}
if count == uint16(0) {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
} else {
resp := byteframe.NewByteFrame()
resp.WriteUint16(count)
resp.WriteBytes(tempresp.Data())
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
}
} else {
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
} }
func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateGuacot) pkt := p.(*mhfpacket.MsgMhfUpdateGuacot)
count := int(pkt.EntryCount) for _, gook := range pkt.Gooks {
fmt.Printf("handleMsgMhfUpdateGuacot:%d\n", count) if !gook.Exists {
if count == 0 { s.server.db.Exec(fmt.Sprintf("UPDATE gook SET gook%d=NULL WHERE id=$1", gook.Index), s.charID)
_, err := s.server.db.Exec("INSERT INTO gook(id,gook0status,gook1status,gook2status,gook3status,gook4status,gook5status) VALUES($1,bool(false),bool(false),bool(false),bool(false),bool(false),bool(false))", s.charID) } else {
if err != nil { bf := byteframe.NewByteFrame()
fmt.Printf("INSERT INTO gook failure\n") bf.WriteUint32(gook.Index)
} bf.WriteUint16(gook.Type)
} else { bf.WriteBytes(gook.Data)
for i := 0; i < int(pkt.EntryCount); i++ { bf.WriteUint8(gook.NameLen)
gookindex := int(pkt.Entries[i].Unk0) bf.WriteBytes(gook.Name)
buf := pkt.GuacotUpdateEntryToBytes(pkt.Entries[i]) s.server.db.Exec(fmt.Sprintf("UPDATE gook SET gook%d=$1 WHERE id=$2", gook.Index), bf.Data(), s.charID)
//fmt.Printf("gookindex:%d\n", gookindex)
switch gookindex {
case 0:
s.server.db.Exec("UPDATE gook SET gook0 = $1 WHERE id = $2", buf, s.charID)
if pkt.Entries[i].Unk1 != uint16(0) {
s.server.db.Exec("UPDATE gook SET gook0status = $1 WHERE id = $2", bool(true), s.charID)
} else {
s.server.db.Exec("UPDATE gook SET gook0status = $1 WHERE id = $2", bool(false), s.charID)
}
case 1:
s.server.db.Exec("UPDATE gook SET gook1 = $1 WHERE id = $2", buf, s.charID)
if pkt.Entries[i].Unk1 != uint16(0) {
s.server.db.Exec("UPDATE gook SET gook1status = $1 WHERE id = $2", bool(true), s.charID)
} else {
s.server.db.Exec("UPDATE gook SET gook1status = $1 WHERE id = $2", bool(false), s.charID)
}
case 2:
s.server.db.Exec("UPDATE gook SET gook2 = $1 WHERE id = $2", buf, s.charID)
if pkt.Entries[i].Unk1 != uint16(0) {
s.server.db.Exec("UPDATE gook SET gook2status = $1 WHERE id = $2", bool(true), s.charID)
} else {
s.server.db.Exec("UPDATE gook SET gook2status = $1 WHERE id = $2", bool(false), s.charID)
}
case 3:
s.server.db.Exec("UPDATE gook SET gook3 = $1 WHERE id = $2", buf, s.charID)
if pkt.Entries[i].Unk1 != uint16(0) {
s.server.db.Exec("UPDATE gook SET gook3status = $1 WHERE id = $2", bool(true), s.charID)
} else {
s.server.db.Exec("UPDATE gook SET gook3status = $1 WHERE id = $2", bool(false), s.charID)
}
case 4:
s.server.db.Exec("UPDATE gook SET gook4 = $1 WHERE id = $2", buf, s.charID)
if pkt.Entries[i].Unk1 != uint16(0) {
s.server.db.Exec("UPDATE gook SET gook4status = $1 WHERE id = $2", bool(true), s.charID)
} else {
s.server.db.Exec("UPDATE gook SET gook4status = $1 WHERE id = $2", bool(false), s.charID)
}
}
} }
} }
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})

View File

@@ -1,15 +1,15 @@
package channelserver package channelserver
import ( import (
"encoding/hex"
"encoding/binary" "encoding/binary"
"encoding/hex"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"erupe-ce/common/byteframe"
"erupe-ce/common/bfutil" "erupe-ce/common/bfutil"
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/server/channelserver/compression/deltacomp" "erupe-ce/server/channelserver/compression/deltacomp"
"erupe-ce/server/channelserver/compression/nullcomp" "erupe-ce/server/channelserver/compression/nullcomp"
@@ -61,6 +61,14 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
s.logger.Fatal("Failed to character weapon type in db", zap.Error(err)) s.logger.Fatal("Failed to character weapon type in db", zap.Error(err))
} }
s.myseries.houseTier = decompressedData[129900:129905] // 0x1FB6C + 5
s.myseries.houseData = decompressedData[130561:130756] // 0x1FE01 + 195
s.myseries.bookshelfData = decompressedData[139928:145504] // 0x22298 + 5576
// Gallery data also exists at 0x21578, is this the contest submission?
s.myseries.galleryData = decompressedData[140064:141812] // 0x22320 + 1748
s.myseries.toreData = decompressedData[130228:130468] // 0x1FCB4 + 240
s.myseries.gardenData = decompressedData[142424:142492] // 0x22C58 + 68
isMale := uint8(decompressedData[80]) // 0x50 isMale := uint8(decompressedData[80]) // 0x50
if isMale == 1 { if isMale == 1 {
_, err = s.server.db.Exec("UPDATE characters SET is_female=true WHERE id=$1", s.charID) _, err = s.server.db.Exec("UPDATE characters SET is_female=true WHERE id=$1", s.charID)

View File

@@ -263,7 +263,7 @@ func getCharInfo(server *Server, charName string) string {
objInfo := "" objInfo := ""
obj := server.FindStageObjectByChar(c.charID) obj := server.FindObjectByChar(c.charID)
// server.logger.Info("Found object: %+v", zap.Object("obj", obj)) // server.logger.Info("Found object: %+v", zap.Object("obj", obj))
if obj != nil { if obj != nil {

View File

@@ -2,6 +2,8 @@ package channelserver
import ( import (
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring"
"erupe-ce/common/stringsupport"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"go.uber.org/zap" "go.uber.org/zap"
) )
@@ -15,29 +17,176 @@ func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { type HouseData struct {
pkt := p.(*mhfpacket.MsgMhfEnumerateHouse) CharID uint32 `db:"id"`
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) HRP uint16 `db:"hrp"`
GR uint16 `db:"gr"`
Name string `db:"name"`
} }
func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateHouse)
bf := byteframe.NewByteFrame()
var houses []HouseData
switch pkt.Method {
case 1:
var friendsList string
s.server.db.QueryRow("SELECT friends FROM characters WHERE id=$1", s.charID).Scan(&friendsList)
cids := stringsupport.CSVElems(friendsList)
for _, cid := range cids {
house := HouseData{}
row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", cid)
err := row.StructScan(&house)
if err != nil {
panic(err)
} else {
houses = append(houses, house)
}
}
case 2:
guild, err := GetGuildInfoByCharacterId(s, s.charID)
if err != nil {
break
}
guildMembers, err := GetGuildMembers(s, guild.ID, false)
if err != nil {
break
}
for _, member := range guildMembers {
house := HouseData{}
row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", member.CharID)
err := row.StructScan(&house)
if err != nil {
panic(err)
} else {
houses = append(houses, house)
}
}
case 3:
house := HouseData{}
row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE name=$1", pkt.Name)
err := row.StructScan(&house)
if err != nil {
panic(err)
} else {
houses = append(houses, house)
}
case 4:
house := HouseData{}
row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", pkt.CharID)
err := row.StructScan(&house)
if err != nil {
panic(err)
} else {
houses = append(houses, house)
}
case 5: // Recent visitors
break
}
var exists int
for _, house := range houses {
for _, session := range s.server.sessions {
if session.charID == house.CharID {
exists++
bf.WriteUint32(house.CharID)
bf.WriteUint8(session.myseries.state)
if len(session.myseries.password) > 0 {
bf.WriteUint8(3)
} else {
bf.WriteUint8(0)
}
bf.WriteUint16(house.HRP)
bf.WriteUint16(house.GR)
ps.Uint8(bf, house.Name, true)
break
}
}
}
resp := byteframe.NewByteFrame()
resp.WriteUint16(uint16(exists))
resp.WriteBytes(bf.Data())
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
}
func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateHouse)
// 01 = closed
// 02 = open anyone
// 03 = open friends
// 04 = open guild
// 05 = open friends+guild
s.myseries.state = pkt.State
s.myseries.password = pkt.Password
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadHouse) pkt := p.(*mhfpacket.MsgMhfLoadHouse)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
var data []byte if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass {
err := s.server.db.QueryRow("SELECT house FROM characters WHERE id=$1", s.charID).Scan(&data) for _, session := range s.server.sessions {
if session.charID == pkt.CharID && pkt.Password != session.myseries.password {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
}
}
var furniture []byte
err := s.server.db.QueryRow("SELECT house FROM characters WHERE id=$1", pkt.CharID).Scan(&furniture)
if err != nil { if err != nil {
panic(err) panic(err)
} }
if data == nil { if furniture == nil {
data = make([]byte, 20) furniture = make([]byte, 20)
} }
if pkt.CharID != s.charID {
bf.WriteBytes(make([]byte, 219)) switch pkt.Destination {
case 3: // Others house
for _, session := range s.server.sessions {
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.houseTier)
bf.WriteBytes(session.myseries.houseData)
bf.WriteBytes(make([]byte, 19)) // Padding?
bf.WriteBytes(furniture)
}
}
case 4: // Bookshelf
for _, session := range s.server.sessions {
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.bookshelfData)
}
}
case 5: // Gallery
for _, session := range s.server.sessions {
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.galleryData)
}
}
case 8: // Tore
for _, session := range s.server.sessions {
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.toreData)
}
}
case 9: // Own house
bf.WriteBytes(furniture)
case 10: // Garden
for _, session := range s.server.sessions {
if session.charID == pkt.CharID {
bf.WriteBytes(session.myseries.gardenData)
c, d := getGookData(s, pkt.CharID)
bf.WriteUint16(c)
bf.WriteUint16(0)
bf.WriteBytes(d)
}
}
}
if len(bf.Data()) == 0 {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
} else {
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
bf.WriteBytes(data)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }
func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {
@@ -145,14 +294,18 @@ func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateTitle) pkt := p.(*mhfpacket.MsgMhfEnumerateTitle)
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
titleCount := 114 // all titles unlocked if pkt.CharID == s.charID {
bf.WriteUint16(uint16(titleCount)) // title count titleCount := 114 // all titles unlocked
bf.WriteUint16(0) // unk bf.WriteUint16(uint16(titleCount)) // title count
for i := 0; i < titleCount; i++ { bf.WriteUint16(0) // unk
bf.WriteUint16(uint16(i)) for i := 0; i < titleCount; i++ {
bf.WriteUint16(0) // unk bf.WriteUint16(uint16(i))
bf.WriteUint32(0) // timestamp acquired bf.WriteUint16(0) // unk
bf.WriteUint32(0) // timestamp updated bf.WriteUint32(0) // timestamp acquired
bf.WriteUint32(0) // timestamp updated
}
} else {
bf.WriteUint16(0)
} }
doAckBufSucceed(s, pkt.AckHandle, bf.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data())
} }

View File

@@ -10,44 +10,31 @@ import (
func handleMsgSysCreateObject(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCreateObject(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysCreateObject) pkt := p.(*mhfpacket.MsgSysCreateObject)
// Lock the stage. s.stage.Lock()
s.server.Lock() newObj := &Object{
id: s.stage.NextObjectID(),
// Make a new stage object and insert it into the stage.
objID := s.stage.GetNewObjectID(s.charID)
newObj := &StageObject{
id: objID,
ownerCharID: s.charID, ownerCharID: s.charID,
x: pkt.X, x: pkt.X,
y: pkt.Y, y: pkt.Y,
z: pkt.Z, z: pkt.Z,
} }
s.stage.objects[s.charID] = newObj s.stage.objects[s.charID] = newObj
s.stage.Unlock()
// Unlock the stage.
s.server.Unlock()
// Response to our requesting client. // Response to our requesting client.
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint32(objID) // New local obj handle. resp.WriteUint32(newObj.id) // New local obj handle.
doAckSimpleSucceed(s, pkt.AckHandle, resp.Data()) doAckSimpleSucceed(s, pkt.AckHandle, resp.Data())
// Duplicate the object creation to all sessions in the same stage. // Duplicate the object creation to all sessions in the same stage.
dupObjUpdate := &mhfpacket.MsgSysDuplicateObject{ dupObjUpdate := &mhfpacket.MsgSysDuplicateObject{
ObjID: objID, ObjID: newObj.id,
X: pkt.X, X: newObj.x,
Y: pkt.Y, Y: newObj.y,
Z: pkt.Z, Z: newObj.z,
OwnerCharID: s.charID, OwnerCharID: newObj.ownerCharID,
} }
for i := 1; i <= 3; i++ { s.logger.Info(fmt.Sprintf("Broadcasting new object: %s (%d)", s.Name, s.charID))
s.server.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{
CharID: s.charID,
BinaryType: uint8(i),
}, s)
}
s.logger.Info("Duplicate a new characters to others clients")
s.stage.BroadcastMHF(dupObjUpdate, s) s.stage.BroadcastMHF(dupObjUpdate, s)
} }
@@ -74,7 +61,14 @@ func handleMsgSysRotateObject(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysDuplicateObject(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysDuplicateObject(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysSetObjectBinary)
for _, object := range s.stage.objects {
if object.id == pkt.ObjID {
object.binary = pkt.RawDataPayload
}
}
}
func handleMsgSysGetObjectBinary(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysGetObjectBinary(s *Session, p mhfpacket.MHFPacket) {}

View File

@@ -1,7 +1,6 @@
package channelserver package channelserver
import ( import (
"encoding/hex"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
) )
@@ -10,129 +9,7 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysOperateRegister) pkt := p.(*mhfpacket.MsgSysOperateRegister)
bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload)
s.server.raviente.Lock() s.server.raviente.Lock()
switch pkt.RegisterID { if pkt.SemaphoreID == s.server.raviente.state.semaphoreID {
case 786461:
resp := byteframe.NewByteFrame()
size := 6
for i := 0; i < len(bf.Data())-1; i += size {
op := bf.ReadUint8()
dest := bf.ReadUint8()
data := bf.ReadUint32()
resp.WriteUint8(1)
resp.WriteUint8(dest)
switch dest {
case 0:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.nextTime = data
case 1:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.startTime = data
case 2:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.killedTime = data
case 3:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.postTime = data
case 4:
ref := &s.server.raviente.register.register[0]
switch op {
case 2:
resp.WriteUint32(*ref)
resp.WriteUint32(*ref + uint32(data))
*ref += data
case 13:
resp.WriteUint32(0)
resp.WriteUint32(data)
*ref = data
case 14:
resp.WriteUint32(0)
resp.WriteUint32(data)
}
case 5:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.carveQuest = data
case 6:
ref := &s.server.raviente.register.register[1]
switch op {
case 2:
resp.WriteUint32(*ref)
resp.WriteUint32(*ref + uint32(data))
*ref += data
case 13:
resp.WriteUint32(0)
resp.WriteUint32(data)
*ref = data
case 14:
resp.WriteUint32(0)
resp.WriteUint32(data)
}
case 7:
ref := &s.server.raviente.register.register[2]
switch op {
case 2:
resp.WriteUint32(*ref)
resp.WriteUint32(*ref + uint32(data))
*ref += data
case 13:
resp.WriteUint32(0)
resp.WriteUint32(data)
*ref = data
case 14:
resp.WriteUint32(0)
resp.WriteUint32(data)
}
case 8:
ref := &s.server.raviente.register.register[3]
switch op {
case 2:
resp.WriteUint32(*ref)
resp.WriteUint32(*ref + uint32(data))
*ref += data
case 13:
resp.WriteUint32(0)
resp.WriteUint32(data)
*ref = data
case 14:
resp.WriteUint32(0)
resp.WriteUint32(data)
}
case 9:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.maxPlayers = data
case 10:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.ravienteType = data
case 11:
ref := &s.server.raviente.register.register[4]
switch op {
case 2:
resp.WriteUint32(*ref)
resp.WriteUint32(*ref + uint32(data))
*ref += data
case 13:
resp.WriteUint32(0)
resp.WriteUint32(data)
*ref = data
case 14:
resp.WriteUint32(0)
resp.WriteUint32(data)
}
default:
resp.WriteUint32(0)
resp.WriteUint32(0)
}
}
resp.WriteUint8(0)
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
case 917533:
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
size := 6 size := 6
for i := 0; i < len(bf.Data())-1; i += size { for i := 0; i < len(bf.Data())-1; i += size {
@@ -152,12 +29,12 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {
} else if dest == 17 { // Berserk poison tracker } else if dest == 17 { // Berserk poison tracker
if damageMultiplier == 1 { if damageMultiplier == 1 {
resp.WriteUint32(*ref + data) resp.WriteUint32(*ref + data)
*ref += data
} else { } else {
resp.WriteUint32(*ref + data) resp.WriteUint32(*ref + data)
*ref += data
} }
} else { } else {
resp.WriteUint32(*ref + data * damageMultiplier) resp.WriteUint32(*ref + data*damageMultiplier)
*ref += data * damageMultiplier *ref += data * damageMultiplier
} }
case 13: case 13:
@@ -170,8 +47,7 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {
} }
resp.WriteUint8(0) resp.WriteUint8(0)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) doAckBufSucceed(s, pkt.AckHandle, resp.Data())
} else if pkt.SemaphoreID == s.server.raviente.support.semaphoreID {
case 851997:
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
size := 6 size := 6
for i := 0; i < len(bf.Data())-1; i += size { for i := 0; i < len(bf.Data())-1; i += size {
@@ -196,6 +72,126 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {
} }
resp.WriteUint8(0) resp.WriteUint8(0)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) doAckBufSucceed(s, pkt.AckHandle, resp.Data())
} else if pkt.SemaphoreID == s.server.raviente.register.semaphoreID {
resp := byteframe.NewByteFrame()
size := 6
for i := 0; i < len(bf.Data())-1; i += size {
op := bf.ReadUint8()
dest := bf.ReadUint8()
data := bf.ReadUint32()
resp.WriteUint8(1)
resp.WriteUint8(dest)
switch dest {
case 0:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.nextTime = data
case 1:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.startTime = data
case 2:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.killedTime = data
case 3:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.postTime = data
case 4:
ref := &s.server.raviente.register.register[0]
switch op {
case 2:
resp.WriteUint32(*ref)
resp.WriteUint32(*ref + uint32(data))
*ref += data
case 13:
resp.WriteUint32(0)
resp.WriteUint32(data)
*ref = data
case 14:
resp.WriteUint32(0)
resp.WriteUint32(data)
}
case 5:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.carveQuest = data
case 6:
ref := &s.server.raviente.register.register[1]
switch op {
case 2:
resp.WriteUint32(*ref)
resp.WriteUint32(*ref + uint32(data))
*ref += data
case 13:
resp.WriteUint32(0)
resp.WriteUint32(data)
*ref = data
case 14:
resp.WriteUint32(0)
resp.WriteUint32(data)
}
case 7:
ref := &s.server.raviente.register.register[2]
switch op {
case 2:
resp.WriteUint32(*ref)
resp.WriteUint32(*ref + uint32(data))
*ref += data
case 13:
resp.WriteUint32(0)
resp.WriteUint32(data)
*ref = data
case 14:
resp.WriteUint32(0)
resp.WriteUint32(data)
}
case 8:
ref := &s.server.raviente.register.register[3]
switch op {
case 2:
resp.WriteUint32(*ref)
resp.WriteUint32(*ref + uint32(data))
*ref += data
case 13:
resp.WriteUint32(0)
resp.WriteUint32(data)
*ref = data
case 14:
resp.WriteUint32(0)
resp.WriteUint32(data)
}
case 9:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.maxPlayers = data
case 10:
resp.WriteUint32(0)
resp.WriteUint32(data)
s.server.raviente.register.ravienteType = data
case 11:
ref := &s.server.raviente.register.register[4]
switch op {
case 2:
resp.WriteUint32(*ref)
resp.WriteUint32(*ref + uint32(data))
*ref += data
case 13:
resp.WriteUint32(0)
resp.WriteUint32(data)
*ref = data
case 14:
resp.WriteUint32(0)
resp.WriteUint32(data)
}
default:
resp.WriteUint32(0)
resp.WriteUint32(0)
}
}
resp.WriteUint8(0)
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
s.notifyall() s.notifyall()
s.server.raviente.Unlock() s.server.raviente.Unlock()
@@ -205,74 +201,66 @@ func handleMsgSysLoadRegister(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysLoadRegister) pkt := p.(*mhfpacket.MsgSysLoadRegister)
r := pkt.Unk1 r := pkt.Unk1
switch r { switch r {
case 12: case 12:
if pkt.RegisterID == 983077 { resp := byteframe.NewByteFrame()
data, _ := hex.DecodeString("000C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") resp.WriteUint8(0)
doAckBufFail(s, pkt.AckHandle, data) resp.WriteUint8(12)
} else if pkt.RegisterID == 983069 { resp.WriteUint32(s.server.raviente.register.nextTime)
data, _ := hex.DecodeString("000C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") resp.WriteUint32(s.server.raviente.register.startTime)
doAckBufFail(s, pkt.AckHandle, data) resp.WriteUint32(s.server.raviente.register.killedTime)
} resp.WriteUint32(s.server.raviente.register.postTime)
resp := byteframe.NewByteFrame() resp.WriteUint32(s.server.raviente.register.register[0])
resp.WriteUint8(0) resp.WriteUint32(s.server.raviente.register.carveQuest)
resp.WriteUint8(12) resp.WriteUint32(s.server.raviente.register.register[1])
resp.WriteUint32(s.server.raviente.register.nextTime) resp.WriteUint32(s.server.raviente.register.register[2])
resp.WriteUint32(s.server.raviente.register.startTime) resp.WriteUint32(s.server.raviente.register.register[3])
resp.WriteUint32(s.server.raviente.register.killedTime) resp.WriteUint32(s.server.raviente.register.maxPlayers)
resp.WriteUint32(s.server.raviente.register.postTime) resp.WriteUint32(s.server.raviente.register.ravienteType)
resp.WriteUint32(s.server.raviente.register.register[0]) resp.WriteUint32(s.server.raviente.register.register[4])
resp.WriteUint32(s.server.raviente.register.carveQuest) doAckBufSucceed(s, pkt.AckHandle, resp.Data())
resp.WriteUint32(s.server.raviente.register.register[1]) case 29:
resp.WriteUint32(s.server.raviente.register.register[2]) resp := byteframe.NewByteFrame()
resp.WriteUint32(s.server.raviente.register.register[3]) resp.WriteUint8(0)
resp.WriteUint32(s.server.raviente.register.maxPlayers) resp.WriteUint8(29)
resp.WriteUint32(s.server.raviente.register.ravienteType) for _, v := range s.server.raviente.state.stateData {
resp.WriteUint32(s.server.raviente.register.register[4]) resp.WriteUint32(v)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) }
case 29: doAckBufSucceed(s, pkt.AckHandle, resp.Data())
resp := byteframe.NewByteFrame() case 25:
resp.WriteUint8(0) resp := byteframe.NewByteFrame()
resp.WriteUint8(29) resp.WriteUint8(0)
for _, v := range s.server.raviente.state.stateData { resp.WriteUint8(25)
resp.WriteUint32(v) for _, v := range s.server.raviente.support.supportData {
} resp.WriteUint32(v)
doAckBufSucceed(s, pkt.AckHandle, resp.Data()) }
case 25: doAckBufSucceed(s, pkt.AckHandle, resp.Data())
resp := byteframe.NewByteFrame()
resp.WriteUint8(0)
resp.WriteUint8(25)
for _, v := range s.server.raviente.support.supportData {
resp.WriteUint32(v)
}
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
} }
} }
// Unused
func (s *Session) notifyplayer() {
s.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0E, 0x00, 0x1D})
s.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0D, 0x00, 0x1D})
s.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0C, 0x00, 0x1D})
}
func (s *Session) notifyall() { func (s *Session) notifyall() {
var temp mhfpacket.MHFPacket
raviNotif := byteframe.NewByteFrame()
temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: s.server.raviente.support.semaphoreID}
raviNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(raviNotif, s.clientContext)
temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: s.server.raviente.state.semaphoreID}
raviNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(raviNotif, s.clientContext)
temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: s.server.raviente.register.semaphoreID}
raviNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(raviNotif, s.clientContext)
raviNotif.WriteUint16(0x0010) // End it.
if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists { if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists {
for session := range s.server.semaphore["hs_l0u3B51J9k3"].clients { for session := range s.server.semaphore["hs_l0u3B51J9k3"].clients {
session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0C, 0x00, 0x1D}) session.QueueSend(raviNotif.Data())
session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0D, 0x00, 0x1D})
session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0E, 0x00, 0x1D})
} }
} else if _, exists := s.server.semaphore["hs_l0u3B5129k3"]; exists { } else if _, exists := s.server.semaphore["hs_l0u3B5129k3"]; exists {
for session := range s.server.semaphore["hs_l0u3B5129k3"].clients { for session := range s.server.semaphore["hs_l0u3B5129k3"].clients {
session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0C, 0x00, 0x1D}) session.QueueSend(raviNotif.Data())
session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0D, 0x00, 0x1D})
session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0E, 0x00, 0x1D})
} }
} else if _, exists := s.server.semaphore["hs_l0u3B512Ak3"]; exists { } else if _, exists := s.server.semaphore["hs_l0u3B512Ak3"]; exists {
for session := range s.server.semaphore["hs_l0u3B512Ak3"].clients { for session := range s.server.semaphore["hs_l0u3B512Ak3"].clients {
session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0C, 0x00, 0x1D}) session.QueueSend(raviNotif.Data())
session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0D, 0x00, 0x1D})
session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0E, 0x00, 0x1D})
} }
} }
} }
@@ -288,27 +276,28 @@ func checkRaviSemaphore(s *Session) bool {
return false return false
} }
func releaseRaviSemaphore(s *Session) { //func releaseRaviSemaphore(s *Session) {
s.server.raviente.Lock() // s.server.raviente.Lock()
if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists { // if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists {
if len(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots) == 0 { // if len(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots) == 0 {
resetRavi(s) // resetRavi(s)
} // }
} // }
if _, exists := s.server.semaphore["hs_l0u3B5129k3"]; exists { // if _, exists := s.server.semaphore["hs_l0u3B5129k3"]; exists {
if len(s.server.semaphore["hs_l0u3B5129k3"].reservedClientSlots) == 0 { // if len(s.server.semaphore["hs_l0u3B5129k3"].reservedClientSlots) == 0 {
resetRavi(s) // resetRavi(s)
} // }
} // }
if _, exists := s.server.semaphore["hs_l0u3B512Ak3"]; exists { // if _, exists := s.server.semaphore["hs_l0u3B512Ak3"]; exists {
if len(s.server.semaphore["hs_l0u3B512Ak3"].reservedClientSlots) == 0 { // if len(s.server.semaphore["hs_l0u3B512Ak3"].reservedClientSlots) == 0 {
resetRavi(s) // resetRavi(s)
} // }
} // }
s.server.raviente.Unlock() // s.server.raviente.Unlock()
} //}
func resetRavi(s *Session) { func resetRavi(s *Session) {
s.server.raviente.Lock()
s.server.raviente.register.nextTime = 0 s.server.raviente.register.nextTime = 0
s.server.raviente.register.startTime = 0 s.server.raviente.register.startTime = 0
s.server.raviente.register.killedTime = 0 s.server.raviente.register.killedTime = 0
@@ -320,6 +309,7 @@ func resetRavi(s *Session) {
s.server.raviente.register.register = []uint32{0, 0, 0, 0, 0} s.server.raviente.register.register = []uint32{0, 0, 0, 0, 0}
s.server.raviente.state.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} s.server.raviente.state.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
s.server.raviente.support.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} s.server.raviente.support.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
s.server.raviente.Unlock()
} }
// Unused // Unused

View File

@@ -1,7 +1,9 @@
package channelserver package channelserver
import ( import (
"erupe-ce/common/byteframe"
"fmt" "fmt"
"go.uber.org/zap"
"strings" "strings"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
@@ -10,11 +12,13 @@ import (
func removeSessionFromSemaphore(s *Session) { func removeSessionFromSemaphore(s *Session) {
s.server.semaphoreLock.Lock() s.server.semaphoreLock.Lock()
for _, semaphore := range s.server.semaphore { for _, semaphore := range s.server.semaphore {
if _, exists := semaphore.reservedClientSlots[s.charID]; exists {
delete(semaphore.reservedClientSlots, s.charID)
}
if _, exists := semaphore.clients[s]; exists { if _, exists := semaphore.clients[s]; exists {
delete(semaphore.clients, s) delete(semaphore.clients, s)
} }
} }
releaseRaviSemaphore(s)
s.server.semaphoreLock.Unlock() s.server.semaphoreLock.Unlock()
} }
@@ -23,54 +27,50 @@ func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x03, 0x00, 0x0d}) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x03, 0x00, 0x0d})
} }
func destructEmptySemaphores(s *Session) {
s.server.semaphoreLock.Lock()
for id, sema := range s.server.semaphore {
if len(sema.reservedClientSlots) == 0 && len(sema.clients) == 0 {
s.server.semaphoreLock.Unlock()
delete(s.server.semaphore, id)
s.server.semaphoreLock.Lock()
if strings.HasPrefix(id, "hs_l0u3B51") {
releaseRaviSemaphore(s, sema)
}
s.logger.Debug("Destructed semaphore", zap.String("sema.id_semaphore", id))
}
}
s.server.semaphoreLock.Unlock()
}
func releaseRaviSemaphore(s *Session, sema *Semaphore) {
if !strings.HasSuffix(sema.id_semaphore, "5") {
delete(sema.reservedClientSlots, s.charID)
delete(sema.clients, s)
}
if len(sema.reservedClientSlots) == 0 && len(sema.clients) == 0 {
s.logger.Debug("Raviente semaphore is empty, resetting")
resetRavi(s)
}
}
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 sem := pkt.AckHandle
if s.server.semaphore != nil { if s.server.semaphore != nil {
destructEmptySemaphores(s)
s.server.semaphoreLock.Lock() s.server.semaphoreLock.Lock()
for id := range s.server.semaphore { for id, sema := range s.server.semaphore {
switch sem { if sema.id == sem {
case 917533: if strings.HasPrefix(id, "hs_l0u3B51") {
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k3" { releaseRaviSemaphore(s, sema)
delete(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots, s.charID) s.server.semaphoreLock.Unlock()
delete(s.server.semaphore["hs_l0u3B51J9k3"].clients, s) return
} else if s.server.semaphore[id].id_semaphore == "hs_l0u3B5129k3" {
delete(s.server.semaphore["hs_l0u3B5129k3"].reservedClientSlots, s.charID)
delete(s.server.semaphore["hs_l0u3B5129k3"].clients, s)
} else if s.server.semaphore[id].id_semaphore == "hs_l0u3B512Ak3" {
delete(s.server.semaphore["hs_l0u3B512Ak3"].reservedClientSlots, s.charID)
delete(s.server.semaphore["hs_l0u3B512Ak3"].clients, s)
}
case 851997:
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k4" {
delete(s.server.semaphore["hs_l0u3B51J9k4"].reservedClientSlots, s.charID)
} else if s.server.semaphore[id].id_semaphore == "hs_l0u3B5129k4" {
delete(s.server.semaphore["hs_l0u3B5129k4"].reservedClientSlots, s.charID)
} else if s.server.semaphore[id].id_semaphore == "hs_l0u3B512Ak4" {
delete(s.server.semaphore["hs_l0u3B512Ak4"].reservedClientSlots, s.charID)
}
case 786461:
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k5" {
delete(s.server.semaphore["hs_l0u3B51J9k5"].reservedClientSlots, s.charID)
} else if s.server.semaphore[id].id_semaphore == "hs_l0u3B5129k5" {
delete(s.server.semaphore["hs_l0u3B5129k5"].reservedClientSlots, s.charID)
} else if s.server.semaphore[id].id_semaphore == "hs_l0u3B512Ak5" {
delete(s.server.semaphore["hs_l0u3B512Ak5"].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" &&
s.server.semaphore[id].id_semaphore != "hs_l0u3B5129k3" &&
s.server.semaphore[id].id_semaphore != "hs_l0u3B5129k4" &&
s.server.semaphore[id].id_semaphore != "hs_l0u3B5129k5" &&
s.server.semaphore[id].id_semaphore != "hs_l0u3B512Ak3" &&
s.server.semaphore[id].id_semaphore != "hs_l0u3B512Ak4" &&
s.server.semaphore[id].id_semaphore != "hs_l0u3B512Ak5" {
delete(s.server.semaphore[id].reservedClientSlots, s.charID)
}
} }
s.server.semaphoreLock.Unlock()
delete(s.server.semaphore, id)
s.logger.Debug("Destructed semaphore", zap.String("sema.id_semaphore", id))
return
} }
} }
s.server.semaphoreLock.Unlock() s.server.semaphoreLock.Unlock()
@@ -81,15 +81,22 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysCreateAcquireSemaphore) pkt := p.(*mhfpacket.MsgSysCreateAcquireSemaphore)
SemaphoreID := pkt.SemaphoreID SemaphoreID := pkt.SemaphoreID
newSemaphore, gotNewStage := s.server.semaphore[SemaphoreID] newSemaphore, exists := s.server.semaphore[SemaphoreID]
fmt.Printf("Got reserve stage req, StageID: %v\n\n", SemaphoreID) fmt.Printf("Got reserve stage req, StageID: %v\n\n", SemaphoreID)
if !gotNewStage { if !exists {
s.server.semaphoreLock.Lock() s.server.semaphoreLock.Lock()
if strings.HasPrefix(SemaphoreID, "hs_l0u3B51") { if strings.HasPrefix(SemaphoreID, "hs_l0u3B51") {
s.server.semaphore[SemaphoreID] = NewSemaphore(SemaphoreID, 32) s.server.semaphore[SemaphoreID] = NewSemaphore(s.server, SemaphoreID, 32)
if strings.HasSuffix(SemaphoreID, "3") {
s.server.raviente.state.semaphoreID = s.server.semaphore[SemaphoreID].id
} else if strings.HasSuffix(SemaphoreID, "4") {
s.server.raviente.support.semaphoreID = s.server.semaphore[SemaphoreID].id
} else if strings.HasSuffix(SemaphoreID, "5") {
s.server.raviente.register.semaphoreID = s.server.semaphore[SemaphoreID].id
}
} else { } else {
s.server.semaphore[SemaphoreID] = NewSemaphore(SemaphoreID, 1) s.server.semaphore[SemaphoreID] = NewSemaphore(s.server, SemaphoreID, 1)
} }
newSemaphore = s.server.semaphore[SemaphoreID] newSemaphore = s.server.semaphore[SemaphoreID]
s.server.semaphoreLock.Unlock() s.server.semaphoreLock.Unlock()
@@ -98,35 +105,18 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
newSemaphore.Lock() newSemaphore.Lock()
defer newSemaphore.Unlock() defer newSemaphore.Unlock()
if _, exists := newSemaphore.reservedClientSlots[s.charID]; exists { if _, exists := newSemaphore.reservedClientSlots[s.charID]; exists {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x1D}) bf := byteframe.NewByteFrame()
bf.WriteUint32(newSemaphore.id)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
} else if uint16(len(newSemaphore.reservedClientSlots)) < newSemaphore.maxPlayers { } else if uint16(len(newSemaphore.reservedClientSlots)) < newSemaphore.maxPlayers {
switch SemaphoreID { newSemaphore.reservedClientSlots[s.charID] = nil
case "hs_l0u3B51J9k3", "hs_l0u3B5129k3", "hs_l0u3B512Ak3": newSemaphore.clients[s] = s.charID
newSemaphore.reservedClientSlots[s.charID] = nil s.Lock()
newSemaphore.clients[s] = s.charID s.semaphore = newSemaphore
s.Lock() s.Unlock()
s.semaphore = newSemaphore bf := byteframe.NewByteFrame()
s.Unlock() bf.WriteUint32(newSemaphore.id)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0E, 0x00, 0x1D}) doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
case "hs_l0u3B51J9k4", "hs_l0u3B5129k4", "hs_l0u3B512Ak4":
newSemaphore.reservedClientSlots[s.charID] = nil
s.Lock()
s.semaphore = newSemaphore
s.Unlock()
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0D, 0x00, 0x1D})
case "hs_l0u3B51J9k5", "hs_l0u3B5129k5", "hs_l0u3B512Ak5":
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})
} }
@@ -138,7 +128,6 @@ 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)
releaseRaviSemaphore(s)
} }
func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) {

View File

@@ -86,7 +86,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
} }
} }
func removeEmptyStages(s *Session) { func destructEmptyStages(s *Session) {
s.server.Lock() s.server.Lock()
defer s.server.Unlock() defer s.server.Unlock()
for _, stage := range s.server.stages { for _, stage := range s.server.stages {
@@ -108,75 +108,33 @@ func removeSessionFromStage(s *Session) {
// Delete old stage objects owned by the client. // Delete old stage objects owned by the client.
s.logger.Info("Sending notification to old stage clients") s.logger.Info("Sending notification to old stage clients")
for objID, stageObject := range s.stage.objects { for _, object := range s.stage.objects {
if stageObject.ownerCharID == s.charID { if object.ownerCharID == s.charID {
clientNotif := byteframe.NewByteFrame() s.stage.BroadcastMHF(&mhfpacket.MsgSysDeleteObject{ObjID: object.id}, s)
var pkt mhfpacket.MHFPacket delete(s.stage.objects, object.ownerCharID)
pkt = &mhfpacket.MsgSysDeleteObject{
ObjID: stageObject.id,
}
clientNotif.WriteUint16(uint16(pkt.Opcode()))
pkt.Build(clientNotif, s.clientContext)
clientNotif.WriteUint16(0x0010)
for client, _ := range s.stage.clients {
client.QueueSend(clientNotif.Data())
}
// TODO(Andoryuuta): Should this be sent to the owner's client as well? it currently isn't.
// Actually delete it from the objects map.
delete(s.stage.objects, objID)
}
}
for objListID, stageObjectList := range s.stage.objectList {
if stageObjectList.charid == s.charID {
// Added to prevent duplicates from flooding ObjectMap and causing server hangs
s.stage.objectList[objListID].status = false
s.stage.objectList[objListID].charid = 0
} }
} }
s.stage.Unlock() s.stage.Unlock()
removeEmptyStages(s) destructEmptyStages(s)
destructEmptySemaphores(s)
} }
func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysEnterStage) pkt := p.(*mhfpacket.MsgSysEnterStage)
// Push our current stage ID to the movement stack before entering another one. // Push our current stage ID to the movement stack before entering another one.
s.Lock() if s.stageID == "" {
s.stageMoveStack.Push(s.stageID) s.stageMoveStack.Set(pkt.StageID)
s.Unlock() } else {
s.stageMoveStack.Push(s.stageID)
s.stageMoveStack.Lock()
}
s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{}) s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{})
if s.reservationStage != nil { if s.reservationStage != nil {
s.reservationStage = nil s.reservationStage = nil
} }
if pkt.StageID == "sl1Ns200p0a0u0" { // First entry
var temp mhfpacket.MHFPacket
loginNotif := byteframe.NewByteFrame()
s.server.Lock()
for _, session := range s.server.sessions {
if s == session || !session.binariesDone {
continue
}
temp = &mhfpacket.MsgSysInsertUser{
CharID: session.charID,
}
loginNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(loginNotif, s.clientContext)
for i := 1; i <= 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: session.charID,
BinaryType: uint8(i),
}
loginNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(loginNotif, s.clientContext)
}
}
s.server.Unlock()
loginNotif.WriteUint16(0x0010) // End it.
if len(loginNotif.Data()) > 2 {
s.QueueSend(loginNotif.Data())
}
}
doStageTransfer(s, pkt.AckHandle, pkt.StageID) doStageTransfer(s, pkt.AckHandle, pkt.StageID)
} }
@@ -184,9 +142,8 @@ func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysBackStage) pkt := p.(*mhfpacket.MsgSysBackStage)
// Transfer back to the saved stage ID before the previous move or enter. // Transfer back to the saved stage ID before the previous move or enter.
s.Lock() s.stageMoveStack.Unlock()
backStage, err := s.stageMoveStack.Pop() backStage, err := s.stageMoveStack.Pop()
s.Unlock()
if err != nil { if err != nil {
panic(err) panic(err)
@@ -198,10 +155,10 @@ func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) {
func handleMsgSysMoveStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysMoveStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysMoveStage) pkt := p.(*mhfpacket.MsgSysMoveStage)
// Push our current stage ID to the movement stack before entering another one. // Set a new move stack from the given stage ID if unlocked
s.Lock() if !s.stageMoveStack.Locked {
s.stageMoveStack.Push(s.stageID) s.stageMoveStack.Set(pkt.StageID)
s.Unlock() }
doStageTransfer(s, pkt.AckHandle, pkt.StageID) doStageTransfer(s, pkt.AckHandle, pkt.StageID)
} }
@@ -218,11 +175,9 @@ func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {
s.reservationStage.RLock() s.reservationStage.RLock()
defer s.reservationStage.RUnlock() defer s.reservationStage.RUnlock()
destructMessage := &mhfpacket.MsgSysStageDestruct{}
for charID := range s.reservationStage.reservedClientSlots { for charID := range s.reservationStage.reservedClientSlots {
session := s.server.FindSessionByCharID(charID) session := s.server.FindSessionByCharID(charID)
session.QueueSendMHF(destructMessage) session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
} }
s.server.Lock() s.server.Lock()

View File

@@ -12,6 +12,49 @@ func handleMsgSysInsertUser(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysDeleteUser(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysDeleteUser(s *Session, p mhfpacket.MHFPacket) {}
func broadcastNewUser(s *Session) {
s.logger.Debug(fmt.Sprintf("Broadcasting new user: %s (%d)", s.Name, s.charID))
clientNotif := byteframe.NewByteFrame()
var temp mhfpacket.MHFPacket
for _, session := range s.server.sessions {
if session == s || !session.binariesDone {
continue
}
temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID}
clientNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(clientNotif, s.clientContext)
for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: session.charID,
BinaryType: uint8(i + 1),
}
clientNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(clientNotif, s.clientContext)
}
}
s.QueueSend(clientNotif.Data())
serverNotif := byteframe.NewByteFrame()
temp = &mhfpacket.MsgSysInsertUser{CharID: s.charID}
serverNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(serverNotif, s.clientContext)
for i := 0; i < 3; i++ {
temp = &mhfpacket.MsgSysNotifyUserBinary{
CharID: s.charID,
BinaryType: uint8(i + 1),
}
serverNotif.WriteUint16(uint16(temp.Opcode()))
temp.Build(serverNotif, s.clientContext)
}
for _, session := range s.server.sessions {
if session == s || !session.binariesDone {
continue
}
session.QueueSend(serverNotif.Data())
}
}
func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysSetUserBinary) pkt := p.(*mhfpacket.MsgSysSetUserBinary)
s.server.userBinaryPartsLock.Lock() s.server.userBinaryPartsLock.Lock()
@@ -27,9 +70,7 @@ func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) {
} }
} }
s.binariesDone = true s.binariesDone = true
s.server.BroadcastMHF(&mhfpacket.MsgSysInsertUser{ broadcastNewUser(s)
CharID: s.charID,
}, s)
return return
} }

View File

@@ -71,8 +71,9 @@ type Server struct {
userBinaryParts map[userBinaryPartID][]byte userBinaryParts map[userBinaryPartID][]byte
// Semaphore // Semaphore
semaphoreLock sync.RWMutex semaphoreLock sync.RWMutex
semaphore map[string]*Semaphore semaphore map[string]*Semaphore
semaphoreIndex uint32
// Discord chat integration // Discord chat integration
discordBot *discordbot.DiscordBot discordBot *discordbot.DiscordBot
@@ -92,55 +93,58 @@ type Raviente struct {
} }
type RavienteRegister struct { type RavienteRegister struct {
nextTime uint32 semaphoreID uint32
startTime uint32 nextTime uint32
postTime uint32 startTime uint32
killedTime uint32 postTime uint32
killedTime uint32
ravienteType uint32 ravienteType uint32
maxPlayers uint32 maxPlayers uint32
carveQuest uint32 carveQuest uint32
register []uint32 register []uint32
} }
type RavienteState struct { type RavienteState struct {
semaphoreID uint32
damageMultiplier uint32 damageMultiplier uint32
stateData []uint32 stateData []uint32
} }
type RavienteSupport struct { type RavienteSupport struct {
semaphoreID uint32
supportData []uint32 supportData []uint32
} }
// Set up the Raviente variables for the server // Set up the Raviente variables for the server
func NewRaviente() *Raviente { func NewRaviente() *Raviente {
ravienteRegister := &RavienteRegister { ravienteRegister := &RavienteRegister{
nextTime: 0, nextTime: 0,
startTime: 0, startTime: 0,
killedTime: 0, killedTime: 0,
postTime: 0, postTime: 0,
ravienteType: 0, ravienteType: 0,
maxPlayers: 0, maxPlayers: 0,
carveQuest: 0, carveQuest: 0,
} }
ravienteState := &RavienteState { ravienteState := &RavienteState{
damageMultiplier: 1, damageMultiplier: 1,
} }
ravienteSupport := &RavienteSupport { } ravienteSupport := &RavienteSupport{}
ravienteRegister.register = []uint32{0, 0, 0, 0, 0} ravienteRegister.register = []uint32{0, 0, 0, 0, 0}
ravienteState.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} ravienteState.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
ravienteSupport.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} ravienteSupport.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
raviente := &Raviente { raviente := &Raviente{
register: ravienteRegister, register: ravienteRegister,
state: ravienteState, state: ravienteState,
support: ravienteSupport, support: ravienteSupport,
} }
return raviente return raviente
} }
// NewServer creates a new Server type. // NewServer creates a new Server type.
func NewServer(config *Config) *Server { func NewServer(config *Config) *Server {
s := &Server { s := &Server{
ID: config.ID, ID: config.ID,
logger: config.Logger, logger: config.Logger,
db: config.DB, db: config.DB,
@@ -151,6 +155,7 @@ func NewServer(config *Config) *Server {
stages: make(map[string]*Stage), stages: make(map[string]*Stage),
userBinaryParts: make(map[userBinaryPartID][]byte), userBinaryParts: make(map[userBinaryPartID][]byte),
semaphore: make(map[string]*Semaphore), semaphore: make(map[string]*Semaphore),
semaphoreIndex: 0,
discordBot: config.DiscordBot, discordBot: config.DiscordBot,
name: config.Name, name: config.Name,
enable: config.Enable, enable: config.Enable,
@@ -277,7 +282,7 @@ func (s *Server) manageSessions() {
func (s *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { func (s *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
// Broadcast the data. // Broadcast the data.
for _, session := range s.sessions { for _, session := range s.sessions {
if session == ignoredSession { if session == ignoredSession || !session.binariesDone {
continue continue
} }
@@ -295,14 +300,14 @@ func (s *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session)
func (s *Server) WorldcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { func (s *Server) WorldcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
for _, c := range s.Channels { for _, c := range s.Channels {
for _, s := range c.sessions { for _, session := range c.sessions {
if s == ignoredSession { if session == ignoredSession || !session.binariesDone {
continue continue
} }
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(uint16(pkt.Opcode())) bf.WriteUint16(uint16(pkt.Opcode()))
pkt.Build(bf, s.clientContext) pkt.Build(bf, session.clientContext)
s.QueueSendNonBlocking(bf.Data()) session.QueueSendNonBlocking(bf.Data())
} }
} }
} }
@@ -384,7 +389,7 @@ func (s *Server) FindSessionByCharID(charID uint32) *Session {
return nil return nil
} }
func (s *Server) FindStageObjectByChar(charID uint32) *StageObject { func (s *Server) FindObjectByChar(charID uint32) *Object {
s.stagesLock.RLock() s.stagesLock.RLock()
defer s.stagesLock.RUnlock() defer s.stagesLock.RUnlock()
for _, stage := range s.stages { for _, stage := range s.stages {
@@ -401,3 +406,8 @@ func (s *Server) FindStageObjectByChar(charID uint32) *StageObject {
return nil return nil
} }
func (s *Server) NextSemaphoreID() uint32 {
s.semaphoreIndex = s.semaphoreIndex + 1
return s.semaphoreIndex
}

View File

@@ -14,6 +14,8 @@ type Semaphore struct {
// Stage ID string // Stage ID string
id_semaphore string id_semaphore string
id uint32
// Map of session -> charID. // Map of session -> charID.
// These are clients that are CURRENTLY in the stage // These are clients that are CURRENTLY in the stage
clients map[*Session]uint32 clients map[*Session]uint32
@@ -26,21 +28,21 @@ type Semaphore struct {
} }
// NewStage creates a new stage with intialized values. // NewStage creates a new stage with intialized values.
func NewSemaphore(ID string, MaxPlayers uint16) *Semaphore { func NewSemaphore(s *Server, ID string, MaxPlayers uint16) *Semaphore {
s := &Semaphore{ sema := &Semaphore{
id_semaphore: ID, id_semaphore: ID,
id: s.NextSemaphoreID(),
clients: make(map[*Session]uint32), clients: make(map[*Session]uint32),
reservedClientSlots: make(map[uint32]interface{}), reservedClientSlots: make(map[uint32]interface{}),
maxPlayers: MaxPlayers, maxPlayers: MaxPlayers,
} }
return s return sema
} }
func (s *Semaphore) BroadcastRavi(pkt mhfpacket.MHFPacket) { func (s *Semaphore) BroadcastRavi(pkt mhfpacket.MHFPacket) {
// Broadcast the data. // Broadcast the data.
for session := range s.clients { for session := range s.clients {
// Make the header // Make the header
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(uint16(pkt.Opcode())) bf.WriteUint16(uint16(pkt.Opcode()))

View File

@@ -27,6 +27,7 @@ type Session struct {
sendPackets chan []byte sendPackets chan []byte
clientContext *clientctx.ClientContext clientContext *clientctx.ClientContext
myseries MySeries
stageID string stageID string
stage *Stage stage *Stage
reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet. reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet.
@@ -54,6 +55,17 @@ type Session struct {
Name string Name string
} }
type MySeries struct {
houseTier []byte
houseData []byte
bookshelfData []byte
galleryData []byte
toreData []byte
gardenData []byte
state uint8
password string
}
// NewSession creates a new Session type. // NewSession creates a new Session type.
func NewSession(server *Server, conn net.Conn) *Session { func NewSession(server *Server, conn net.Conn) *Session {
s := &Session{ s := &Session{
@@ -239,5 +251,9 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien
} }
fmt.Printf("[%s] -> [%s]\n", sender, recipient) fmt.Printf("[%s] -> [%s]\n", sender, recipient)
fmt.Printf("Opcode: %s\n", opcodePID) fmt.Printf("Opcode: %s\n", opcodePID)
fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data)) if len(data) <= s.server.erupeConfig.DevModeOptions.MaxHexdumpLength {
fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data))
} else {
fmt.Printf("Data [%d bytes]:\n(Too long!)\n\n", len(data))
}
} }

View File

@@ -9,18 +9,13 @@ import (
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
) )
// StageObject holds infomation about a specific stage object. // Object holds infomation about a specific object.
type StageObject struct { type Object struct {
sync.RWMutex sync.RWMutex
id uint32 id uint32
ownerCharID uint32 ownerCharID uint32
x, y, z float32 x, y, z float32
} binary []byte
type ObjectMap struct {
id uint8
charid uint32
status bool
} }
// stageBinaryKey is a struct used as a map key for identifying a stage binary part. // stageBinaryKey is a struct used as a map key for identifying a stage binary part.
@@ -36,13 +31,10 @@ type Stage struct {
// Stage ID string // Stage ID string
id string id string
// Total count of objects ever created for this stage. Used for ObjID generation. // Objects
gameObjectCount uint32 objects map[uint32]*Object
objectIndex uint32
// Save all object in stage
objects map[uint32]*StageObject
objectList map[uint8]*ObjectMap
// Map of session -> charID. // Map of session -> charID.
// These are clients that are CURRENTLY in the stage // These are clients that are CURRENTLY in the stage
clients map[*Session]uint32 clients map[*Session]uint32
@@ -66,14 +58,12 @@ func NewStage(ID string) *Stage {
id: ID, id: ID,
clients: make(map[*Session]uint32), clients: make(map[*Session]uint32),
reservedClientSlots: make(map[uint32]bool), reservedClientSlots: make(map[uint32]bool),
objects: make(map[uint32]*StageObject), objects: make(map[uint32]*Object),
objectIndex: 0,
rawBinaryData: make(map[stageBinaryKey][]byte), rawBinaryData: make(map[stageBinaryKey][]byte),
maxPlayers: 4, maxPlayers: 4,
gameObjectCount: 1,
objectList: make(map[uint8]*ObjectMap),
createdAt: time.Now().Format("01-02-2006 15:04:05"), createdAt: time.Now().Format("01-02-2006 15:04:05"),
} }
s.InitObjectList()
return s return s
} }
@@ -81,7 +71,7 @@ func NewStage(ID string) *Stage {
func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
// Broadcast the data. // Broadcast the data.
for session := range s.clients { for session := range s.clients {
if session == ignoredSession { if session == ignoredSession || !session.binariesDone {
continue continue
} }
@@ -97,17 +87,6 @@ func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
} }
} }
func (s *Stage) InitObjectList() {
for seq := uint8(0x7f); seq > uint8(0); seq-- {
newObj := &ObjectMap{
id: seq,
charid: uint32(0),
status: false,
}
s.objectList[seq] = newObj
}
}
func (s *Stage) isCharInQuestByID(charID uint32) bool { func (s *Stage) isCharInQuestByID(charID uint32) bool {
if _, exists := s.reservedClientSlots[charID]; exists { if _, exists := s.reservedClientSlots[charID]; exists {
return exists return exists
@@ -120,8 +99,8 @@ func (s *Stage) isQuest() bool {
return len(s.reservedClientSlots) > 0 return len(s.reservedClientSlots) > 0
} }
func (stage *Stage) GetName() string { func (s *Stage) GetName() string {
switch stage.id { switch s.id {
case MezeportaStageId: case MezeportaStageId:
return "Mezeporta" return "Mezeporta"
case GuildHallLv1StageId: case GuildHallLv1StageId:
@@ -149,20 +128,7 @@ func (stage *Stage) GetName() string {
} }
} }
func (s *Stage) GetNewObjectID(CharID uint32) uint32 { func (s *Stage) NextObjectID() uint32 {
ObjId := uint8(0) s.objectIndex = s.objectIndex + 1
for seq := uint8(0x7f); seq > uint8(0); seq-- { return s.objectIndex
if s.objectList[seq].status == false {
ObjId = seq
break
}
}
s.objectList[ObjId].status = true
s.objectList[ObjId].charid = CharID
bf := byteframe.NewByteFrame()
bf.WriteUint8(uint8(0))
bf.WriteUint8(ObjId)
bf.WriteUint16(uint16(0))
obj := uint32(bf.Data()[3]) | uint32(bf.Data()[2])<<8 | uint32(bf.Data()[1])<<16 | uint32(bf.Data()[0])<<32
return obj
} }