mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-02-06 10:06:53 +01:00
Merge branch 'main' into main
This commit is contained in:
@@ -12,12 +12,14 @@ type OperateMailOperation uint8
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
OPERATE_MAIL_DELETE = 0x01
|
OPERATE_MAIL_DELETE = 0x01
|
||||||
|
OPERATE_MAIL_LOCK = 0x02
|
||||||
|
OPERATE_MAIL_UNLOCK = 0x03
|
||||||
OPERATE_MAIL_ACQUIRE_ITEM = 0x05
|
OPERATE_MAIL_ACQUIRE_ITEM = 0x05
|
||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfOprtMail represents the MSG_MHF_OPRT_MAIL
|
// MsgMhfOprtMail represents the MSG_MHF_OPRT_MAIL
|
||||||
type MsgMhfOprtMail struct {
|
type MsgMhfOprtMail struct {
|
||||||
AckHandle uint32
|
AckHandle uint32
|
||||||
AccIndex uint8
|
AccIndex uint8
|
||||||
Index uint8
|
Index uint8
|
||||||
Operation OperateMailOperation
|
Operation OperateMailOperation
|
||||||
@@ -34,7 +36,7 @@ func (m *MsgMhfOprtMail) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfOprtMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfOprtMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
m.AckHandle = bf.ReadUint32()
|
m.AckHandle = bf.ReadUint32()
|
||||||
m.AccIndex = bf.ReadUint8()
|
m.AccIndex = bf.ReadUint8()
|
||||||
m.Index = bf.ReadUint8()
|
m.Index = bf.ReadUint8()
|
||||||
m.Operation = OperateMailOperation(bf.ReadUint8())
|
m.Operation = OperateMailOperation(bf.ReadUint8())
|
||||||
|
|||||||
@@ -9,7 +9,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// MsgMhfTransitMessage represents the MSG_MHF_TRANSIT_MESSAGE
|
// MsgMhfTransitMessage represents the MSG_MHF_TRANSIT_MESSAGE
|
||||||
type MsgMhfTransitMessage struct{}
|
type MsgMhfTransitMessage struct {
|
||||||
|
AckHandle uint32
|
||||||
|
Unk0 uint8
|
||||||
|
Unk1 uint8
|
||||||
|
Unk2 uint16
|
||||||
|
Unk3 uint16
|
||||||
|
TargetID uint32
|
||||||
|
}
|
||||||
|
|
||||||
// Opcode returns the ID associated with this packet type.
|
// Opcode returns the ID associated with this packet type.
|
||||||
func (m *MsgMhfTransitMessage) Opcode() network.PacketID {
|
func (m *MsgMhfTransitMessage) Opcode() network.PacketID {
|
||||||
@@ -18,7 +25,13 @@ func (m *MsgMhfTransitMessage) Opcode() network.PacketID {
|
|||||||
|
|
||||||
// Parse parses the packet from binary
|
// Parse parses the packet from binary
|
||||||
func (m *MsgMhfTransitMessage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
func (m *MsgMhfTransitMessage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||||
return errors.New("NOT IMPLEMENTED")
|
m.AckHandle = bf.ReadUint32()
|
||||||
|
m.Unk0 = bf.ReadUint8()
|
||||||
|
m.Unk1 = bf.ReadUint8()
|
||||||
|
m.Unk2 = bf.ReadUint16()
|
||||||
|
m.Unk3 = bf.ReadUint16()
|
||||||
|
m.TargetID = bf.ReadUint32()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build builds a binary packet from the current data.
|
// Build builds a binary packet from the current data.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -20,10 +20,10 @@ const (
|
|||||||
|
|
||||||
// MSG_SYS_CAST[ED]_BINARY broadcast types enum
|
// MSG_SYS_CAST[ED]_BINARY broadcast types enum
|
||||||
const (
|
const (
|
||||||
BroadcastTypeTargeted = 0x01
|
BroadcastTypeTargeted = 0x01
|
||||||
BroadcastTypeStage = 0x03
|
BroadcastTypeStage = 0x03
|
||||||
BroadcastTypeRavi = 0x06
|
BroadcastTypeSemaphore = 0x06
|
||||||
BroadcastTypeWorld = 0x0a
|
BroadcastTypeWorld = 0x0a
|
||||||
)
|
)
|
||||||
|
|
||||||
func sendServerChatMessage(s *Session, message string) {
|
func sendServerChatMessage(s *Session, message string) {
|
||||||
@@ -93,10 +93,24 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
s.server.BroadcastMHF(resp, s)
|
s.server.BroadcastMHF(resp, s)
|
||||||
case BroadcastTypeStage:
|
case BroadcastTypeStage:
|
||||||
s.stage.BroadcastMHF(resp, s)
|
s.stage.BroadcastMHF(resp, s)
|
||||||
case BroadcastTypeRavi:
|
case BroadcastTypeSemaphore:
|
||||||
if pkt.MessageType == 1 {
|
if pkt.MessageType == 1 {
|
||||||
session := s.server.semaphore["hs_l0u3B51J9k3"]
|
var session *Semaphore
|
||||||
|
if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists {
|
||||||
|
session = s.server.semaphore["hs_l0u3B51J9k3"]
|
||||||
|
} else if _, exists := s.server.semaphore["hs_l0u3B5129k3"]; exists {
|
||||||
|
session = s.server.semaphore["hs_l0u3B5129k3"]
|
||||||
|
} else if _, exists := s.server.semaphore["hs_l0u3B512Ak3"]; exists {
|
||||||
|
session = s.server.semaphore["hs_l0u3B512Ak3"]
|
||||||
|
}
|
||||||
(*session).BroadcastMHF(resp, s)
|
(*session).BroadcastMHF(resp, s)
|
||||||
|
} else {
|
||||||
|
s.Lock()
|
||||||
|
haveStage := s.stage != nil
|
||||||
|
if haveStage {
|
||||||
|
s.stage.BroadcastMHF(resp, s)
|
||||||
|
}
|
||||||
|
s.Unlock()
|
||||||
}
|
}
|
||||||
case BroadcastTypeTargeted:
|
case BroadcastTypeTargeted:
|
||||||
for _, targetID := range (*msgBinTargeted).TargetCharIDs {
|
for _, targetID := range (*msgBinTargeted).TargetCharIDs {
|
||||||
@@ -133,113 +147,66 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
s.server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message)
|
s.server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RAVI COMMANDS
|
// RAVI COMMANDS V2
|
||||||
if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists {
|
if strings.HasPrefix(chatMessage.Message, "!ravi") {
|
||||||
s.server.semaphoreLock.Lock()
|
if checkRaviSemaphore(s) {
|
||||||
getSemaphore := s.server.semaphore["hs_l0u3B51J9k3"]
|
s.server.raviente.Lock()
|
||||||
s.server.semaphoreLock.Unlock()
|
if !strings.HasPrefix(chatMessage.Message, "!ravi ") {
|
||||||
if _, exists := getSemaphore.reservedClientSlots[s.charID]; exists {
|
sendServerChatMessage(s, "No Raviente command specified!")
|
||||||
if strings.HasPrefix(chatMessage.Message, "!ravistart") {
|
} else {
|
||||||
row := s.server.db.QueryRow("SELECT raviposttime, ravistarted FROM raviregister WHERE refid = 12")
|
if strings.HasPrefix(chatMessage.Message, "!ravi start") {
|
||||||
var raviPosted, raviStarted uint32
|
if s.server.raviente.register.startTime == 0 {
|
||||||
err := row.Scan(&raviPosted, &raviStarted)
|
s.server.raviente.register.startTime = s.server.raviente.register.postTime
|
||||||
if err != nil {
|
sendServerChatMessage(s, "The Great Slaying will begin in a moment")
|
||||||
panic(err)
|
s.notifyall()
|
||||||
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 {
|
} else {
|
||||||
sendServerChatMessage(s, fmt.Sprintf("Setting Ravi damage multiplier to %d", num))
|
sendServerChatMessage(s, "The Great Slaying has already begun!")
|
||||||
s.server.db.Exec("UPDATE ravistate SET damagemultiplier = $1", num)
|
|
||||||
}
|
}
|
||||||
|
} else if strings.HasPrefix(chatMessage.Message, "!ravi sm") || strings.HasPrefix(chatMessage.Message, "!ravi setmultiplier") {
|
||||||
|
var num uint16
|
||||||
|
n, numerr := fmt.Sscanf(chatMessage.Message, "!ravi sm %d", &num)
|
||||||
|
if numerr != nil || n != 1 {
|
||||||
|
sendServerChatMessage(s, "Error in command. Format: !ravi sm n")
|
||||||
|
} else if s.server.raviente.state.damageMultiplier == 1 {
|
||||||
|
if num > 65535 {
|
||||||
|
sendServerChatMessage(s, "Raviente multiplier too high, defaulting to 20x")
|
||||||
|
s.server.raviente.state.damageMultiplier = 65535
|
||||||
|
} else {
|
||||||
|
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier set to %dx", num))
|
||||||
|
s.server.raviente.state.damageMultiplier = uint32(num)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is already set to %dx!", s.server.raviente.state.damageMultiplier))
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(chatMessage.Message, "!ravi cm") || strings.HasPrefix(chatMessage.Message, "!ravi checkmultiplier") {
|
||||||
|
sendServerChatMessage(s, fmt.Sprintf("Raviente multiplier is currently %dx", s.server.raviente.state.damageMultiplier))
|
||||||
|
} else if strings.HasPrefix(chatMessage.Message, "!ravi sr") || strings.HasPrefix(chatMessage.Message, "!ravi sendres") {
|
||||||
|
if s.server.raviente.state.stateData[28] > 0 {
|
||||||
|
sendServerChatMessage(s, "Sending resurrection support!")
|
||||||
|
s.server.raviente.state.stateData[28] = 0
|
||||||
|
} else {
|
||||||
|
sendServerChatMessage(s, "Resurrection support has not been requested!")
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(chatMessage.Message, "!ravi ss") || strings.HasPrefix(chatMessage.Message, "!ravi sendsed") {
|
||||||
|
sendServerChatMessage(s, "Sending sedation support if requested!")
|
||||||
|
// Total BerRavi HP
|
||||||
|
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
|
||||||
|
s.server.raviente.support.supportData[1] = HP
|
||||||
|
} else if strings.HasPrefix(chatMessage.Message, "!ravi rs") || strings.HasPrefix(chatMessage.Message, "!ravi reqsed") {
|
||||||
|
sendServerChatMessage(s, "Requesting sedation support!")
|
||||||
|
// Total BerRavi HP
|
||||||
|
HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4]
|
||||||
|
s.server.raviente.support.supportData[1] = HP + 12
|
||||||
} else {
|
} else {
|
||||||
sendServerChatMessage(s, fmt.Sprintf("Multiplier can only be set once, please restart Ravi to set again"))
|
sendServerChatMessage(s, "Raviente command not recognised!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(chatMessage.Message, "!checkmultiplier") {
|
} else {
|
||||||
var damageMultiplier uint32
|
sendServerChatMessage(s, "No one has joined the Great Slaying!")
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
s.server.raviente.Unlock()
|
||||||
}
|
}
|
||||||
// END OF RAVI COMMANDS
|
// END RAVI COMMANDS V2
|
||||||
|
|
||||||
if strings.HasPrefix(chatMessage.Message, "!tele ") {
|
if strings.HasPrefix(chatMessage.Message, "!tele ") {
|
||||||
var x, y int16
|
var x, y int16
|
||||||
|
|||||||
@@ -128,16 +128,5 @@ func (save *CharacterSaveData) updateStructWithSaveData() {
|
|||||||
|
|
||||||
func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfSexChanger)
|
pkt := p.(*mhfpacket.MsgMhfSexChanger)
|
||||||
if pkt.Gender == 0 {
|
|
||||||
_, err := s.server.db.Exec("UPDATE characters SET is_female=true WHERE id=$1", s.charID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update gender in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_, err := s.server.db.Exec("UPDATE characters SET is_female=false WHERE id=$1", s.charID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Fatal("Failed to update gender in db", zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/Andoryuuta/byteframe"
|
||||||
"github.com/Solenataris/Erupe/common/bfutil"
|
"github.com/Solenataris/Erupe/common/bfutil"
|
||||||
"github.com/Solenataris/Erupe/network/mhfpacket"
|
"github.com/Solenataris/Erupe/network/mhfpacket"
|
||||||
"github.com/Solenataris/Erupe/server/channelserver/compression/deltacomp"
|
"github.com/Solenataris/Erupe/server/channelserver/compression/deltacomp"
|
||||||
@@ -32,17 +33,16 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
s.logger.Fatal("Failed to decompress diff", zap.Error(err))
|
s.logger.Fatal("Failed to decompress diff", zap.Error(err))
|
||||||
}
|
}
|
||||||
// Perform diff.
|
// Perform diff.
|
||||||
characterSaveData.SetBaseSaveData(deltacomp.ApplyDataDiff(diff, characterSaveData.BaseSaveData()))
|
|
||||||
s.logger.Info("Diffing...")
|
s.logger.Info("Diffing...")
|
||||||
|
characterSaveData.SetBaseSaveData(deltacomp.ApplyDataDiff(diff, characterSaveData.BaseSaveData()))
|
||||||
} else {
|
} else {
|
||||||
// Regular blob update.
|
// Regular blob update.
|
||||||
saveData, err := nullcomp.Decompress(pkt.RawDataPayload)
|
saveData, err := nullcomp.Decompress(pkt.RawDataPayload)
|
||||||
|
|
||||||
characterSaveData.SetBaseSaveData(saveData)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Fatal("Failed to decompress savedata from packet", zap.Error(err))
|
s.logger.Fatal("Failed to decompress savedata from packet", zap.Error(err))
|
||||||
}
|
}
|
||||||
s.logger.Info("Updating save with blob")
|
s.logger.Info("Updating save with blob")
|
||||||
|
characterSaveData.SetBaseSaveData(saveData)
|
||||||
}
|
}
|
||||||
characterSaveData.IsNewCharacter = false
|
characterSaveData.IsNewCharacter = false
|
||||||
characterBaseSaveData := characterSaveData.BaseSaveData()
|
characterBaseSaveData := characterSaveData.BaseSaveData()
|
||||||
@@ -193,7 +193,10 @@ func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfSaveScenarioData)
|
pkt := p.(*mhfpacket.MsgMhfSaveScenarioData)
|
||||||
|
_, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE characters.id = $2", pkt.RawDataPayload, int(s.charID))
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Fatal("Failed to update scenario data in db", zap.Error(err))
|
||||||
|
}
|
||||||
// Do this ack manually because it uses a non-(0|1) error code
|
// Do this ack manually because it uses a non-(0|1) error code
|
||||||
s.QueueSendMHF(&mhfpacket.MsgSysAck{
|
s.QueueSendMHF(&mhfpacket.MsgSysAck{
|
||||||
AckHandle: pkt.AckHandle,
|
AckHandle: pkt.AckHandle,
|
||||||
@@ -205,7 +208,19 @@ func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfLoadScenarioData)
|
pkt := p.(*mhfpacket.MsgMhfLoadScenarioData)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
|
var scenarioData []byte
|
||||||
|
bf := byteframe.NewByteFrame()
|
||||||
|
err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE characters.id = $1", int(s.charID)).Scan(&scenarioData)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Fatal("Failed to get scenario data contents in db", zap.Error(err))
|
||||||
|
} else {
|
||||||
|
if len(scenarioData) == 0 {
|
||||||
|
bf.WriteUint32(0x00)
|
||||||
|
} else {
|
||||||
|
bf.WriteBytes(scenarioData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfGetPaperData(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetPaperData(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ type ItemDist struct {
|
|||||||
func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfEnumerateDistItem)
|
pkt := p.(*mhfpacket.MsgMhfEnumerateDistItem)
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
|
|
||||||
distCount := 0
|
distCount := 0
|
||||||
dists, err := s.server.db.Queryx(`
|
dists, err := s.server.db.Queryx(`
|
||||||
SELECT d.id, event_name, description, times_acceptable,
|
SELECT d.id, event_name, description, times_acceptable,
|
||||||
@@ -55,7 +54,6 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Error parsing item distribution data", zap.Error(err))
|
s.logger.Error("Error parsing item distribution data", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
bf.WriteUint32(distData.ID)
|
bf.WriteUint32(distData.ID)
|
||||||
bf.WriteUint32(distData.Deadline)
|
bf.WriteUint32(distData.Deadline)
|
||||||
bf.WriteUint32(0) // Unk
|
bf.WriteUint32(0) // Unk
|
||||||
@@ -119,18 +117,15 @@ func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfGetDistDescription(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetDistDescription(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetDistDescription)
|
pkt := p.(*mhfpacket.MsgMhfGetDistDescription)
|
||||||
|
var desc string
|
||||||
var itemDesc string
|
err := s.server.db.QueryRow("SELECT description FROM distribution WHERE id = $1", pkt.DistributionID).Scan(&desc)
|
||||||
err := s.server.db.QueryRow("SELECT description FROM distribution WHERE id = $1", pkt.DistributionID).Scan(&itemDesc)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Error parsing item distribution description", zap.Error(err))
|
s.logger.Error("Error parsing item distribution description", zap.Error(err))
|
||||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
description, _ := stringsupport.ConvertUTF8ToShiftJIS(itemDesc)
|
description, _ := stringsupport.ConvertUTF8ToShiftJIS(desc)
|
||||||
bf.WriteUint16(uint16(len(description)+1))
|
bf.WriteUint16(uint16(len(description)+1))
|
||||||
bf.WriteNullTerminatedBytes(description)
|
bf.WriteNullTerminatedBytes(description)
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Solenataris/Erupe/common/stringsupport"
|
|
||||||
"github.com/Solenataris/Erupe/network/binpacket"
|
"github.com/Solenataris/Erupe/network/binpacket"
|
||||||
"github.com/Solenataris/Erupe/network/mhfpacket"
|
"github.com/Solenataris/Erupe/network/mhfpacket"
|
||||||
"github.com/Andoryuuta/byteframe"
|
"github.com/Andoryuuta/byteframe"
|
||||||
@@ -19,9 +18,10 @@ type Mail struct {
|
|||||||
Body string `db:"body"`
|
Body string `db:"body"`
|
||||||
Read bool `db:"read"`
|
Read bool `db:"read"`
|
||||||
Deleted bool `db:"deleted"`
|
Deleted bool `db:"deleted"`
|
||||||
|
Locked bool `db:"locked"`
|
||||||
AttachedItemReceived bool `db:"attached_item_received"`
|
AttachedItemReceived bool `db:"attached_item_received"`
|
||||||
AttachedItemID *uint16 `db:"attached_item"`
|
AttachedItemID uint16 `db:"attached_item"`
|
||||||
AttachedItemAmount int16 `db:"attached_item_amount"`
|
AttachedItemAmount uint16 `db:"attached_item_amount"`
|
||||||
CreatedAt time.Time `db:"created_at"`
|
CreatedAt time.Time `db:"created_at"`
|
||||||
IsGuildInvite bool `db:"is_guild_invite"`
|
IsGuildInvite bool `db:"is_guild_invite"`
|
||||||
SenderName string `db:"sender_name"`
|
SenderName string `db:"sender_name"`
|
||||||
@@ -49,8 +49,8 @@ func (m *Mail) Send(s *Session, transaction *sql.Tx) error {
|
|||||||
zap.Uint32("recipientID", m.RecipientID),
|
zap.Uint32("recipientID", m.RecipientID),
|
||||||
zap.String("subject", m.Subject),
|
zap.String("subject", m.Subject),
|
||||||
zap.String("body", m.Body),
|
zap.String("body", m.Body),
|
||||||
zap.Uint16p("itemID", m.AttachedItemID),
|
zap.Uint16("itemID", m.AttachedItemID),
|
||||||
zap.Int16("itemAmount", m.AttachedItemAmount),
|
zap.Uint16("itemAmount", m.AttachedItemAmount),
|
||||||
zap.Bool("isGuildInvite", m.IsGuildInvite),
|
zap.Bool("isGuildInvite", m.IsGuildInvite),
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
@@ -110,6 +110,23 @@ func (m *Mail) MarkAcquired(s *Session) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Mail) MarkLocked(s *Session, locked bool) error {
|
||||||
|
_, err := s.server.db.Exec(`
|
||||||
|
UPDATE mail SET locked = $1 WHERE id = $2
|
||||||
|
`, locked, m.ID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error(
|
||||||
|
"failed to mark mail as locked",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Int("mailID", m.ID),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
|
func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
|
||||||
rows, err := s.server.db.Queryx(`
|
rows, err := s.server.db.Queryx(`
|
||||||
SELECT
|
SELECT
|
||||||
@@ -124,6 +141,7 @@ func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) {
|
|||||||
m.created_at,
|
m.created_at,
|
||||||
m.is_guild_invite,
|
m.is_guild_invite,
|
||||||
m.deleted,
|
m.deleted,
|
||||||
|
m.locked,
|
||||||
c.name as sender_name
|
c.name as sender_name
|
||||||
FROM mail m
|
FROM mail m
|
||||||
JOIN characters c ON c.id = m.sender_id
|
JOIN characters c ON c.id = m.sender_id
|
||||||
@@ -171,6 +189,7 @@ func GetMailByID(s *Session, ID int) (*Mail, error) {
|
|||||||
m.created_at,
|
m.created_at,
|
||||||
m.is_guild_invite,
|
m.is_guild_invite,
|
||||||
m.deleted,
|
m.deleted,
|
||||||
|
m.locked,
|
||||||
c.name as sender_name
|
c.name as sender_name
|
||||||
FROM mail m
|
FROM mail m
|
||||||
JOIN characters c ON c.id = m.sender_id
|
JOIN characters c ON c.id = m.sender_id
|
||||||
@@ -255,8 +274,9 @@ func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
_ = mail.MarkRead(s)
|
_ = mail.MarkRead(s)
|
||||||
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bodyBytes, _ := stringsupport.ConvertUTF8ToShiftJIS(mail.Body)
|
|
||||||
bf.WriteNullTerminatedBytes(bodyBytes)
|
body := s.clientContext.StrConv.MustEncode(mail.Body)
|
||||||
|
bf.WriteNullTerminatedBytes(body)
|
||||||
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
@@ -286,9 +306,10 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
s.mailList[accIndex] = m.ID
|
s.mailList[accIndex] = m.ID
|
||||||
s.mailAccIndex++
|
s.mailAccIndex++
|
||||||
|
|
||||||
itemAttached := m.AttachedItemID != nil
|
|
||||||
subjectBytes, _ := stringsupport.ConvertUTF8ToShiftJIS(m.Subject)
|
itemAttached := m.AttachedItemID != 0
|
||||||
senderNameBytes, _ := stringsupport.ConvertUTF8ToShiftJIS(m.SenderName)
|
subject := s.clientContext.StrConv.MustEncode(m.Subject)
|
||||||
|
sender := s.clientContext.StrConv.MustEncode(m.SenderName)
|
||||||
|
|
||||||
msg.WriteUint32(m.SenderID)
|
msg.WriteUint32(m.SenderID)
|
||||||
msg.WriteUint32(uint32(m.CreatedAt.Unix()))
|
msg.WriteUint32(uint32(m.CreatedAt.Unix()))
|
||||||
@@ -302,28 +323,34 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
flags |= 0x01
|
flags |= 0x01
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.Locked {
|
||||||
|
flags |= 0x02
|
||||||
|
}
|
||||||
|
|
||||||
|
// System message, hides ID
|
||||||
|
// flags |= 0x04
|
||||||
|
|
||||||
|
// Mitigate game crash
|
||||||
|
flags |= 0x08
|
||||||
if m.AttachedItemReceived {
|
if m.AttachedItemReceived {
|
||||||
flags |= 0x08
|
// flags |= 0x08
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.IsGuildInvite {
|
if m.IsGuildInvite {
|
||||||
// Guild Invite
|
|
||||||
flags |= 0x10
|
flags |= 0x10
|
||||||
|
|
||||||
// System message?
|
|
||||||
flags |= 0x04
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.WriteUint8(flags)
|
msg.WriteUint8(flags)
|
||||||
msg.WriteBool(itemAttached)
|
msg.WriteBool(itemAttached)
|
||||||
msg.WriteUint8(uint8(len(subjectBytes)+1))
|
msg.WriteUint8(uint8(len(subject)+1))
|
||||||
msg.WriteUint8(uint8(len(senderNameBytes)+1))
|
msg.WriteUint8(uint8(len(sender)+1))
|
||||||
msg.WriteNullTerminatedBytes(subjectBytes)
|
msg.WriteNullTerminatedBytes(subject)
|
||||||
msg.WriteNullTerminatedBytes(senderNameBytes)
|
msg.WriteNullTerminatedBytes(sender)
|
||||||
|
|
||||||
|
// TODO: The game will crash if it attempts to receive items
|
||||||
if itemAttached {
|
if itemAttached {
|
||||||
msg.WriteInt16(m.AttachedItemAmount)
|
msg.WriteUint16(m.AttachedItemAmount)
|
||||||
msg.WriteUint16(*m.AttachedItemID)
|
msg.WriteUint16(m.AttachedItemID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,6 +374,18 @@ func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
doAckSimpleFail(s, pkt.AckHandle, nil)
|
doAckSimpleFail(s, pkt.AckHandle, nil)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
case mhfpacket.OPERATE_MAIL_LOCK:
|
||||||
|
err = mail.MarkLocked(s, true)
|
||||||
|
if err != nil {
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, nil)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
case mhfpacket.OPERATE_MAIL_UNLOCK:
|
||||||
|
err = mail.MarkLocked(s, false)
|
||||||
|
if err != nil {
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, nil)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
case mhfpacket.OPERATE_MAIL_ACQUIRE_ITEM:
|
case mhfpacket.OPERATE_MAIL_ACQUIRE_ITEM:
|
||||||
err = mail.MarkAcquired(s)
|
err = mail.MarkAcquired(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,10 +2,22 @@ package channelserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/Solenataris/Erupe/network/mhfpacket"
|
"github.com/Solenataris/Erupe/network/mhfpacket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func removeSessionFromSemaphore(s *Session) {
|
||||||
|
s.server.semaphoreLock.Lock()
|
||||||
|
for _, semaphore := range s.server.semaphore {
|
||||||
|
if _, exists := semaphore.clients[s]; exists {
|
||||||
|
delete(semaphore.clients, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
releaseRaviSemaphore(s)
|
||||||
|
s.server.semaphoreLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgSysCreateSemaphore)
|
pkt := p.(*mhfpacket.MsgSysCreateSemaphore)
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x03, 0x00, 0x0d})
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x03, 0x00, 0x0d})
|
||||||
@@ -15,31 +27,53 @@ 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 {
|
||||||
s.server.semaphoreLock.Lock()
|
s.server.semaphoreLock.Lock()
|
||||||
for id := range s.server.semaphore {
|
for id := range s.server.semaphore {
|
||||||
switch sem {
|
switch sem {
|
||||||
case 917533:
|
case 917533:
|
||||||
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k3" {
|
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k3" {
|
||||||
delete(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots, s.charID)
|
delete(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots, s.charID)
|
||||||
delete(s.server.semaphore["hs_l0u3B51J9k3"].clients, s)
|
delete(s.server.semaphore["hs_l0u3B51J9k3"].clients, s)
|
||||||
|
} 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:
|
case 851997:
|
||||||
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k4" {
|
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k4" {
|
||||||
delete(s.server.semaphore["hs_l0u3B51J9k4"].reservedClientSlots, s.charID)
|
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:
|
case 786461:
|
||||||
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k5" {
|
if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k5" {
|
||||||
delete(s.server.semaphore["hs_l0u3B51J9k5"].reservedClientSlots, s.charID)
|
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:
|
default:
|
||||||
if len(s.server.semaphore[id].reservedClientSlots) != 0 {
|
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" {
|
if s.server.semaphore[id].id_semaphore != "hs_l0u3B51J9k3" &&
|
||||||
delete(s.server.semaphore[id].reservedClientSlots, s.charID)
|
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()
|
s.server.semaphoreLock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,11 +86,7 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
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 !gotNewStage {
|
||||||
s.server.semaphoreLock.Lock()
|
s.server.semaphoreLock.Lock()
|
||||||
if SemaphoreID == "hs_l0u3B51J9k1" ||
|
if strings.HasPrefix(SemaphoreID, "hs_l0u3B51") {
|
||||||
SemaphoreID == "hs_l0u3B51J9k2" ||
|
|
||||||
SemaphoreID == "hs_l0u3B51J9k3" ||
|
|
||||||
SemaphoreID == "hs_l0u3B51J9k4" ||
|
|
||||||
SemaphoreID == "hs_l0u3B51J9k5" {
|
|
||||||
s.server.semaphore[SemaphoreID] = NewSemaphore(SemaphoreID, 32)
|
s.server.semaphore[SemaphoreID] = NewSemaphore(SemaphoreID, 32)
|
||||||
} else {
|
} else {
|
||||||
s.server.semaphore[SemaphoreID] = NewSemaphore(SemaphoreID, 1)
|
s.server.semaphore[SemaphoreID] = NewSemaphore(SemaphoreID, 1)
|
||||||
@@ -68,24 +98,23 @@ 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 {
|
||||||
s.logger.Info("IS ALREADY EXIST !")
|
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x1D})
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x1D})
|
||||||
} else if uint16(len(newSemaphore.reservedClientSlots)) < newSemaphore.maxPlayers {
|
} else if uint16(len(newSemaphore.reservedClientSlots)) < newSemaphore.maxPlayers {
|
||||||
switch SemaphoreID {
|
switch SemaphoreID {
|
||||||
case "hs_l0u3B51J9k3":
|
case "hs_l0u3B51J9k3", "hs_l0u3B5129k3", "hs_l0u3B512Ak3":
|
||||||
newSemaphore.reservedClientSlots[s.charID] = nil
|
newSemaphore.reservedClientSlots[s.charID] = nil
|
||||||
newSemaphore.clients[s] = s.charID
|
newSemaphore.clients[s] = s.charID
|
||||||
s.Lock()
|
s.Lock()
|
||||||
s.semaphore = newSemaphore
|
s.semaphore = newSemaphore
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0E, 0x00, 0x1D})
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0E, 0x00, 0x1D})
|
||||||
case "hs_l0u3B51J9k4":
|
case "hs_l0u3B51J9k4", "hs_l0u3B5129k4", "hs_l0u3B512Ak4":
|
||||||
newSemaphore.reservedClientSlots[s.charID] = nil
|
newSemaphore.reservedClientSlots[s.charID] = nil
|
||||||
s.Lock()
|
s.Lock()
|
||||||
s.semaphore = newSemaphore
|
s.semaphore = newSemaphore
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0D, 0x00, 0x1D})
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0D, 0x00, 0x1D})
|
||||||
case "hs_l0u3B51J9k5":
|
case "hs_l0u3B51J9k5", "hs_l0u3B5129k5", "hs_l0u3B512Ak5":
|
||||||
newSemaphore.reservedClientSlots[s.charID] = nil
|
newSemaphore.reservedClientSlots[s.charID] = nil
|
||||||
s.Lock()
|
s.Lock()
|
||||||
s.semaphore = newSemaphore
|
s.semaphore = newSemaphore
|
||||||
@@ -109,29 +138,16 @@ 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)
|
||||||
if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists {
|
releaseRaviSemaphore(s)
|
||||||
reset := len(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots)
|
|
||||||
if reset == 0 {
|
|
||||||
s.server.db.Exec("CALL ravireset($1)", 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeSessionFromSemaphore(s *Session) {
|
|
||||||
|
|
||||||
s.server.semaphoreLock.Lock()
|
|
||||||
for id := range s.server.semaphore {
|
|
||||||
delete(s.server.semaphore[id].reservedClientSlots, s.charID)
|
|
||||||
if id == "hs_l0u3B51J9k3" {
|
|
||||||
delete(s.server.semaphore[id].clients, s)
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.server.semaphoreLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgSysCheckSemaphore)
|
pkt := p.(*mhfpacket.MsgSysCheckSemaphore)
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
resp := []byte{0x00, 0x00, 0x00, 0x00}
|
||||||
|
s.server.semaphoreLock.Lock()
|
||||||
|
if _, exists := s.server.semaphore[pkt.StageID]; exists {
|
||||||
|
resp = []byte{0x00, 0x00, 0x00, 0x01}
|
||||||
|
}
|
||||||
|
s.server.semaphoreLock.Unlock()
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, resp)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package channelserver
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/Solenataris/Erupe/network/mhfpacket"
|
"github.com/Solenataris/Erupe/network/mhfpacket"
|
||||||
"github.com/Andoryuuta/byteframe"
|
"github.com/Andoryuuta/byteframe"
|
||||||
@@ -11,13 +12,16 @@ import (
|
|||||||
|
|
||||||
func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgSysCreateStage)
|
pkt := p.(*mhfpacket.MsgSysCreateStage)
|
||||||
|
s.server.Lock()
|
||||||
s.server.stagesLock.Lock()
|
defer s.server.Unlock()
|
||||||
|
if _, exists := s.server.stages[pkt.StageID]; exists {
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||||
|
} else {
|
||||||
stage := NewStage(pkt.StageID)
|
stage := NewStage(pkt.StageID)
|
||||||
stage.maxPlayers = uint16(pkt.PlayerCount)
|
stage.maxPlayers = uint16(pkt.PlayerCount)
|
||||||
s.server.stages[stage.id] = stage
|
s.server.stages[stage.id] = stage
|
||||||
s.server.stagesLock.Unlock()
|
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {}
|
func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {}
|
||||||
@@ -64,58 +68,65 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
|||||||
// Notify existing stage clients that this new client has entered.
|
// Notify existing stage clients that this new client has entered.
|
||||||
s.logger.Info("Sending MsgSysInsertUser")
|
s.logger.Info("Sending MsgSysInsertUser")
|
||||||
if s.stage != nil { // avoids lock up when using bed for dream quests
|
if s.stage != nil { // avoids lock up when using bed for dream quests
|
||||||
s.stage.BroadcastMHF(&mhfpacket.MsgSysInsertUser{
|
// Add character to everyone elses stage
|
||||||
|
s.stage.BroadcastMHF(&mhfpacket.MsgSysInsertUser {
|
||||||
CharID: s.charID,
|
CharID: s.charID,
|
||||||
}, s)
|
}, s)
|
||||||
|
|
||||||
// It seems to be acceptable to recast all MSG_SYS_SET_USER_BINARY messages so far,
|
// Update others binary of your session
|
||||||
// players are still notified when a new player has joined the stage.
|
s.server.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary {
|
||||||
// These extra messages may not be needed
|
CharID: s.charID,
|
||||||
//s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{
|
BinaryType: 1,
|
||||||
// CharID: s.charID,
|
}, s)
|
||||||
// BinaryType: 1,
|
s.server.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary {
|
||||||
//}, s)
|
CharID: s.charID,
|
||||||
//s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{
|
BinaryType: 2,
|
||||||
// CharID: s.charID,
|
}, s)
|
||||||
// BinaryType: 2,
|
s.server.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary {
|
||||||
//}, s)
|
CharID: s.charID,
|
||||||
//s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{
|
BinaryType: 3,
|
||||||
// CharID: s.charID,
|
}, s)
|
||||||
// BinaryType: 3,
|
|
||||||
//}, s)
|
|
||||||
|
|
||||||
//Notify the entree client about all of the existing clients in the stage.
|
// Notify the entree client about all of the existing clients in the stage.
|
||||||
s.logger.Info("Notifying entree about existing stage clients")
|
s.logger.Info("Notifying entree about existing stage clients")
|
||||||
s.stage.RLock()
|
s.stage.RLock()
|
||||||
clientNotif := byteframe.NewByteFrame()
|
clientNotif := byteframe.NewByteFrame()
|
||||||
|
|
||||||
|
// Get other players in the stage
|
||||||
for session := range s.stage.clients {
|
for session := range s.stage.clients {
|
||||||
var cur mhfpacket.MHFPacket
|
var cur mhfpacket.MHFPacket
|
||||||
cur = &mhfpacket.MsgSysInsertUser{
|
cur = &mhfpacket.MsgSysInsertUser{
|
||||||
CharID: session.charID,
|
CharID: session.charID,
|
||||||
}
|
}
|
||||||
clientNotif.WriteUint16(uint16(cur.Opcode()))
|
clientNotif.WriteUint16(uint16(cur.Opcode()))
|
||||||
cur.Build(clientNotif, session.clientContext)
|
cur.Build(clientNotif, session.clientContext)
|
||||||
|
}
|
||||||
|
|
||||||
cur = &mhfpacket.MsgSysNotifyUserBinary{
|
// Get every players binary
|
||||||
CharID: session.charID,
|
for session := range s.server.sessions {
|
||||||
BinaryType: 1,
|
var cur mhfpacket.MHFPacket
|
||||||
}
|
session := s.server.sessions[session]
|
||||||
clientNotif.WriteUint16(uint16(cur.Opcode()))
|
|
||||||
cur.Build(clientNotif, session.clientContext)
|
|
||||||
|
|
||||||
cur = &mhfpacket.MsgSysNotifyUserBinary{
|
cur = &mhfpacket.MsgSysNotifyUserBinary{
|
||||||
CharID: session.charID,
|
CharID: session.charID,
|
||||||
BinaryType: 2,
|
BinaryType: 1,
|
||||||
}
|
}
|
||||||
clientNotif.WriteUint16(uint16(cur.Opcode()))
|
clientNotif.WriteUint16(uint16(cur.Opcode()))
|
||||||
cur.Build(clientNotif, session.clientContext)
|
cur.Build(clientNotif, session.clientContext)
|
||||||
|
|
||||||
cur = &mhfpacket.MsgSysNotifyUserBinary{
|
cur = &mhfpacket.MsgSysNotifyUserBinary{
|
||||||
CharID: session.charID,
|
CharID: session.charID,
|
||||||
BinaryType: 3,
|
BinaryType: 2,
|
||||||
}
|
}
|
||||||
clientNotif.WriteUint16(uint16(cur.Opcode()))
|
clientNotif.WriteUint16(uint16(cur.Opcode()))
|
||||||
cur.Build(clientNotif, session.clientContext)
|
cur.Build(clientNotif, session.clientContext)
|
||||||
|
|
||||||
|
cur = &mhfpacket.MsgSysNotifyUserBinary{
|
||||||
|
CharID: session.charID,
|
||||||
|
BinaryType: 3,
|
||||||
|
}
|
||||||
|
clientNotif.WriteUint16(uint16(cur.Opcode()))
|
||||||
|
cur.Build(clientNotif, session.clientContext)
|
||||||
}
|
}
|
||||||
s.stage.RUnlock()
|
s.stage.RUnlock()
|
||||||
clientNotif.WriteUint16(0x0010) // End it.
|
clientNotif.WriteUint16(0x0010) // End it.
|
||||||
@@ -143,6 +154,18 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeEmptyStages(s *Session) {
|
||||||
|
s.server.Lock()
|
||||||
|
for sid, stage := range s.server.stages {
|
||||||
|
if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 {
|
||||||
|
if strings.HasPrefix(sid, "sl1Qs") || strings.HasPrefix(sid, "sl2Qs") || strings.HasPrefix(sid, "sl3Qs") {
|
||||||
|
delete(s.server.stages, sid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.server.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
func removeSessionFromStage(s *Session) {
|
func removeSessionFromStage(s *Session) {
|
||||||
s.stage.Lock()
|
s.stage.Lock()
|
||||||
defer s.stage.Unlock()
|
defer s.stage.Unlock()
|
||||||
@@ -151,6 +174,15 @@ func removeSessionFromStage(s *Session) {
|
|||||||
delete(s.stage.clients, s)
|
delete(s.stage.clients, s)
|
||||||
delete(s.stage.reservedClientSlots, s.charID)
|
delete(s.stage.reservedClientSlots, s.charID)
|
||||||
|
|
||||||
|
// Remove client from all reservations
|
||||||
|
s.server.Lock()
|
||||||
|
for _, stage := range s.server.stages {
|
||||||
|
if _, exists := stage.reservedClientSlots[s.charID]; exists {
|
||||||
|
delete(stage.reservedClientSlots, s.charID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.server.Unlock()
|
||||||
|
|
||||||
// Delete old stage objects owned by the client.
|
// Delete old stage objects owned by the client.
|
||||||
s.logger.Info("Sending MsgSysDeleteObject to old stage clients")
|
s.logger.Info("Sending MsgSysDeleteObject to old stage clients")
|
||||||
for objID, stageObject := range s.stage.objects {
|
for objID, stageObject := range s.stage.objects {
|
||||||
@@ -163,14 +195,16 @@ func removeSessionFromStage(s *Session) {
|
|||||||
// Actually delete it form the objects map.
|
// Actually delete it form the objects map.
|
||||||
delete(s.stage.objects, objID)
|
delete(s.stage.objects, objID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for objListID, stageObjectList := range s.stage.objectList {
|
for objListID, stageObjectList := range s.stage.objectList {
|
||||||
if stageObjectList.charid == s.charID {
|
if stageObjectList.charid == s.charID {
|
||||||
//Added to prevent duplicates from flooding ObjectMap and causing server hangs
|
//Added to prevent duplicates from flooding ObjectMap and causing server hangs
|
||||||
s.stage.objectList[objListID].status=false
|
s.stage.objectList[objListID].status=false
|
||||||
s.stage.objectList[objListID].charid=0
|
s.stage.objectList[objListID].charid=0
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEmptyStages(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -252,7 +286,9 @@ func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
s.server.stagesLock.Unlock()
|
s.server.stagesLock.Unlock()
|
||||||
|
|
||||||
if !gotStage {
|
if !gotStage {
|
||||||
s.logger.Fatal("Failed to get stage", zap.String("StageID", stageID))
|
s.logger.Error("Failed to get stage", zap.String("StageID", stageID))
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to reserve a slot, fail if full.
|
// Try to reserve a slot, fail if full.
|
||||||
@@ -427,16 +463,18 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
// Build the response
|
// Build the response
|
||||||
resp := byteframe.NewByteFrame()
|
resp := byteframe.NewByteFrame()
|
||||||
resp.WriteUint16(uint16(len(s.server.stages)))
|
bf := byteframe.NewByteFrame()
|
||||||
|
var joinable int
|
||||||
for sid, stage := range s.server.stages {
|
for sid, stage := range s.server.stages {
|
||||||
stage.RLock()
|
stage.RLock()
|
||||||
defer stage.RUnlock()
|
defer stage.RUnlock()
|
||||||
if len(stage.reservedClientSlots)+len(stage.clients) == 0 {
|
if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
joinable++
|
||||||
|
|
||||||
resp.WriteUint16(uint16(len(stage.reservedClientSlots))) // Current players.
|
resp.WriteUint16(uint16(len(stage.reservedClientSlots))) // Reserved players.
|
||||||
resp.WriteUint16(0) // Unknown value
|
resp.WriteUint16(0) // Unknown value
|
||||||
|
|
||||||
var hasDeparted uint16
|
var hasDeparted uint16
|
||||||
if stage.hasDeparted {
|
if stage.hasDeparted {
|
||||||
@@ -448,6 +486,8 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
resp.WriteUint8(uint8(len(sid)))
|
resp.WriteUint8(uint8(len(sid)))
|
||||||
resp.WriteBytes([]byte(sid))
|
resp.WriteBytes([]byte(sid))
|
||||||
}
|
}
|
||||||
|
bf.WriteUint16(uint16(joinable))
|
||||||
|
bf.WriteBytes(resp.Data())
|
||||||
|
|
||||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,11 +248,16 @@ function switchPrompt() {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
addLog('Error parsing character info XML: '+e, 'error');
|
addLog('Error parsing character info XML: '+e, 'error');
|
||||||
|
switchPrompt();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
let uid = localStorage.getItem('uid');
|
let uid = localStorage.getItem('uid');
|
||||||
if (uid != 'null' && uids.indexOf(uid) >= 0) {
|
if (uid != 'null' && uids.indexOf(uid) >= 0) {
|
||||||
setUidIndex(uids.indexOf(uid));
|
setUidIndex(uids.indexOf(uid));
|
||||||
}
|
} else {
|
||||||
|
addLog('Error setting character ID: '+e, 'error');
|
||||||
|
switchPrompt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user