mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-04-07 16:32:31 +02:00
Merge branch 'main' of https://github.com/ZeruLight/Erupe into feature/enum-event
This commit is contained in:
@@ -88,7 +88,7 @@ func updateRights(s *Session) {
|
||||
Rights: s.courses,
|
||||
UnkSize: 0,
|
||||
}
|
||||
s.QueueSendMHF(update)
|
||||
s.QueueSendMHFNonBlocking(update)
|
||||
}
|
||||
|
||||
func handleMsgHead(s *Session, p mhfpacket.MHFPacket) {}
|
||||
@@ -143,7 +143,6 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
|
||||
s.token = pkt.LoginTokenString
|
||||
s.Unlock()
|
||||
|
||||
updateRights(s)
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Unix())) // Unix timestamp
|
||||
|
||||
@@ -193,7 +192,7 @@ func logoutPlayer(s *Session) {
|
||||
for _, sess := range s.server.sessions {
|
||||
for rSlot := range stage.reservedClientSlots {
|
||||
if sess.charID == rSlot && sess.stage != nil && sess.stage.id[3:5] != "Qs" {
|
||||
sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
|
||||
sess.QueueSendMHFNonBlocking(&mhfpacket.MsgSysStageDestruct{})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1051,32 +1050,58 @@ func handleMsgMhfUpdateEtcPoint(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfStampcardStamp)
|
||||
|
||||
rewards := []struct {
|
||||
HR uint16
|
||||
Item1 uint16
|
||||
Quantity1 uint16
|
||||
Item2 uint16
|
||||
Quantity2 uint16
|
||||
}{
|
||||
{0, 6164, 1, 6164, 2},
|
||||
{50, 6164, 2, 6164, 3},
|
||||
{100, 6164, 3, 5392, 1},
|
||||
{300, 5392, 1, 5392, 3},
|
||||
{999, 5392, 1, 5392, 4},
|
||||
}
|
||||
if _config.ErupeConfig.RealClientMode <= _config.Z1 {
|
||||
for _, reward := range rewards {
|
||||
if pkt.HR >= reward.HR {
|
||||
pkt.Item1 = reward.Item1
|
||||
pkt.Quantity1 = reward.Quantity1
|
||||
pkt.Item2 = reward.Item2
|
||||
pkt.Quantity2 = reward.Quantity2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(pkt.HR)
|
||||
var stamps uint16
|
||||
_ = s.server.db.QueryRow(`SELECT stampcard FROM characters WHERE id = $1`, s.charID).Scan(&stamps)
|
||||
if _config.ErupeConfig.RealClientMode >= _config.G1 {
|
||||
bf.WriteUint16(pkt.GR)
|
||||
}
|
||||
var stamps, rewardTier, rewardUnk uint16
|
||||
reward := mhfitem.MHFItemStack{Item: mhfitem.MHFItem{}}
|
||||
s.server.db.QueryRow(`UPDATE characters SET stampcard = stampcard + $1 WHERE id = $2 RETURNING stampcard`, pkt.Stamps, s.charID).Scan(&stamps)
|
||||
bf.WriteUint16(stamps - pkt.Stamps)
|
||||
bf.WriteUint16(stamps)
|
||||
stamps += pkt.Stamps
|
||||
bf.WriteUint16(stamps)
|
||||
s.server.db.Exec(`UPDATE characters SET stampcard = $1 WHERE id = $2`, stamps, s.charID)
|
||||
if stamps%30 == 0 {
|
||||
bf.WriteUint16(2)
|
||||
bf.WriteUint16(pkt.Reward2)
|
||||
bf.WriteUint16(pkt.Item2)
|
||||
bf.WriteUint16(pkt.Quantity2)
|
||||
addWarehouseItem(s, mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: pkt.Item2}, Quantity: pkt.Quantity2})
|
||||
} else if stamps%15 == 0 {
|
||||
bf.WriteUint16(1)
|
||||
bf.WriteUint16(pkt.Reward1)
|
||||
bf.WriteUint16(pkt.Item1)
|
||||
bf.WriteUint16(pkt.Quantity1)
|
||||
addWarehouseItem(s, mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: pkt.Item1}, Quantity: pkt.Quantity1})
|
||||
} else {
|
||||
bf.WriteBytes(make([]byte, 8))
|
||||
|
||||
if stamps/30 > (stamps-pkt.Stamps)/30 {
|
||||
rewardTier = 2
|
||||
rewardUnk = pkt.Reward2
|
||||
reward = mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: pkt.Item2}, Quantity: pkt.Quantity2}
|
||||
addWarehouseItem(s, reward)
|
||||
} else if stamps/15 > (stamps-pkt.Stamps)/15 {
|
||||
rewardTier = 1
|
||||
rewardUnk = pkt.Reward1
|
||||
reward = mhfitem.MHFItemStack{Item: mhfitem.MHFItem{ItemID: pkt.Item1}, Quantity: pkt.Quantity1}
|
||||
addWarehouseItem(s, reward)
|
||||
}
|
||||
|
||||
bf.WriteUint16(rewardTier)
|
||||
bf.WriteUint16(rewardUnk)
|
||||
bf.WriteUint16(reward.Item.ItemID)
|
||||
bf.WriteUint16(reward.Quantity)
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/common/mhfcourse"
|
||||
ps "erupe-ce/common/pascalstring"
|
||||
_config "erupe-ce/config"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
@@ -92,10 +93,11 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
|
||||
if mhfcourse.CourseExists(30, s.courses) {
|
||||
cafeTime = uint32(TimeAdjusted().Unix()) - uint32(s.sessionStart) + cafeTime
|
||||
}
|
||||
bf.WriteUint32(cafeTime) // Total cafe time
|
||||
bf.WriteUint16(0)
|
||||
ps.Uint16(bf, fmt.Sprintf(s.server.i18n.cafe.reset, int(cafeReset.Month()), cafeReset.Day()), true)
|
||||
|
||||
bf.WriteUint32(cafeTime)
|
||||
if _config.ErupeConfig.RealClientMode >= _config.ZZ {
|
||||
bf.WriteUint16(0)
|
||||
ps.Uint16(bf, fmt.Sprintf(s.server.i18n.cafe.reset, int(cafeReset.Month()), cafeReset.Day()), true)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
@@ -164,7 +166,7 @@ func handleMsgMhfReceiveCafeDurationBonus(s *Session, p mhfpacket.MHFPacket) {
|
||||
FROM characters ch
|
||||
WHERE ch.id = $1
|
||||
) >= time_req`, s.charID, TimeAdjusted().Unix()-s.sessionStart)
|
||||
if err != nil {
|
||||
if err != nil || !mhfcourse.CourseExists(30, s.courses) {
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
} else {
|
||||
for rows.Next() {
|
||||
|
||||
@@ -82,7 +82,7 @@ func sendServerChatMessage(s *Session, message string) {
|
||||
RawDataPayload: bf.Data(),
|
||||
}
|
||||
|
||||
s.QueueSendMHF(castedBin)
|
||||
s.QueueSendMHFNonBlocking(castedBin)
|
||||
}
|
||||
|
||||
func parseChatCommand(s *Session, command string) {
|
||||
@@ -198,7 +198,7 @@ func parseChatCommand(s *Session, command string) {
|
||||
temp.Build(deleteNotif, s.clientContext)
|
||||
}
|
||||
deleteNotif.WriteUint16(uint16(network.MSG_SYS_END))
|
||||
s.QueueSend(deleteNotif.Data())
|
||||
s.QueueSendNonBlocking(deleteNotif.Data())
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
reloadNotif := byteframe.NewByteFrame()
|
||||
for _, session := range s.server.sessions {
|
||||
@@ -233,7 +233,7 @@ func parseChatCommand(s *Session, command string) {
|
||||
temp.Build(reloadNotif, s.clientContext)
|
||||
}
|
||||
reloadNotif.WriteUint16(uint16(network.MSG_SYS_END))
|
||||
s.QueueSend(reloadNotif.Data())
|
||||
s.QueueSendNonBlocking(reloadNotif.Data())
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Reload"])
|
||||
}
|
||||
@@ -381,7 +381,7 @@ func parseChatCommand(s *Session, command string) {
|
||||
payload.WriteInt16(int16(x)) // X
|
||||
payload.WriteInt16(int16(y)) // Y
|
||||
payloadBytes := payload.Data()
|
||||
s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{
|
||||
s.QueueSendMHFNonBlocking(&mhfpacket.MsgSysCastedBinary{
|
||||
CharID: s.charID,
|
||||
MessageType: BinaryMessageTypeState,
|
||||
RawDataPayload: payloadBytes,
|
||||
@@ -407,6 +407,13 @@ func parseChatCommand(s *Session, command string) {
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Discord"])
|
||||
}
|
||||
case commands["Playtime"].Prefix:
|
||||
if commands["Playtime"].Enabled || s.isOp() {
|
||||
playtime := s.playtime + uint32(time.Now().Sub(s.playtimeTime).Seconds())
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.server.i18n.commands.playtime, playtime/60/60, playtime/60%60, playtime%60))
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Playtime"])
|
||||
}
|
||||
case commands["Help"].Prefix:
|
||||
if commands["Help"].Enabled || s.isOp() {
|
||||
for _, command := range commands {
|
||||
@@ -532,7 +539,7 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
char := s.server.FindSessionByCharID(targetID)
|
||||
|
||||
if char != nil {
|
||||
char.QueueSendMHF(resp)
|
||||
char.QueueSendMHFNonBlocking(resp)
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -23,6 +23,7 @@ const (
|
||||
pGalleryData // +1748
|
||||
pToreData // +240
|
||||
pGardenData // +68
|
||||
pPlaytime // +4
|
||||
pWeaponType // +1
|
||||
pWeaponID // +2
|
||||
pHR // +2
|
||||
@@ -45,6 +46,7 @@ type CharacterSaveData struct {
|
||||
GalleryData []byte
|
||||
ToreData []byte
|
||||
GardenData []byte
|
||||
Playtime uint32
|
||||
WeaponType uint8
|
||||
WeaponID uint16
|
||||
HR uint16
|
||||
@@ -59,6 +61,7 @@ func getPointers() map[SavePointer]int {
|
||||
pointers := map[SavePointer]int{pGender: 81, lBookshelfData: 5576}
|
||||
switch _config.ErupeConfig.RealClientMode {
|
||||
case _config.ZZ:
|
||||
pointers[pPlaytime] = 128356
|
||||
pointers[pWeaponID] = 128522
|
||||
pointers[pWeaponType] = 128789
|
||||
pointers[pHouseTier] = 129900
|
||||
@@ -74,6 +77,7 @@ func getPointers() map[SavePointer]int {
|
||||
case _config.Z2, _config.Z1, _config.G101, _config.G10, _config.G91, _config.G9, _config.G81, _config.G8,
|
||||
_config.G7, _config.G61, _config.G6, _config.G52, _config.G51, _config.G5, _config.GG, _config.G32, _config.G31,
|
||||
_config.G3, _config.G2, _config.G1:
|
||||
pointers[pPlaytime] = 92356
|
||||
pointers[pWeaponID] = 92522
|
||||
pointers[pWeaponType] = 92789
|
||||
pointers[pHouseTier] = 93900
|
||||
@@ -87,6 +91,7 @@ func getPointers() map[SavePointer]int {
|
||||
pointers[pRP] = 106614
|
||||
pointers[pKQF] = 110720
|
||||
case _config.F5, _config.F4:
|
||||
pointers[pPlaytime] = 60356
|
||||
pointers[pWeaponID] = 60522
|
||||
pointers[pWeaponType] = 60789
|
||||
pointers[pHouseTier] = 61900
|
||||
@@ -98,6 +103,7 @@ func getPointers() map[SavePointer]int {
|
||||
pointers[pGardenData] = 74424
|
||||
pointers[pRP] = 74614
|
||||
case _config.S6:
|
||||
pointers[pPlaytime] = 12356
|
||||
pointers[pWeaponID] = 12522
|
||||
pointers[pWeaponType] = 12789
|
||||
pointers[pHouseTier] = 13900
|
||||
@@ -231,6 +237,7 @@ func (save *CharacterSaveData) updateStructWithSaveData() {
|
||||
save.GalleryData = save.decompSave[save.Pointers[pGalleryData] : save.Pointers[pGalleryData]+1748]
|
||||
save.ToreData = save.decompSave[save.Pointers[pToreData] : save.Pointers[pToreData]+240]
|
||||
save.GardenData = save.decompSave[save.Pointers[pGardenData] : save.Pointers[pGardenData]+68]
|
||||
save.Playtime = binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pPlaytime] : save.Pointers[pPlaytime]+4])
|
||||
save.WeaponType = save.decompSave[save.Pointers[pWeaponType]]
|
||||
save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pWeaponID] : save.Pointers[pWeaponID]+2])
|
||||
save.HR = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pHR] : save.Pointers[pHR]+2])
|
||||
|
||||
@@ -54,6 +54,9 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
characterSaveData.updateStructWithSaveData()
|
||||
|
||||
s.playtime = characterSaveData.Playtime
|
||||
s.playtimeTime = time.Now()
|
||||
|
||||
// Bypass name-checker if new
|
||||
if characterSaveData.IsNewCharacter == true {
|
||||
s.Name = characterSaveData.Name
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
type Distribution struct {
|
||||
ID uint32 `db:"id"`
|
||||
Deadline time.Time `db:"deadline"`
|
||||
Rights uint32 `db:"rights"`
|
||||
TimesAcceptable uint16 `db:"times_acceptable"`
|
||||
TimesAccepted uint16 `db:"times_accepted"`
|
||||
MinHR int16 `db:"min_hr"`
|
||||
@@ -23,7 +24,7 @@ type Distribution struct {
|
||||
MaxGR int16 `db:"max_gr"`
|
||||
EventName string `db:"event_name"`
|
||||
Description string `db:"description"`
|
||||
Data []byte `db:"data"`
|
||||
Selection bool `db:"selection"`
|
||||
}
|
||||
|
||||
func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
||||
@@ -32,7 +33,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
||||
var itemDists []Distribution
|
||||
bf := byteframe.NewByteFrame()
|
||||
rows, err := s.server.db.Queryx(`
|
||||
SELECT d.id, event_name, description, times_acceptable,
|
||||
SELECT d.id, event_name, description, COALESCE(rights, 0) AS rights, COALESCE(selection, false) AS selection, times_acceptable,
|
||||
COALESCE(min_hr, -1) AS min_hr, COALESCE(max_hr, -1) AS max_hr,
|
||||
COALESCE(min_sr, -1) AS min_sr, COALESCE(max_sr, -1) AS max_sr,
|
||||
COALESCE(min_gr, -1) AS min_gr, COALESCE(max_gr, -1) AS max_gr,
|
||||
@@ -60,7 +61,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
||||
for _, dist := range itemDists {
|
||||
bf.WriteUint32(dist.ID)
|
||||
bf.WriteUint32(uint32(dist.Deadline.Unix()))
|
||||
bf.WriteUint32(0) // Unk
|
||||
bf.WriteUint32(dist.Rights)
|
||||
bf.WriteUint16(dist.TimesAcceptable)
|
||||
bf.WriteUint16(dist.TimesAccepted)
|
||||
if _config.ErupeConfig.RealClientMode >= _config.G9 {
|
||||
@@ -79,7 +80,11 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint16(0) // Unk
|
||||
}
|
||||
if _config.ErupeConfig.RealClientMode >= _config.G8 {
|
||||
bf.WriteUint8(0) // Unk
|
||||
if dist.Selection {
|
||||
bf.WriteUint8(2) // Selection
|
||||
} else {
|
||||
bf.WriteUint8(0)
|
||||
}
|
||||
}
|
||||
if _config.ErupeConfig.RealClientMode >= _config.G7 {
|
||||
bf.WriteUint16(0) // Unk
|
||||
|
||||
@@ -292,7 +292,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
|
||||
} else {
|
||||
bf.WriteUint32(s.server.erupeConfig.GameplayOptions.MaximumFP)
|
||||
}
|
||||
bf.WriteUint16(500)
|
||||
bf.WriteUint16(100) // Reward multiplier (%)
|
||||
|
||||
var temp uint32
|
||||
bf.WriteUint16(4)
|
||||
|
||||
@@ -971,14 +971,21 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint8(0)
|
||||
bf.WriteUint8(0)
|
||||
|
||||
bf.WriteBool(!guild.Recruiting)
|
||||
flags := uint8(0)
|
||||
if !guild.Recruiting {
|
||||
flags |= 0x01
|
||||
}
|
||||
//if guild.Suspended {
|
||||
// flags |= 0x02
|
||||
//}
|
||||
bf.WriteUint8(flags)
|
||||
|
||||
if characterGuildData == nil || characterGuildData.IsApplicant {
|
||||
bf.WriteUint16(0x00)
|
||||
bf.WriteUint16(0)
|
||||
} else if guild.LeaderCharID == s.charID {
|
||||
bf.WriteUint16(0x01)
|
||||
bf.WriteUint16(1)
|
||||
} else {
|
||||
bf.WriteUint16(0x02)
|
||||
bf.WriteUint16(2)
|
||||
}
|
||||
|
||||
bf.WriteUint32(uint32(guild.CreatedAt.Unix()))
|
||||
@@ -1098,20 +1105,25 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint32(applicant.CharID)
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteUint16(applicant.HR)
|
||||
bf.WriteUint16(applicant.GR)
|
||||
if s.server.erupeConfig.RealClientMode >= _config.G10 {
|
||||
bf.WriteUint16(applicant.GR)
|
||||
}
|
||||
ps.Uint8(bf, applicant.Name, true)
|
||||
}
|
||||
}
|
||||
|
||||
type UnkGuildInfo struct {
|
||||
Unk0 uint8
|
||||
type Activity struct {
|
||||
Pass uint8
|
||||
Unk1 uint8
|
||||
Unk2 uint8
|
||||
}
|
||||
unkGuildInfo := []UnkGuildInfo{}
|
||||
bf.WriteUint8(uint8(len(unkGuildInfo)))
|
||||
for _, info := range unkGuildInfo {
|
||||
bf.WriteUint8(info.Unk0)
|
||||
activity := []Activity{
|
||||
// 1,0,0 = ok
|
||||
// 0,0,0 = ng
|
||||
}
|
||||
bf.WriteUint8(uint8(len(activity)))
|
||||
for _, info := range activity {
|
||||
bf.WriteUint8(info.Pass)
|
||||
bf.WriteUint8(info.Unk1)
|
||||
bf.WriteUint8(info.Unk2)
|
||||
}
|
||||
@@ -1159,7 +1171,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
} else {
|
||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 5))
|
||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1526,7 +1538,7 @@ func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfGetGuildManageRight)
|
||||
|
||||
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||
if guild == nil && s.prevGuildID != 0 {
|
||||
if guild == nil || s.prevGuildID != 0 {
|
||||
guild, err = GetGuildInfoByID(s, s.prevGuildID)
|
||||
s.prevGuildID = 0
|
||||
if guild == nil || err != nil {
|
||||
|
||||
@@ -61,35 +61,41 @@ func (gm *GuildMember) Save(s *Session) error {
|
||||
}
|
||||
|
||||
const guildMembersSelectSQL = `
|
||||
SELECT * FROM (
|
||||
SELECT
|
||||
g.id AS guild_id,
|
||||
joined_at,
|
||||
COALESCE((SELECT SUM(souls) FROM festa_submissions fs WHERE fs.character_id=c.id), 0) AS souls,
|
||||
COALESCE(rp_today, 0) AS rp_today,
|
||||
COALESCE(rp_yesterday, 0) AS rp_yesterday,
|
||||
c.name,
|
||||
c.id AS character_id,
|
||||
COALESCE(order_index, 0) AS order_index,
|
||||
c.last_login,
|
||||
COALESCE(recruiter, false) AS recruiter,
|
||||
COALESCE(avoid_leadership, false) AS avoid_leadership,
|
||||
c.hr,
|
||||
c.gr,
|
||||
c.weapon_id,
|
||||
c.weapon_type,
|
||||
EXISTS(SELECT 1 FROM guild_applications ga WHERE ga.character_id=c.id AND application_type='applied') AS is_applicant,
|
||||
CASE WHEN g.leader_id = c.id THEN true ELSE false END AS is_leader
|
||||
SELECT
|
||||
COALESCE(g.id, 0) AS guild_id,
|
||||
joined_at,
|
||||
COALESCE((SELECT SUM(souls) FROM festa_submissions fs WHERE fs.character_id=c.id), 0) AS souls,
|
||||
COALESCE(rp_today, 0) AS rp_today,
|
||||
COALESCE(rp_yesterday, 0) AS rp_yesterday,
|
||||
c.name,
|
||||
c.id AS character_id,
|
||||
COALESCE(order_index, 0) AS order_index,
|
||||
c.last_login,
|
||||
COALESCE(recruiter, false) AS recruiter,
|
||||
COALESCE(avoid_leadership, false) AS avoid_leadership,
|
||||
c.hr,
|
||||
c.gr,
|
||||
c.weapon_id,
|
||||
c.weapon_type,
|
||||
CASE WHEN g.leader_id = c.id THEN true ELSE false END AS is_leader,
|
||||
character.is_applicant
|
||||
FROM (
|
||||
SELECT character_id, true as is_applicant, guild_id
|
||||
FROM guild_applications ga
|
||||
WHERE ga.application_type = 'applied'
|
||||
UNION
|
||||
SELECT character_id, false as is_applicant, guild_id
|
||||
FROM guild_characters gc
|
||||
LEFT JOIN characters c ON c.id = gc.character_id
|
||||
LEFT JOIN guilds g ON g.id = gc.guild_id
|
||||
) AS subquery
|
||||
) character
|
||||
JOIN characters c on character.character_id = c.id
|
||||
LEFT JOIN guild_characters gc ON gc.character_id = character.character_id
|
||||
LEFT JOIN guilds g ON g.id = gc.guild_id
|
||||
`
|
||||
|
||||
func GetGuildMembers(s *Session, guildID uint32, applicants bool) ([]*GuildMember, error) {
|
||||
rows, err := s.server.db.Queryx(fmt.Sprintf(`
|
||||
%s
|
||||
WHERE guild_id = $1 AND is_applicant = $2
|
||||
WHERE character.guild_id = $1 AND is_applicant = $2
|
||||
`, guildMembersSelectSQL), guildID, applicants)
|
||||
|
||||
if err != nil {
|
||||
@@ -115,7 +121,7 @@ func GetGuildMembers(s *Session, guildID uint32, applicants bool) ([]*GuildMembe
|
||||
}
|
||||
|
||||
func GetCharacterGuildData(s *Session, charID uint32) (*GuildMember, error) {
|
||||
rows, err := s.server.db.Queryx(fmt.Sprintf("%s WHERE character_id=$1", guildMembersSelectSQL), charID)
|
||||
rows, err := s.server.db.Queryx(fmt.Sprintf("%s WHERE character.character_id=$1", guildMembersSelectSQL), charID)
|
||||
|
||||
if err != nil {
|
||||
s.logger.Error(fmt.Sprintf("failed to retrieve membership data for character '%d'", charID))
|
||||
|
||||
@@ -367,13 +367,17 @@ func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
func handleMsgMhfResetTitle(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfOperateWarehouse)
|
||||
func initializeWarehouse(s *Session) {
|
||||
var t int
|
||||
err := s.server.db.QueryRow("SELECT character_id FROM warehouse WHERE character_id=$1", s.charID).Scan(&t)
|
||||
if err != nil {
|
||||
s.server.db.Exec("INSERT INTO warehouse (character_id) VALUES ($1)", s.charID)
|
||||
}
|
||||
}
|
||||
|
||||
func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfOperateWarehouse)
|
||||
initializeWarehouse(s)
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint8(pkt.Operation)
|
||||
switch pkt.Operation {
|
||||
@@ -446,6 +450,7 @@ func addWarehouseEquipment(s *Session, equipment mhfitem.MHFEquipment) {
|
||||
}
|
||||
|
||||
func warehouseGetItems(s *Session, index uint8) []mhfitem.MHFItemStack {
|
||||
initializeWarehouse(s)
|
||||
var data []byte
|
||||
var items []mhfitem.MHFItemStack
|
||||
s.server.db.QueryRow(fmt.Sprintf(`SELECT item%d FROM warehouse WHERE character_id=$1`, index), s.charID).Scan(&data)
|
||||
|
||||
@@ -185,7 +185,7 @@ func SendMailNotification(s *Session, m *Mail, recipient *Session) {
|
||||
|
||||
castedBinary.Build(bf, s.clientContext)
|
||||
|
||||
recipient.QueueSendMHF(castedBinary)
|
||||
recipient.QueueSendMHFNonBlocking(castedBinary)
|
||||
}
|
||||
|
||||
func getCharacterName(s *Session, charID uint32) string {
|
||||
|
||||
@@ -21,7 +21,6 @@ func handleMsgMhfLoadPartner(s *Session, p mhfpacket.MHFPacket) {
|
||||
data = make([]byte, 9)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, data)
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
}
|
||||
|
||||
func handleMsgMhfSavePartner(s *Session, p mhfpacket.MHFPacket) {
|
||||
@@ -157,60 +156,60 @@ func handleMsgMhfSaveMercenary(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfReadMercenaryW)
|
||||
if pkt.Op > 0 {
|
||||
bf := byteframe.NewByteFrame()
|
||||
var pactID uint32
|
||||
var name string
|
||||
var cid uint32
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
s.server.db.QueryRow("SELECT pact_id FROM characters WHERE id=$1", s.charID).Scan(&pactID)
|
||||
if pactID > 0 {
|
||||
s.server.db.QueryRow("SELECT name, id FROM characters WHERE rasta_id = $1", pactID).Scan(&name, &cid)
|
||||
bf.WriteUint8(1) // numLends
|
||||
bf.WriteUint32(pactID)
|
||||
bf.WriteUint32(cid)
|
||||
bf.WriteBool(false) // ?
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -8).Unix()))
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -1).Unix()))
|
||||
bf.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
||||
} else {
|
||||
bf.WriteUint8(0)
|
||||
}
|
||||
|
||||
if pkt.Op < 2 {
|
||||
var loans uint8
|
||||
temp := byteframe.NewByteFrame()
|
||||
rows, _ := s.server.db.Query("SELECT name, id, pact_id FROM characters WHERE pact_id=(SELECT rasta_id FROM characters WHERE id=$1)", s.charID)
|
||||
for rows.Next() {
|
||||
loans++
|
||||
rows.Scan(&name, &cid, &pactID)
|
||||
temp.WriteUint32(pactID)
|
||||
temp.WriteUint32(cid)
|
||||
temp.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -8).Unix()))
|
||||
temp.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * -1).Unix()))
|
||||
temp.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
||||
}
|
||||
bf.WriteUint8(loans)
|
||||
bf.WriteBytes(temp.Data())
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
return
|
||||
}
|
||||
var data []byte
|
||||
var gcp uint32
|
||||
s.server.db.QueryRow("SELECT savemercenary FROM characters WHERE id=$1", s.charID).Scan(&data)
|
||||
s.server.db.QueryRow("SELECT COALESCE(gcp, 0) FROM characters WHERE id=$1", s.charID).Scan(&gcp)
|
||||
|
||||
resp := byteframe.NewByteFrame()
|
||||
resp.WriteUint16(0)
|
||||
if len(data) == 0 {
|
||||
resp.WriteBool(false)
|
||||
var pactID, cid uint32
|
||||
var name string
|
||||
s.server.db.QueryRow("SELECT pact_id FROM characters WHERE id=$1", s.charID).Scan(&pactID)
|
||||
if pactID > 0 {
|
||||
s.server.db.QueryRow("SELECT name, id FROM characters WHERE rasta_id = $1", pactID).Scan(&name, &cid)
|
||||
bf.WriteUint8(1) // numLends
|
||||
bf.WriteUint32(pactID)
|
||||
bf.WriteUint32(cid)
|
||||
bf.WriteBool(true) // Escort enabled
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * 7).Unix()))
|
||||
bf.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
||||
} else {
|
||||
resp.WriteBool(true)
|
||||
resp.WriteBytes(data)
|
||||
bf.WriteUint8(0)
|
||||
}
|
||||
resp.WriteUint32(gcp)
|
||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||
|
||||
if pkt.Op != 2 && pkt.Op != 5 {
|
||||
var loans uint8
|
||||
temp := byteframe.NewByteFrame()
|
||||
rows, _ := s.server.db.Query("SELECT name, id, pact_id FROM characters WHERE pact_id=(SELECT rasta_id FROM characters WHERE id=$1)", s.charID)
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&name, &cid, &pactID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
loans++
|
||||
temp.WriteUint32(pactID)
|
||||
temp.WriteUint32(cid)
|
||||
temp.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||
temp.WriteUint32(uint32(TimeAdjusted().Add(time.Hour * 24 * 7).Unix()))
|
||||
temp.WriteBytes(stringsupport.PaddedString(name, 18, true))
|
||||
}
|
||||
bf.WriteUint8(loans)
|
||||
bf.WriteBytes(temp.Data())
|
||||
|
||||
if pkt.Op != 1 && pkt.Op != 4 {
|
||||
var data []byte
|
||||
var gcp uint32
|
||||
s.server.db.QueryRow("SELECT savemercenary FROM characters WHERE id=$1", s.charID).Scan(&data)
|
||||
s.server.db.QueryRow("SELECT COALESCE(gcp, 0) FROM characters WHERE id=$1", s.charID).Scan(&gcp)
|
||||
|
||||
if len(data) == 0 {
|
||||
bf.WriteBool(false)
|
||||
} else {
|
||||
bf.WriteBool(true)
|
||||
bf.WriteBytes(data)
|
||||
}
|
||||
bf.WriteUint32(gcp)
|
||||
}
|
||||
}
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfReadMercenaryM(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
@@ -238,8 +238,10 @@ func loadQuestFile(s *Session, questId int) []byte {
|
||||
}
|
||||
questBody.WriteBytes(newStrings.Data())
|
||||
|
||||
s.server.questCacheLock.Lock()
|
||||
s.server.questCacheData[questId] = questBody.Data()
|
||||
s.server.questCacheTime[questId] = time.Now()
|
||||
s.server.questCacheLock.Unlock()
|
||||
return questBody.Data()
|
||||
}
|
||||
|
||||
|
||||
@@ -129,12 +129,12 @@ func (s *Session) notifyRavi() {
|
||||
raviNotif.WriteUint16(0x0010) // End it.
|
||||
if s.server.erupeConfig.GameplayOptions.LowLatencyRaviente {
|
||||
for session := range sema.clients {
|
||||
session.QueueSend(raviNotif.Data())
|
||||
session.QueueSendNonBlocking(raviNotif.Data())
|
||||
}
|
||||
} else {
|
||||
for session := range sema.clients {
|
||||
if session.charID == s.charID {
|
||||
session.QueueSend(raviNotif.Data())
|
||||
session.QueueSendNonBlocking(raviNotif.Data())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,15 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysCreateAcquireSemaphore)
|
||||
SemaphoreID := pkt.SemaphoreID
|
||||
|
||||
if s.server.HasSemaphore(s) {
|
||||
s.semaphoreMode = !s.semaphoreMode
|
||||
}
|
||||
if s.semaphoreMode {
|
||||
s.semaphoreID[1]++
|
||||
} else {
|
||||
s.semaphoreID[0]++
|
||||
}
|
||||
|
||||
newSemaphore, exists := s.server.semaphore[SemaphoreID]
|
||||
if !exists {
|
||||
s.server.semaphoreLock.Lock()
|
||||
@@ -77,7 +86,7 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
|
||||
maxPlayers: 127,
|
||||
}
|
||||
} else {
|
||||
s.server.semaphore[SemaphoreID] = NewSemaphore(s.server, SemaphoreID, 1)
|
||||
s.server.semaphore[SemaphoreID] = NewSemaphore(s, SemaphoreID, 1)
|
||||
}
|
||||
newSemaphore = s.server.semaphore[SemaphoreID]
|
||||
s.server.semaphoreLock.Unlock()
|
||||
@@ -103,7 +112,7 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
|
||||
func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysAcquireSemaphore)
|
||||
if sema, exists := s.server.semaphore[pkt.SemaphoreID]; exists {
|
||||
sema.clients[s] = s.charID
|
||||
sema.host = s
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(sema.id)
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
|
||||
|
||||
@@ -59,7 +59,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
||||
s.Unlock()
|
||||
|
||||
// Tell the client to cleanup its current stage objects.
|
||||
s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{})
|
||||
s.QueueSendMHFNonBlocking(&mhfpacket.MsgSysCleanupObject{})
|
||||
|
||||
// Confirm the stage entry.
|
||||
doAckSimpleSucceed(s, ackHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
@@ -112,9 +112,8 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
||||
s.stage.RUnlock()
|
||||
}
|
||||
|
||||
newNotif.WriteUint16(0x0010) // End it.
|
||||
if len(newNotif.Data()) > 2 {
|
||||
s.QueueSend(newNotif.Data())
|
||||
s.QueueSendNonBlocking(newNotif.Data())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +237,7 @@ func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
for charID := range s.reservationStage.reservedClientSlots {
|
||||
session := s.server.FindSessionByCharID(charID)
|
||||
if session != nil {
|
||||
session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
|
||||
session.QueueSendMHFNonBlocking(&mhfpacket.MsgSysStageDestruct{})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +361,7 @@ func handleMsgSysWaitStageBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
|
||||
return
|
||||
}
|
||||
for {
|
||||
for i := 0; i < 10; i++ {
|
||||
s.logger.Debug("MsgSysWaitStageBinary before lock and get stage")
|
||||
stage.Lock()
|
||||
stageBinary, gotBinary := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]
|
||||
@@ -370,13 +369,15 @@ func handleMsgSysWaitStageBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
s.logger.Debug("MsgSysWaitStageBinary after lock and get stage")
|
||||
if gotBinary {
|
||||
doAckBufSucceed(s, pkt.AckHandle, stageBinary)
|
||||
break
|
||||
return
|
||||
} else {
|
||||
s.logger.Debug("Waiting stage binary", zap.Uint8("BinaryType0", pkt.BinaryType0), zap.Uint8("pkt.BinaryType1", pkt.BinaryType1))
|
||||
time.Sleep(1 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
s.logger.Warn("MsgSysWaitStageBinary stage binary timeout")
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{})
|
||||
} else {
|
||||
s.logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID))
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ type Server struct {
|
||||
|
||||
raviente *Raviente
|
||||
|
||||
questCacheLock sync.RWMutex
|
||||
questCacheData map[int][]byte
|
||||
questCacheTime map[int]time.Time
|
||||
}
|
||||
@@ -207,6 +208,7 @@ func (s *Server) Start() error {
|
||||
|
||||
go s.acceptClients()
|
||||
go s.manageSessions()
|
||||
go s.invalidateSessions()
|
||||
|
||||
// Start the discord bot for chat integration.
|
||||
if s.erupeConfig.Discord.Enabled && s.discordBot != nil {
|
||||
@@ -278,6 +280,21 @@ func (s *Server) manageSessions() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) invalidateSessions() {
|
||||
for {
|
||||
if s.isShuttingDown {
|
||||
break
|
||||
}
|
||||
for _, sess := range s.sessions {
|
||||
if time.Now().Sub(sess.lastPacket) > time.Second*time.Duration(30) {
|
||||
s.logger.Info("session timeout", zap.String("Name", sess.Name))
|
||||
logoutPlayer(sess)
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
}
|
||||
|
||||
// BroadcastMHF queues a MHFPacket to be sent to all sessions.
|
||||
func (s *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
|
||||
// Broadcast the data.
|
||||
@@ -424,24 +441,13 @@ func (s *Server) FindObjectByChar(charID uint32) *Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) NextSemaphoreID() uint32 {
|
||||
for {
|
||||
exists := false
|
||||
s.semaphoreIndex = s.semaphoreIndex + 1
|
||||
if s.semaphoreIndex > 0xFFFF {
|
||||
s.semaphoreIndex = 1
|
||||
}
|
||||
for _, semaphore := range s.semaphore {
|
||||
if semaphore.id == s.semaphoreIndex {
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
break
|
||||
func (s *Server) HasSemaphore(ses *Session) bool {
|
||||
for _, semaphore := range s.semaphore {
|
||||
if semaphore.host == ses {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return s.semaphoreIndex
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Server) Season() uint8 {
|
||||
|
||||
@@ -10,6 +10,7 @@ type i18n struct {
|
||||
noOp string
|
||||
disabled string
|
||||
reload string
|
||||
playtime string
|
||||
kqf struct {
|
||||
get string
|
||||
set struct {
|
||||
@@ -175,6 +176,8 @@ func getLangStrings(s *Server) i18n {
|
||||
i.commands.noOp = "You don't have permission to use this command"
|
||||
i.commands.disabled = "%s command is disabled"
|
||||
i.commands.reload = "Reloading players..."
|
||||
i.commands.playtime = "Playtime: %d hours %d minutes %d seconds"
|
||||
|
||||
i.commands.kqf.get = "KQF: %x"
|
||||
i.commands.kqf.set.error = "Error in command. Format: %s set xxxxxxxxxxxxxxxx"
|
||||
i.commands.kqf.set.success = "KQF set, please switch Land/World"
|
||||
|
||||
@@ -22,15 +22,18 @@ type Semaphore struct {
|
||||
|
||||
// Max Players for Semaphore
|
||||
maxPlayers uint16
|
||||
|
||||
host *Session
|
||||
}
|
||||
|
||||
// NewSemaphore creates a new Semaphore with intialized values
|
||||
func NewSemaphore(s *Server, ID string, MaxPlayers uint16) *Semaphore {
|
||||
func NewSemaphore(s *Session, ID string, MaxPlayers uint16) *Semaphore {
|
||||
sema := &Semaphore{
|
||||
name: ID,
|
||||
id: s.NextSemaphoreID(),
|
||||
id: s.GetSemaphoreID(),
|
||||
clients: make(map[*Session]uint32),
|
||||
maxPlayers: MaxPlayers,
|
||||
host: s,
|
||||
}
|
||||
return sema
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"erupe-ce/common/mhfcourse"
|
||||
_config "erupe-ce/config"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -48,7 +50,12 @@ type Session struct {
|
||||
kqf []byte
|
||||
kqfOverride bool
|
||||
|
||||
semaphore *Semaphore // Required for the stateful MsgSysUnreserveStage packet.
|
||||
playtime uint32
|
||||
playtimeTime time.Time
|
||||
|
||||
semaphore *Semaphore // Required for the stateful MsgSysUnreserveStage packet.
|
||||
semaphoreMode bool
|
||||
semaphoreID []uint16
|
||||
|
||||
// A stack containing the stage movement history (push on enter/move, pop on back)
|
||||
stageMoveStack *stringstack.StringStack
|
||||
@@ -79,6 +86,7 @@ func NewSession(server *Server, conn net.Conn) *Session {
|
||||
sessionStart: TimeAdjusted().Unix(),
|
||||
stageMoveStack: stringstack.New(),
|
||||
ackStart: make(map[uint32]time.Time),
|
||||
semaphoreID: make([]uint16, 2),
|
||||
}
|
||||
s.SetObjectID()
|
||||
return s
|
||||
@@ -96,22 +104,9 @@ func (s *Session) Start() {
|
||||
// QueueSend queues a packet (raw []byte) to be sent.
|
||||
func (s *Session) QueueSend(data []byte) {
|
||||
s.logMessage(binary.BigEndian.Uint16(data[0:2]), data, "Server", s.Name)
|
||||
select {
|
||||
case s.sendPackets <- packet{data, false}:
|
||||
// Enqueued data
|
||||
default:
|
||||
s.logger.Warn("Packet queue too full, flushing!")
|
||||
var tempPackets []packet
|
||||
for len(s.sendPackets) > 0 {
|
||||
tempPacket := <-s.sendPackets
|
||||
if !tempPacket.nonBlocking {
|
||||
tempPackets = append(tempPackets, tempPacket)
|
||||
}
|
||||
}
|
||||
for _, tempPacket := range tempPackets {
|
||||
s.sendPackets <- tempPacket
|
||||
}
|
||||
s.sendPackets <- packet{data, false}
|
||||
err := s.cryptConn.SendPacket(append(data, []byte{0x00, 0x10}...))
|
||||
if err != nil {
|
||||
s.logger.Warn("Failed to send packet")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +133,19 @@ func (s *Session) QueueSendMHF(pkt mhfpacket.MHFPacket) {
|
||||
s.QueueSend(bf.Data())
|
||||
}
|
||||
|
||||
// QueueSendMHFNonBlocking queues a MHFPacket to be sent, dropping the packet entirely if the queue is full.
|
||||
func (s *Session) QueueSendMHFNonBlocking(pkt mhfpacket.MHFPacket) {
|
||||
// Make the header
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(uint16(pkt.Opcode()))
|
||||
|
||||
// Build the packet onto the byteframe.
|
||||
pkt.Build(bf, s.clientContext)
|
||||
|
||||
// Queue it.
|
||||
s.QueueSendNonBlocking(bf.Data())
|
||||
}
|
||||
|
||||
// QueueAck is a helper function to queue an MSG_SYS_ACK with the given ack handle and data.
|
||||
func (s *Session) QueueAck(ackHandle uint32, data []byte) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
@@ -150,26 +158,26 @@ func (s *Session) QueueAck(ackHandle uint32, data []byte) {
|
||||
func (s *Session) sendLoop() {
|
||||
var pkt packet
|
||||
for {
|
||||
var buf []byte
|
||||
if s.closed {
|
||||
return
|
||||
}
|
||||
for len(s.sendPackets) > 0 {
|
||||
pkt = <-s.sendPackets
|
||||
err := s.cryptConn.SendPacket(append(pkt.data, []byte{0x00, 0x10}...))
|
||||
buf = append(buf, pkt.data...)
|
||||
}
|
||||
if len(buf) > 0 {
|
||||
err := s.cryptConn.SendPacket(append(buf, []byte{0x00, 0x10}...))
|
||||
if err != nil {
|
||||
s.logger.Warn("Failed to send packet")
|
||||
}
|
||||
}
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
time.Sleep(time.Duration(_config.ErupeConfig.LoopDelay) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) recvLoop() {
|
||||
for {
|
||||
if time.Now().Add(-30 * time.Second).After(s.lastPacket) {
|
||||
logoutPlayer(s)
|
||||
return
|
||||
}
|
||||
if s.closed {
|
||||
logoutPlayer(s)
|
||||
return
|
||||
@@ -185,7 +193,7 @@ func (s *Session) recvLoop() {
|
||||
return
|
||||
}
|
||||
s.handlePacketGroup(pkt)
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
time.Sleep(time.Duration(_config.ErupeConfig.LoopDelay) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +280,7 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien
|
||||
} else {
|
||||
fmt.Printf("[%s] -> [%s]\n", sender, recipient)
|
||||
}
|
||||
fmt.Printf("Opcode: %s\n", opcodePID)
|
||||
fmt.Printf("Opcode: (Dec: %d Hex: 0x%04X Name: %s) \n", opcode, opcode, opcodePID)
|
||||
if s.server.erupeConfig.DebugOptions.LogMessageData {
|
||||
if len(data) <= s.server.erupeConfig.DebugOptions.MaxHexdumpLength {
|
||||
fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data))
|
||||
@@ -310,6 +318,14 @@ func (s *Session) NextObjectID() uint32 {
|
||||
return bf.ReadUint32()
|
||||
}
|
||||
|
||||
func (s *Session) GetSemaphoreID() uint32 {
|
||||
if s.semaphoreMode {
|
||||
return 0x000E0000 + uint32(s.semaphoreID[1])
|
||||
} else {
|
||||
return 0x000F0000 + uint32(s.semaphoreID[0])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) isOp() bool {
|
||||
var op bool
|
||||
err := s.server.db.QueryRow(`SELECT op FROM users u WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$1)`, s.charID).Scan(&op)
|
||||
|
||||
Reference in New Issue
Block a user