mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-02-05 09:42:56 +01:00
Merge branch 'ZeruLight:main' into main
This commit is contained in:
@@ -552,10 +552,6 @@ func handleMsgSysInfokyserver(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
func handleMsgMhfGetCaUniqueID(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
func handleMsgMhfAcquireItem(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
func handleMsgMhfTransferItem(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfTransferItem)
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
|
||||
@@ -1,18 +1,173 @@
|
||||
package channelserver
|
||||
|
||||
import "erupe-ce/network/mhfpacket"
|
||||
import (
|
||||
"erupe-ce/common/byteframe"
|
||||
ps "erupe-ce/common/pascalstring"
|
||||
"erupe-ce/common/stringsupport"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CampaignEvent struct {
|
||||
ID uint32
|
||||
Unk0 uint32
|
||||
MinHR int16
|
||||
MaxHR int16
|
||||
MinSR int16
|
||||
MaxSR int16
|
||||
MinGR int16
|
||||
MaxGR int16
|
||||
Unk1 uint16
|
||||
Unk2 uint8
|
||||
Unk3 uint8
|
||||
Unk4 uint16
|
||||
Unk5 uint16
|
||||
Start time.Time
|
||||
End time.Time
|
||||
Unk6 uint8
|
||||
String0 string
|
||||
String1 string
|
||||
String2 string
|
||||
String3 string
|
||||
Link string
|
||||
Prefix string
|
||||
Categories []uint16
|
||||
}
|
||||
|
||||
type CampaignCategory struct {
|
||||
ID uint16
|
||||
Type uint8
|
||||
Title string
|
||||
Description string
|
||||
}
|
||||
|
||||
type CampaignLink struct {
|
||||
CategoryID uint16
|
||||
CampaignID uint32
|
||||
}
|
||||
|
||||
func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfEnumerateCampaign)
|
||||
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
events := []CampaignEvent{}
|
||||
categories := []CampaignCategory{}
|
||||
var campaignLinks []CampaignLink
|
||||
|
||||
if len(events) > 255 {
|
||||
bf.WriteUint8(255)
|
||||
bf.WriteUint16(uint16(len(events)))
|
||||
} else {
|
||||
bf.WriteUint8(uint8(len(events)))
|
||||
}
|
||||
for _, event := range events {
|
||||
bf.WriteUint32(event.ID)
|
||||
bf.WriteUint32(event.Unk0)
|
||||
bf.WriteInt16(event.MinHR)
|
||||
bf.WriteInt16(event.MaxHR)
|
||||
bf.WriteInt16(event.MinSR)
|
||||
bf.WriteInt16(event.MaxSR)
|
||||
bf.WriteInt16(event.MinGR)
|
||||
bf.WriteInt16(event.MaxGR)
|
||||
bf.WriteUint16(event.Unk1)
|
||||
bf.WriteUint8(event.Unk2)
|
||||
bf.WriteUint8(event.Unk3)
|
||||
bf.WriteUint16(event.Unk4)
|
||||
bf.WriteUint16(event.Unk5)
|
||||
bf.WriteUint32(uint32(event.Start.Unix()))
|
||||
bf.WriteUint32(uint32(event.End.Unix()))
|
||||
bf.WriteUint8(event.Unk6)
|
||||
ps.Uint8(bf, event.String0, true)
|
||||
ps.Uint8(bf, event.String1, true)
|
||||
ps.Uint8(bf, event.String2, true)
|
||||
ps.Uint8(bf, event.String3, true)
|
||||
ps.Uint8(bf, event.Link, true)
|
||||
for i := range event.Categories {
|
||||
campaignLinks = append(campaignLinks, CampaignLink{event.Categories[i], event.ID})
|
||||
}
|
||||
}
|
||||
|
||||
if len(events) > 255 {
|
||||
bf.WriteUint8(255)
|
||||
bf.WriteUint16(uint16(len(events)))
|
||||
} else {
|
||||
bf.WriteUint8(uint8(len(events)))
|
||||
}
|
||||
for _, event := range events {
|
||||
bf.WriteUint32(event.ID)
|
||||
bf.WriteUint8(1) // Always 1?
|
||||
bf.WriteBytes([]byte(event.Prefix))
|
||||
}
|
||||
|
||||
if len(categories) > 255 {
|
||||
bf.WriteUint8(255)
|
||||
bf.WriteUint16(uint16(len(categories)))
|
||||
} else {
|
||||
bf.WriteUint8(uint8(len(categories)))
|
||||
}
|
||||
for _, category := range categories {
|
||||
bf.WriteUint16(category.ID)
|
||||
bf.WriteUint8(category.Type)
|
||||
xTitle := stringsupport.UTF8ToSJIS(category.Title)
|
||||
xDescription := stringsupport.UTF8ToSJIS(category.Description)
|
||||
bf.WriteUint8(uint8(len(xTitle)))
|
||||
bf.WriteUint8(uint8(len(xDescription)))
|
||||
bf.WriteBytes(xTitle)
|
||||
bf.WriteBytes(xDescription)
|
||||
}
|
||||
|
||||
if len(campaignLinks) > 255 {
|
||||
bf.WriteUint8(255)
|
||||
bf.WriteUint16(uint16(len(campaignLinks)))
|
||||
} else {
|
||||
bf.WriteUint8(uint8(len(campaignLinks)))
|
||||
}
|
||||
for _, link := range campaignLinks {
|
||||
bf.WriteUint16(link.CategoryID)
|
||||
bf.WriteUint32(link.CampaignID)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfStateCampaign)
|
||||
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(1)
|
||||
bf.WriteUint16(0)
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfApplyCampaign(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfApplyCampaign)
|
||||
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1)
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfEnumerateItem)
|
||||
items := []struct {
|
||||
Unk0 uint32
|
||||
Unk1 uint16
|
||||
Unk2 uint16
|
||||
Unk3 uint16
|
||||
Unk4 uint32
|
||||
Unk5 uint32
|
||||
}{}
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(uint16(len(items)))
|
||||
for _, item := range items {
|
||||
bf.WriteUint32(item.Unk0)
|
||||
bf.WriteUint16(item.Unk1)
|
||||
bf.WriteUint16(item.Unk2)
|
||||
bf.WriteUint16(item.Unk3)
|
||||
bf.WriteUint32(item.Unk4)
|
||||
bf.WriteUint32(item.Unk5)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfAcquireItem(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfAcquireItem)
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ func (save *CharacterSaveData) updateSaveDataWithStruct() {
|
||||
if _config.ErupeConfig.RealClientMode == _config.ZZ {
|
||||
copy(save.decompSave[pointerRP:pointerRP+2], rpBytes)
|
||||
copy(save.decompSave[pointerKQF:pointerKQF+8], save.KQF)
|
||||
} else {
|
||||
} else if _config.ErupeConfig.RealClientMode >= _config.Z1 {
|
||||
copy(save.decompSave[pointerRPZ:pointerRPZ+2], rpBytes)
|
||||
copy(save.decompSave[pointerKQFZ:pointerKQFZ+8], save.KQF)
|
||||
}
|
||||
@@ -181,7 +181,7 @@ func (save *CharacterSaveData) updateStructWithSaveData() {
|
||||
save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4]))
|
||||
}
|
||||
save.KQF = save.decompSave[pointerKQF : pointerKQF+8]
|
||||
} else {
|
||||
} else if _config.ErupeConfig.RealClientMode >= _config.Z1 {
|
||||
save.RP = binary.LittleEndian.Uint16(save.decompSave[pointerRPZ : pointerRPZ+2])
|
||||
save.HouseTier = save.decompSave[pointerHouseTierZ : pointerHouseTierZ+5]
|
||||
save.HouseData = save.decompSave[pointerHouseDataZ : pointerHouseDataZ+195]
|
||||
|
||||
@@ -48,9 +48,41 @@ func handleMsgMhfReleaseEvent(s *Session, p mhfpacket.MHFPacket) {
|
||||
})
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
Unk0 uint16
|
||||
Unk1 uint16
|
||||
Unk2 uint16
|
||||
Unk3 uint16
|
||||
Unk4 uint16
|
||||
Unk5 uint32
|
||||
Unk6 uint32
|
||||
Unk7 []uint16
|
||||
}
|
||||
|
||||
func handleMsgMhfEnumerateEvent(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfEnumerateEvent)
|
||||
stubEnumerateNoResults(s, pkt.AckHandle)
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
events := []Event{}
|
||||
|
||||
bf.WriteUint8(uint8(len(events)))
|
||||
for _, event := range events {
|
||||
bf.WriteUint16(event.Unk0)
|
||||
bf.WriteUint16(event.Unk1)
|
||||
bf.WriteUint16(event.Unk2)
|
||||
bf.WriteUint16(event.Unk3)
|
||||
bf.WriteUint16(event.Unk4)
|
||||
bf.WriteUint32(event.Unk5)
|
||||
bf.WriteUint32(event.Unk6)
|
||||
if event.Unk0 == 2 {
|
||||
bf.WriteUint8(uint8(len(event.Unk7)))
|
||||
for _, u := range event.Unk7 {
|
||||
bf.WriteUint16(u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
type activeFeature struct {
|
||||
|
||||
@@ -616,13 +616,7 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfOperateGuild)
|
||||
|
||||
guild, err := GetGuildInfoByID(s, pkt.GuildID)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
characterGuildInfo, err := GetCharacterGuildData(s, s.charID)
|
||||
|
||||
if err != nil {
|
||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
@@ -631,22 +625,19 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
switch pkt.Action {
|
||||
case mhfpacket.OPERATE_GUILD_DISBAND:
|
||||
case mhfpacket.OperateGuildDisband:
|
||||
response := 1
|
||||
if guild.LeaderCharID != s.charID {
|
||||
s.logger.Warn(fmt.Sprintf("character '%d' is attempting to manage guild '%d' without permission", s.charID, guild.ID))
|
||||
return
|
||||
response = 0
|
||||
} else {
|
||||
err = guild.Disband(s)
|
||||
if err != nil {
|
||||
response = 0
|
||||
}
|
||||
}
|
||||
|
||||
err = guild.Disband(s)
|
||||
response := 0x01
|
||||
|
||||
if err != nil {
|
||||
// All successful acks return 0x01, assuming 0x00 is failure
|
||||
response = 0x00
|
||||
}
|
||||
|
||||
bf.WriteUint32(uint32(response))
|
||||
case mhfpacket.OPERATE_GUILD_RESIGN:
|
||||
case mhfpacket.OperateGuildResign:
|
||||
guildMembers, err := GetGuildMembers(s, guild.ID, false)
|
||||
if err == nil {
|
||||
sort.Slice(guildMembers[:], func(i, j int) bool {
|
||||
@@ -665,25 +656,22 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
guild.Save(s)
|
||||
}
|
||||
case mhfpacket.OPERATE_GUILD_APPLY:
|
||||
case mhfpacket.OperateGuildApply:
|
||||
err = guild.CreateApplication(s, s.charID, GuildApplicationTypeApplied, nil)
|
||||
|
||||
if err == nil {
|
||||
bf.WriteUint32(guild.LeaderCharID)
|
||||
} else {
|
||||
bf.WriteUint32(0)
|
||||
}
|
||||
case mhfpacket.OPERATE_GUILD_LEAVE:
|
||||
var err error
|
||||
|
||||
case mhfpacket.OperateGuildLeave:
|
||||
if characterGuildInfo.IsApplicant {
|
||||
err = guild.RejectApplication(s, s.charID)
|
||||
} else {
|
||||
err = guild.RemoveCharacter(s, s.charID)
|
||||
}
|
||||
|
||||
response := 0x01
|
||||
response := 1
|
||||
if err != nil {
|
||||
// All successful acks return 0x01, assuming 0x00 is failure
|
||||
response = 0x00
|
||||
response = 0
|
||||
} else {
|
||||
mail := Mail{
|
||||
RecipientID: s.charID,
|
||||
@@ -693,26 +681,25 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
mail.Send(s, nil)
|
||||
}
|
||||
|
||||
bf.WriteUint32(uint32(response))
|
||||
case mhfpacket.OPERATE_GUILD_DONATE_RANK:
|
||||
case mhfpacket.OperateGuildDonateRank:
|
||||
bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, false))
|
||||
case mhfpacket.OPERATE_GUILD_SET_APPLICATION_DENY:
|
||||
case mhfpacket.OperateGuildSetApplicationDeny:
|
||||
s.server.db.Exec("UPDATE guilds SET recruiting=false WHERE id=$1", guild.ID)
|
||||
case mhfpacket.OPERATE_GUILD_SET_APPLICATION_ALLOW:
|
||||
case mhfpacket.OperateGuildSetApplicationAllow:
|
||||
s.server.db.Exec("UPDATE guilds SET recruiting=true WHERE id=$1", guild.ID)
|
||||
case mhfpacket.OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE:
|
||||
case mhfpacket.OperateGuildSetAvoidLeadershipTrue:
|
||||
handleAvoidLeadershipUpdate(s, pkt, true)
|
||||
case mhfpacket.OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE:
|
||||
case mhfpacket.OperateGuildSetAvoidLeadershipFalse:
|
||||
handleAvoidLeadershipUpdate(s, pkt, false)
|
||||
case mhfpacket.OPERATE_GUILD_UPDATE_COMMENT:
|
||||
case mhfpacket.OperateGuildUpdateComment:
|
||||
if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() {
|
||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
guild.Comment = stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())
|
||||
guild.Save(s)
|
||||
case mhfpacket.OPERATE_GUILD_UPDATE_MOTTO:
|
||||
case mhfpacket.OperateGuildUpdateMotto:
|
||||
if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() {
|
||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
@@ -721,27 +708,29 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
guild.SubMotto = pkt.Data1.ReadUint8()
|
||||
guild.MainMotto = pkt.Data1.ReadUint8()
|
||||
guild.Save(s)
|
||||
case mhfpacket.OPERATE_GUILD_RENAME_PUGI_1:
|
||||
case mhfpacket.OperateGuildRenamePugi1:
|
||||
handleRenamePugi(s, pkt.Data2, guild, 1)
|
||||
case mhfpacket.OPERATE_GUILD_RENAME_PUGI_2:
|
||||
case mhfpacket.OperateGuildRenamePugi2:
|
||||
handleRenamePugi(s, pkt.Data2, guild, 2)
|
||||
case mhfpacket.OPERATE_GUILD_RENAME_PUGI_3:
|
||||
case mhfpacket.OperateGuildRenamePugi3:
|
||||
handleRenamePugi(s, pkt.Data2, guild, 3)
|
||||
case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_1:
|
||||
case mhfpacket.OperateGuildChangePugi1:
|
||||
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 1)
|
||||
case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_2:
|
||||
case mhfpacket.OperateGuildChangePugi2:
|
||||
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 2)
|
||||
case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_3:
|
||||
case mhfpacket.OperateGuildChangePugi3:
|
||||
handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 3)
|
||||
case mhfpacket.OPERATE_GUILD_UNLOCK_OUTFIT:
|
||||
case mhfpacket.OperateGuildUnlockOutfit:
|
||||
// TODO: This doesn't implement blocking, if someone unlocked the same outfit at the same time
|
||||
s.server.db.Exec(`UPDATE guilds SET pugi_outfits=pugi_outfits+$1 WHERE id=$2`, int(math.Pow(float64(pkt.Data1.ReadUint32()), 2)), guild.ID)
|
||||
case mhfpacket.OPERATE_GUILD_DONATE_EVENT:
|
||||
case mhfpacket.OperateGuildDonateRoom:
|
||||
// TODO: Where does this go?
|
||||
case mhfpacket.OperateGuildDonateEvent:
|
||||
quantity := uint16(pkt.Data1.ReadUint32())
|
||||
bf.WriteBytes(handleDonateRP(s, quantity, guild, true))
|
||||
// TODO: Move this value onto rp_yesterday and reset to 0... daily?
|
||||
s.server.db.Exec(`UPDATE guild_characters SET rp_today=rp_today+$1 WHERE character_id=$2`, quantity, s.charID)
|
||||
case mhfpacket.OPERATE_GUILD_EVENT_EXCHANGE:
|
||||
case mhfpacket.OperateGuildEventExchange:
|
||||
rp := uint16(pkt.Data1.ReadUint32())
|
||||
var balance uint32
|
||||
s.server.db.QueryRow(`UPDATE guilds SET event_rp=event_rp-$1 WHERE id=$2 RETURNING event_rp`, rp, guild.ID).Scan(&balance)
|
||||
@@ -930,7 +919,12 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint8(guild.SubMotto)
|
||||
|
||||
// Unk appears to be static
|
||||
bf.WriteBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
|
||||
bf.WriteUint8(0)
|
||||
bf.WriteUint8(0)
|
||||
bf.WriteUint8(0)
|
||||
bf.WriteUint8(0)
|
||||
bf.WriteUint8(0)
|
||||
bf.WriteUint8(0)
|
||||
|
||||
bf.WriteBool(!guild.Recruiting)
|
||||
|
||||
@@ -953,28 +947,39 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint8(FestivalColourCodes[guild.FestivalColour])
|
||||
bf.WriteUint32(guild.RankRP)
|
||||
bf.WriteBytes(guildLeaderName)
|
||||
bf.WriteBytes([]byte{0x00, 0x00, 0x00, 0x00}) // Unk
|
||||
bf.WriteBool(false) // isReturnGuild
|
||||
bf.WriteBool(false) // earnedSpecialHall
|
||||
bf.WriteBytes([]byte{0x02, 0x02}) // Unk
|
||||
bf.WriteUint32(guild.EventRP)
|
||||
bf.WriteUint32(0) // Unk
|
||||
bf.WriteBool(false) // isReturnGuild
|
||||
bf.WriteBool(false) // earnedSpecialHall
|
||||
bf.WriteUint8(2)
|
||||
bf.WriteUint8(2)
|
||||
bf.WriteUint32(guild.EventRP) // Skipped if last byte is <2?
|
||||
ps.Uint8(bf, guild.PugiName1, true)
|
||||
ps.Uint8(bf, guild.PugiName2, true)
|
||||
ps.Uint8(bf, guild.PugiName3, true)
|
||||
bf.WriteUint8(guild.PugiOutfit1)
|
||||
bf.WriteUint8(guild.PugiOutfit2)
|
||||
bf.WriteUint8(guild.PugiOutfit3)
|
||||
bf.WriteUint8(guild.PugiOutfit1)
|
||||
bf.WriteUint8(guild.PugiOutfit2)
|
||||
bf.WriteUint8(guild.PugiOutfit3)
|
||||
if s.server.erupeConfig.RealClientMode >= _config.Z1 {
|
||||
bf.WriteUint8(guild.PugiOutfit1)
|
||||
bf.WriteUint8(guild.PugiOutfit2)
|
||||
bf.WriteUint8(guild.PugiOutfit3)
|
||||
}
|
||||
bf.WriteUint32(guild.PugiOutfits)
|
||||
|
||||
// Unk flags
|
||||
bf.WriteUint8(0x3C) // also seen as 0x32 on JP and 0x64 on TW
|
||||
if guild.Rank >= 3 {
|
||||
bf.WriteUint8(40)
|
||||
} else if guild.Rank >= 7 {
|
||||
bf.WriteUint8(50)
|
||||
} else if guild.Rank >= 10 {
|
||||
bf.WriteUint8(60)
|
||||
} else {
|
||||
bf.WriteUint8(30)
|
||||
}
|
||||
|
||||
bf.WriteBytes([]byte{
|
||||
0x00, 0x00, 0xD6, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
})
|
||||
bf.WriteUint32(55000)
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteUint16(0) // Changing Room RP
|
||||
bf.WriteUint16(0)
|
||||
|
||||
if guild.AllianceID > 0 {
|
||||
alliance, err := GetAllianceData(s, guild.AllianceID)
|
||||
@@ -984,7 +989,8 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint32(alliance.ID)
|
||||
bf.WriteUint32(uint32(alliance.CreatedAt.Unix()))
|
||||
bf.WriteUint16(alliance.TotalMembers)
|
||||
bf.WriteUint16(0) // Unk0
|
||||
bf.WriteUint8(0)
|
||||
bf.WriteUint8(0)
|
||||
ps.Uint16(bf, alliance.Name, true)
|
||||
if alliance.SubGuild1ID > 0 {
|
||||
if alliance.SubGuild2ID > 0 {
|
||||
@@ -1044,29 +1050,46 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint16(uint16(len(applicants)))
|
||||
for _, applicant := range applicants {
|
||||
bf.WriteUint32(applicant.CharID)
|
||||
bf.WriteUint16(0)
|
||||
bf.WriteUint16(0)
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteUint16(applicant.HRP)
|
||||
bf.WriteUint16(applicant.GR)
|
||||
ps.Uint8(bf, applicant.Name, true)
|
||||
}
|
||||
}
|
||||
|
||||
bf.WriteUint16(0x0000) // lenAllianceApplications
|
||||
type UnkGuildInfo struct {
|
||||
Unk0 uint8
|
||||
Unk1 uint8
|
||||
Unk2 uint8
|
||||
}
|
||||
unkGuildInfo := []UnkGuildInfo{}
|
||||
bf.WriteUint8(uint8(len(unkGuildInfo)))
|
||||
for _, info := range unkGuildInfo {
|
||||
bf.WriteUint8(info.Unk0)
|
||||
bf.WriteUint8(info.Unk1)
|
||||
bf.WriteUint8(info.Unk2)
|
||||
}
|
||||
|
||||
/*
|
||||
alliance application format
|
||||
uint16 numapplicants (above)
|
||||
|
||||
uint32 guild id
|
||||
uint32 guild leader id (for mail)
|
||||
uint32 unk (always null in pcap)
|
||||
uint16 member count
|
||||
uint16 len guild name
|
||||
string nullterm guild name
|
||||
uint16 len guild leader name
|
||||
string nullterm guild leader name
|
||||
*/
|
||||
type AllianceInvite struct {
|
||||
GuildID uint32
|
||||
LeaderID uint32
|
||||
Unk0 uint16
|
||||
Unk1 uint16
|
||||
Members uint16
|
||||
GuildName string
|
||||
LeaderName string
|
||||
}
|
||||
allianceInvites := []AllianceInvite{}
|
||||
bf.WriteUint8(uint8(len(allianceInvites)))
|
||||
for _, invite := range allianceInvites {
|
||||
bf.WriteUint32(invite.GuildID)
|
||||
bf.WriteUint32(invite.LeaderID)
|
||||
bf.WriteUint16(invite.Unk0)
|
||||
bf.WriteUint16(invite.Unk1)
|
||||
bf.WriteUint16(invite.Members)
|
||||
ps.Uint16(bf, invite.GuildName, true)
|
||||
ps.Uint16(bf, invite.LeaderName, true)
|
||||
}
|
||||
|
||||
if guild.Icon != nil {
|
||||
bf.WriteUint8(uint8(len(guild.Icon.Parts)))
|
||||
@@ -1084,7 +1107,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint16(p.PosY)
|
||||
}
|
||||
} else {
|
||||
bf.WriteUint8(0x00)
|
||||
bf.WriteUint8(0)
|
||||
}
|
||||
bf.WriteUint8(0) // Unk
|
||||
|
||||
@@ -1348,7 +1371,7 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
||||
if guild != nil {
|
||||
isApplicant, _ := guild.HasApplicationForCharID(s, s.charID)
|
||||
if isApplicant {
|
||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 2))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1390,7 +1413,9 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
||||
for _, member := range guildMembers {
|
||||
bf.WriteUint32(member.CharID)
|
||||
bf.WriteUint16(member.HRP)
|
||||
bf.WriteUint16(member.GR)
|
||||
if s.server.erupeConfig.RealClientMode > _config.G7 {
|
||||
bf.WriteUint16(member.GR)
|
||||
}
|
||||
if s.server.erupeConfig.RealClientMode < _config.ZZ {
|
||||
// Magnet Spike crash workaround
|
||||
bf.WriteUint16(0)
|
||||
@@ -1456,7 +1481,6 @@ func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfGetGuildManageRight)
|
||||
|
||||
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||
|
||||
if guild == nil && s.prevGuildID != 0 {
|
||||
guild, err = GetGuildInfoByID(s, s.prevGuildID)
|
||||
s.prevGuildID = 0
|
||||
@@ -1466,31 +1490,14 @@ func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
s.logger.Warn("failed to respond to manage rights message")
|
||||
return
|
||||
} else if guild == nil {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(0x00) // Unk
|
||||
bf.WriteUint16(0x00) // Member count
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
return
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
bf.WriteUint16(0x00) // Unk
|
||||
bf.WriteUint16(guild.MemberCount)
|
||||
|
||||
bf.WriteUint32(uint32(guild.MemberCount))
|
||||
members, _ := GetGuildMembers(s, guild.ID, false)
|
||||
|
||||
for _, member := range members {
|
||||
bf.WriteUint32(member.CharID)
|
||||
bf.WriteBool(member.Recruiter)
|
||||
bf.WriteBytes(make([]byte, 3))
|
||||
}
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"erupe-ce/common/byteframe"
|
||||
ps "erupe-ce/common/pascalstring"
|
||||
"erupe-ce/common/stringsupport"
|
||||
_config "erupe-ce/config"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
@@ -249,6 +250,9 @@ func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) {
|
||||
s.logger.Error("Failed to load decomyset", zap.Error(err))
|
||||
}
|
||||
if len(data) == 0 {
|
||||
if s.server.erupeConfig.RealClientMode <= _config.G7 {
|
||||
data = []byte{0x00, 0x00}
|
||||
}
|
||||
data = []byte{0x01, 0x00}
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, data)
|
||||
|
||||
@@ -7,54 +7,124 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type TournamentInfo0 struct {
|
||||
ID uint32
|
||||
MaxPlayers uint32
|
||||
CurrentPlayers uint32
|
||||
Unk1 uint16
|
||||
TextColor uint16
|
||||
Unk2 uint32
|
||||
Time1 time.Time
|
||||
Time2 time.Time
|
||||
Time3 time.Time
|
||||
Time4 time.Time
|
||||
Time5 time.Time
|
||||
Time6 time.Time
|
||||
Unk3 uint8
|
||||
Unk4 uint8
|
||||
MinHR uint32
|
||||
MaxHR uint32
|
||||
Unk5 string
|
||||
Unk6 string
|
||||
}
|
||||
|
||||
type TournamentInfo21 struct {
|
||||
Unk0 uint32
|
||||
Unk1 uint32
|
||||
Unk2 uint32
|
||||
Unk3 uint8
|
||||
}
|
||||
|
||||
type TournamentInfo22 struct {
|
||||
Unk0 uint32
|
||||
Unk1 uint32
|
||||
Unk2 uint32
|
||||
Unk3 uint8
|
||||
Unk4 string
|
||||
}
|
||||
|
||||
func handleMsgMhfInfoTournament(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfInfoTournament)
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
tournamentInfo0 := []TournamentInfo0{}
|
||||
tournamentInfo21 := []TournamentInfo21{}
|
||||
tournamentInfo22 := []TournamentInfo22{}
|
||||
|
||||
switch pkt.Unk0 {
|
||||
case 0:
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||
bf.WriteUint32(0) // Tied to schedule ID?
|
||||
case 1:
|
||||
|
||||
bf.WriteBytes(make([]byte, 21))
|
||||
ps.Uint8(bf, "", false)
|
||||
break
|
||||
|
||||
bf.WriteUint32(0xACEDCAFE)
|
||||
|
||||
bf.WriteUint32(5) // Active schedule?
|
||||
|
||||
bf.WriteUint32(1) // Schedule ID?
|
||||
|
||||
bf.WriteUint32(32) // Max players
|
||||
bf.WriteUint32(0) // Registered players
|
||||
|
||||
bf.WriteUint16(0)
|
||||
bf.WriteUint16(2) // Color code for schedule item
|
||||
bf.WriteUint32(0)
|
||||
|
||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * -10).Unix()))
|
||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix()))
|
||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix()))
|
||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix()))
|
||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix()))
|
||||
bf.WriteUint32(uint32(time.Now().Add(time.Hour * 10).Unix()))
|
||||
|
||||
bf.WriteBool(true) // Unk
|
||||
bf.WriteBool(false) // Cafe-only
|
||||
|
||||
bf.WriteUint32(0) // Min HR
|
||||
bf.WriteUint32(0) // Max HR
|
||||
|
||||
ps.Uint8(bf, "Test", false)
|
||||
|
||||
// ...
|
||||
bf.WriteUint32(uint32(len(tournamentInfo0)))
|
||||
for _, tinfo := range tournamentInfo0 {
|
||||
bf.WriteUint32(tinfo.ID)
|
||||
bf.WriteUint32(tinfo.MaxPlayers)
|
||||
bf.WriteUint32(tinfo.CurrentPlayers)
|
||||
bf.WriteUint16(tinfo.Unk1)
|
||||
bf.WriteUint16(tinfo.TextColor)
|
||||
bf.WriteUint32(tinfo.Unk2)
|
||||
bf.WriteUint32(uint32(tinfo.Time1.Unix()))
|
||||
bf.WriteUint32(uint32(tinfo.Time2.Unix()))
|
||||
bf.WriteUint32(uint32(tinfo.Time3.Unix()))
|
||||
bf.WriteUint32(uint32(tinfo.Time4.Unix()))
|
||||
bf.WriteUint32(uint32(tinfo.Time5.Unix()))
|
||||
bf.WriteUint32(uint32(tinfo.Time6.Unix()))
|
||||
bf.WriteUint8(tinfo.Unk3)
|
||||
bf.WriteUint8(tinfo.Unk4)
|
||||
bf.WriteUint32(tinfo.MinHR)
|
||||
bf.WriteUint32(tinfo.MaxHR)
|
||||
ps.Uint8(bf, tinfo.Unk5, true)
|
||||
ps.Uint16(bf, tinfo.Unk6, true)
|
||||
}
|
||||
case 1:
|
||||
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
|
||||
bf.WriteUint32(0) // Registered ID
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteUint8(0)
|
||||
bf.WriteUint32(0)
|
||||
ps.Uint8(bf, "", true)
|
||||
case 2:
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteUint32(uint32(len(tournamentInfo21)))
|
||||
for _, info := range tournamentInfo21 {
|
||||
bf.WriteUint32(info.Unk0)
|
||||
bf.WriteUint32(info.Unk1)
|
||||
bf.WriteUint32(info.Unk2)
|
||||
bf.WriteUint8(info.Unk3)
|
||||
}
|
||||
bf.WriteUint32(uint32(len(tournamentInfo22)))
|
||||
for _, info := range tournamentInfo22 {
|
||||
bf.WriteUint32(info.Unk0)
|
||||
bf.WriteUint32(info.Unk1)
|
||||
bf.WriteUint32(info.Unk2)
|
||||
bf.WriteUint8(info.Unk3)
|
||||
ps.Uint8(bf, info.Unk4, true)
|
||||
}
|
||||
}
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfEntryTournament(s *Session, p mhfpacket.MHFPacket) {}
|
||||
func handleMsgMhfEntryTournament(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfEntryTournament)
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
|
||||
func handleMsgMhfAcquireTournament(s *Session, p mhfpacket.MHFPacket) {}
|
||||
type TournamentReward struct {
|
||||
Unk0 uint16
|
||||
Unk1 uint16
|
||||
Unk2 uint16
|
||||
}
|
||||
|
||||
func handleMsgMhfAcquireTournament(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfAcquireTournament)
|
||||
rewards := []TournamentReward{}
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint8(uint8(len(rewards)))
|
||||
for _, reward := range rewards {
|
||||
bf.WriteUint16(reward.Unk0)
|
||||
bf.WriteUint16(reward.Unk1)
|
||||
bf.WriteUint16(reward.Unk2)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user