From 1df961d2aac55f50b329752774da9b61e9507ceb Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 1 Sep 2022 20:40:31 +1000 Subject: [PATCH 01/95] update readme --- README.md | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 916c6db7a..57065532a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,21 @@ # Erupe Community Edition -This is a community upload of a community project. The amount of people who worked on it is innumerous, and hard to keep track of. Credits to Andoryuuta, Fist's Team, the French Team, Mai's Team and many others. No matter the relations, these files will remain public and open source, free for all to use and modify. +--- +## Setup +- If you are only looking to install Erupe, please use [a pre-compiled binary](https://github.com/ZeruLight/Erupe/releases/latest). +- If you want to modify or compile Erupe yourself please read on. +### Requirements +- [Go](https://go.dev/dl/) +- [PostgreSQL](https://www.postgresql.org/download/) +### Installation +1. Bring up a fresh database by using the [backup file attached with the latest release](https://github.com/ZeruLight/Erupe/releases/latest/download/Erupe.sql). +2. Run each script under [patch-schema](./patch-schema) as they introduce newer schema. +3. Edit [config.json](./config.json) such that the database password matches your PostgreSQL setup. +4. Run `go build` or `go run .` to compile Erupe. +### Note +- You will need to acquire and install the client files and quest binaries separately. +--- +# Resources +[Community FAQ Pastebin](https://pastebin.com/QqAwZSTC) -[A pastebin with various links, tips, and FAQ](https://pastebin.com/QqAwZSTC) - -[An upload for the quest and scenario files exists here](https://github.com/xl3lackout/MHFZ-Quest-Files) -(Over 300k+ files) +[Quests and Scenario Binary Files](https://github.com/xl3lackout/MHFZ-Quest-Files) From 1aa7bfdd51b398331c88ec892229b8dfdbd54423 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 1 Sep 2022 22:26:28 +1000 Subject: [PATCH 02/95] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 57065532a..a157aabe3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ # Erupe Community Edition - ---- ## Setup - If you are only looking to install Erupe, please use [a pre-compiled binary](https://github.com/ZeruLight/Erupe/releases/latest). - If you want to modify or compile Erupe yourself please read on. @@ -14,7 +12,6 @@ 4. Run `go build` or `go run .` to compile Erupe. ### Note - You will need to acquire and install the client files and quest binaries separately. ---- # Resources [Community FAQ Pastebin](https://pastebin.com/QqAwZSTC) From df1a4834ba95f06bd9e193481af1722988bc58aa Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 2 Sep 2022 20:28:58 +1000 Subject: [PATCH 03/95] fix airou dismissal --- server/channelserver/handlers_mercenary.go | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/server/channelserver/handlers_mercenary.go b/server/channelserver/handlers_mercenary.go index 31bc26249..66c7da046 100644 --- a/server/channelserver/handlers_mercenary.go +++ b/server/channelserver/handlers_mercenary.go @@ -236,19 +236,31 @@ func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) { return } bf := byteframe.NewByteFrameFromBytes(decomp) + save := byteframe.NewByteFrame() + var catsExist uint8 + save.WriteUint8(0) + cats := bf.ReadUint8() for i := 0; i < int(cats); i++ { dataLen := bf.ReadUint32() catID := bf.ReadUint32() if catID == 0 { - var nextID uint32 - _ = s.server.db.QueryRow("SELECT nextval('airou_id_seq')").Scan(&nextID) - bf.Seek(-4, io.SeekCurrent) - bf.WriteUint32(nextID) + _ = s.server.db.QueryRow("SELECT nextval('airou_id_seq')").Scan(&catID) + } + exists := bf.ReadBool() + data := bf.ReadBytes(uint(dataLen) - 5) + if exists { + catsExist++ + save.WriteUint32(dataLen) + save.WriteUint32(catID) + save.WriteBool(exists) + save.WriteBytes(data) } - _ = bf.ReadBytes(uint(dataLen) - 4) } - comp, err := nullcomp.Compress(bf.Data()) + save.WriteBytes(bf.DataFromCurrent()) + save.Seek(0, 0) + save.WriteUint8(catsExist) + comp, err := nullcomp.Compress(save.Data()) if err != nil { s.logger.Error("Failed to compress airou", zap.Error(err)) } else { From cd6561dd61b35fca3327b657a363eb1b0c8943a9 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 3 Sep 2022 19:49:39 +1000 Subject: [PATCH 04/95] rework guild operations --- network/mhfpacket/msg_mhf_operate_guild.go | 60 +++++++------- server/channelserver/handlers_guild.go | 93 ++++++++++------------ 2 files changed, 73 insertions(+), 80 deletions(-) diff --git a/network/mhfpacket/msg_mhf_operate_guild.go b/network/mhfpacket/msg_mhf_operate_guild.go index ea986cda2..f141796cb 100644 --- a/network/mhfpacket/msg_mhf_operate_guild.go +++ b/network/mhfpacket/msg_mhf_operate_guild.go @@ -1,39 +1,39 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) type OperateGuildAction uint8 const ( - OPERATE_GUILD_DISBAND = 0x01 - OPERATE_GUILD_APPLY = 0x02 - OPERATE_GUILD_LEAVE = 0x03 - OPERATE_GUILD_RESIGN = 0x04 - OPERATE_GUILD_SET_APPLICATION_DENY = 0x05 - OPERATE_GUILD_SET_APPLICATION_ALLOW = 0x06 - OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE = 0x07 - OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE = 0x08 - OPERATE_GUILD_UPDATE_COMMENT = 0x09 - OPERATE_GUILD_DONATE_RANK = 0x0a - OPERATE_GUILD_UPDATE_MOTTO = 0x0b - OPERATE_GUILD_RENAME_PUGI_1 = 0x0c - OPERATE_GUILD_RENAME_PUGI_2 = 0x0d - OPERATE_GUILD_RENAME_PUGI_3 = 0x0e - OPERATE_GUILD_CHANGE_PUGI_1 = 0x0f - OPERATE_GUILD_CHANGE_PUGI_2 = 0x10 - OPERATE_GUILD_CHANGE_PUGI_3 = 0x11 - // pugi something - OPERATE_GUILD_DONATE_EVENT = 0x15 - // pugi something - OPERATE_GUILD_CHANGE_DIVA_PUGI_1 = 0x19 - OPERATE_GUILD_CHANGE_DIVA_PUGI_2 = 0x1a - OPERATE_GUILD_CHANGE_DIVA_PUGI_3 = 0x1b + OPERATE_GUILD_DISBAND = 0x01 + OPERATE_GUILD_APPLY = 0x02 + OPERATE_GUILD_LEAVE = 0x03 + OPERATE_GUILD_RESIGN = 0x04 + OPERATE_GUILD_SET_APPLICATION_DENY = 0x05 + OPERATE_GUILD_SET_APPLICATION_ALLOW = 0x06 + OPERATE_GUILD_SET_AVOID_LEADERSHIP_TRUE = 0x07 + OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE = 0x08 + OPERATE_GUILD_UPDATE_COMMENT = 0x09 + OPERATE_GUILD_DONATE_RANK = 0x0a + OPERATE_GUILD_UPDATE_MOTTO = 0x0b + OPERATE_GUILD_RENAME_PUGI_1 = 0x0c + OPERATE_GUILD_RENAME_PUGI_2 = 0x0d + OPERATE_GUILD_RENAME_PUGI_3 = 0x0e + OPERATE_GUILD_CHANGE_PUGI_1 = 0x0f + OPERATE_GUILD_CHANGE_PUGI_2 = 0x10 + OPERATE_GUILD_CHANGE_PUGI_3 = 0x11 + // pugi something + OPERATE_GUILD_DONATE_EVENT = 0x15 + OPERATE_GUILD_EVENT_EXCHANGE = 0x16 + OPERATE_GUILD_CHANGE_DIVA_PUGI_1 = 0x19 + OPERATE_GUILD_CHANGE_DIVA_PUGI_2 = 0x1a + OPERATE_GUILD_CHANGE_DIVA_PUGI_3 = 0x1b ) // MsgMhfOperateGuild represents the MSG_MHF_OPERATE_GUILD @@ -41,7 +41,8 @@ type MsgMhfOperateGuild struct { AckHandle uint32 GuildID uint32 Action OperateGuildAction - UnkData []byte + Data1 *byteframe.ByteFrame + Data2 *byteframe.ByteFrame } // Opcode returns the ID associated with this packet type. @@ -54,8 +55,9 @@ func (m *MsgMhfOperateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien m.AckHandle = bf.ReadUint32() m.GuildID = bf.ReadUint32() m.Action = OperateGuildAction(bf.ReadUint8()) - m.UnkData = bf.DataFromCurrent() - bf.Seek(int64(len(bf.Data()) - 2), 0) + dataLen := uint(bf.ReadUint8()) + m.Data1 = byteframe.NewByteFrameFromBytes(bf.ReadBytes(4)) + m.Data2 = byteframe.NewByteFrameFromBytes(bf.ReadBytes(dataLen)) return nil } diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 6bbee7eba..327f35781 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -634,11 +634,8 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { } bf.WriteUint32(uint32(response)) - doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) - return case mhfpacket.OPERATE_GUILD_RESIGN: guildMembers, err := GetGuildMembers(s, guild.ID, false) - success := false if err == nil { sort.Slice(guildMembers[:], func(i, j int) bool { return guildMembers[i].OrderIndex < guildMembers[j].OrderIndex @@ -651,29 +648,17 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { guildMembers[0].Save(s) guildMembers[i].Save(s) bf.WriteUint32(guildMembers[i].CharID) - success = true break } } guild.Save(s) - doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } - if !success { - bf.WriteUint32(0) - doAckBufSucceed(s, pkt.AckHandle, bf.Data()) - } - return case mhfpacket.OPERATE_GUILD_APPLY: err = guild.CreateApplication(s, s.charID, GuildApplicationTypeApplied, nil) - if err != nil { - // All successful acks return 0x01, assuming 0x00 is failure - bf.WriteUint32(0x00) - } else { + if err == nil { bf.WriteUint32(guild.LeaderCharID) } - doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) - return case mhfpacket.OPERATE_GUILD_LEAVE: var err error @@ -698,10 +683,8 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { } bf.WriteUint32(uint32(response)) - doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) - return case mhfpacket.OPERATE_GUILD_DONATE_RANK: - handleDonateRP(s, pkt, bf, guild, false) + bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, false)) case mhfpacket.OPERATE_GUILD_SET_APPLICATION_DENY: s.server.db.Exec("UPDATE guilds SET recruiting=false WHERE id=$1", guild.ID) case mhfpacket.OPERATE_GUILD_SET_APPLICATION_ALLOW: @@ -711,46 +694,55 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { case mhfpacket.OPERATE_GUILD_SET_AVOID_LEADERSHIP_FALSE: handleAvoidLeadershipUpdate(s, pkt, false) case mhfpacket.OPERATE_GUILD_UPDATE_COMMENT: - pbf := byteframe.NewByteFrameFromBytes(pkt.UnkData) if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return } - _ = pbf.ReadUint8() // len - _ = pbf.ReadUint32() - guild.Comment = stringsupport.SJISToUTF8(pbf.ReadNullTerminatedBytes()) + guild.Comment = stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes()) guild.Save(s) case mhfpacket.OPERATE_GUILD_UPDATE_MOTTO: if !characterGuildInfo.IsLeader && !characterGuildInfo.IsSubLeader() { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return } - guild.SubMotto = pkt.UnkData[3] - guild.MainMotto = pkt.UnkData[4] + _ = pkt.Data1.ReadUint16() + guild.SubMotto = pkt.Data1.ReadUint8() + guild.MainMotto = pkt.Data1.ReadUint8() guild.Save(s) case mhfpacket.OPERATE_GUILD_RENAME_PUGI_1: - handleRenamePugi(s, pkt.UnkData, guild, 1) + handleRenamePugi(s, pkt.Data2, guild, 1) case mhfpacket.OPERATE_GUILD_RENAME_PUGI_2: - handleRenamePugi(s, pkt.UnkData, guild, 2) + handleRenamePugi(s, pkt.Data2, guild, 2) case mhfpacket.OPERATE_GUILD_RENAME_PUGI_3: - handleRenamePugi(s, pkt.UnkData, guild, 3) + handleRenamePugi(s, pkt.Data2, guild, 3) case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_1: // TODO: decode guild poogie outfits case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_2: case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_3: case mhfpacket.OPERATE_GUILD_DONATE_EVENT: - handleDonateRP(s, pkt, bf, guild, true) + bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, true)) + case mhfpacket.OPERATE_GUILD_EVENT_EXCHANGE: + rp := uint16(pkt.Data1.ReadUint32()) + saveData, _ := GetCharacterSaveData(s, s.charID) + saveData.RP -= rp + transaction, err := s.server.db.Begin() + err = saveData.Save(s, transaction) + if err != nil { + transaction.Rollback() + } + bf.WriteUint32(uint32(saveData.RP)) default: panic(fmt.Sprintf("unhandled operate guild action '%d'", pkt.Action)) } - doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + if len(bf.Data()) > 0 { + doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) + } else { + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + } } -func handleRenamePugi(s *Session, data []byte, guild *Guild, num int) { - bf := byteframe.NewByteFrameFromBytes(data) - _ = bf.ReadUint8() // len - _ = bf.ReadUint32() // unk +func handleRenamePugi(s *Session, bf *byteframe.ByteFrame, guild *Guild, num int) { name := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) switch num { case 1: @@ -763,33 +755,30 @@ func handleRenamePugi(s *Session, data []byte, guild *Guild, num int) { guild.Save(s) } -func handleDonateRP(s *Session, pkt *mhfpacket.MsgMhfOperateGuild, bf *byteframe.ByteFrame, guild *Guild, isEvent bool) error { - rp := binary.BigEndian.Uint16(pkt.UnkData[3:5]) +func handleDonateRP(s *Session, amount uint16, guild *Guild, isEvent bool) []byte { + bf := byteframe.NewByteFrame() + bf.WriteUint32(0) saveData, err := GetCharacterSaveData(s, s.charID) if err != nil { - return err + return bf.Data() } - saveData.RP -= rp + saveData.RP -= amount transaction, err := s.server.db.Begin() err = saveData.Save(s, transaction) if err != nil { transaction.Rollback() - return err + return bf.Data() + } else { + transaction.Commit() } updateSQL := "UPDATE guilds SET rank_rp = rank_rp + $1 WHERE id = $2" if isEvent { updateSQL = "UPDATE guilds SET event_rp = event_rp + $1 WHERE id = $2" } - _, err = s.server.db.Exec(updateSQL, rp, guild.ID) - if err != nil { - s.logger.Error("Failed to donate rank RP to guild", zap.Error(err), zap.Uint32("guildID", guild.ID)) - transaction.Rollback() - return err - } else { - transaction.Commit() - } + s.server.db.Exec(updateSQL, amount, guild.ID) + bf.Seek(0, 0) bf.WriteUint32(uint32(saveData.RP)) - return nil + return bf.Data() } func handleAvoidLeadershipUpdate(s *Session, pkt *mhfpacket.MsgMhfOperateGuild, avoidLeadership bool) { @@ -1712,9 +1701,11 @@ func handleMsgMhfGetGuildWeeklyBonusMaster(s *Session, p mhfpacket.MHFPacket) { } func handleMsgMhfGetGuildWeeklyBonusActiveCount(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetGuildWeeklyBonusActiveCount) - - // Values taken from brand new guild capture - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 0x03)) + bf := byteframe.NewByteFrame() + bf.WriteUint8(0x3C) // Active count + bf.WriteUint8(0x3C) // Current active count + bf.WriteUint8(0x00) // New active count + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) { From 90314fa411d8a8370dfbf0801dd5b0f99da959c1 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 4 Sep 2022 03:19:32 +1000 Subject: [PATCH 05/95] rework savedata --- server/channelserver/handlers.go | 12 +- server/channelserver/handlers_character.go | 135 +++++++++++---------- server/channelserver/handlers_data.go | 60 ++++----- server/channelserver/handlers_guild.go | 15 +-- 4 files changed, 101 insertions(+), 121 deletions(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 6c49ba0af..e5476ca5f 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -235,17 +235,11 @@ func logoutPlayer(s *Session) { saveData, err := GetCharacterSaveData(s, s.charID) if err != nil { - panic(err) + s.logger.Error("Failed to get savedata") + return } saveData.RP += uint16(rpGained) - transaction, err := s.server.db.Begin() - err = saveData.Save(s, transaction) - if err != nil { - transaction.Rollback() - panic(err) - } else { - transaction.Commit() - } + saveData.Save(s) } func handleMsgSysSetStatus(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index b712f960e..aa3ab5e72 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -1,7 +1,6 @@ package channelserver import ( - "database/sql" "encoding/binary" "erupe-ce/network/mhfpacket" @@ -10,120 +9,134 @@ import ( ) const ( - CharacterSaveRPPointer = 0x22D16 + pointerGender = 0x81 // +1 + pointerRP = 0x22D16 // +2 + pointerHouseTier = 0x1FB6C // +5 + pointerHouseData = 0x1FE01 // +195 + pointerBookshelfData = 0x22298 // +5576 + // Gallery data also exists at 0x21578, is this the contest submission? + pointerGalleryData = 0x22320 // +1748 + pointerToreData = 0x1FCB4 // +240 + pointerGardenData = 0x22C58 // +68 + pointerWeaponID = 0x1F60A // +2 + pointerHRP = 0x1FDF6 // +2 + pointerGRP = 0x1FDFC // +4 ) type CharacterSaveData struct { CharID uint32 Name string - RP uint16 IsNewCharacter bool - // Use provided setter/getter - baseSaveData []byte + Gender bool + RP uint16 + HouseTier []byte + HouseData []byte + BookshelfData []byte + GalleryData []byte + ToreData []byte + GardenData []byte + WeaponID uint16 + HRP uint16 + GRP uint32 + GR uint16 + + compSave []byte + decompSave []byte } func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error) { result, err := s.server.db.Query("SELECT id, savedata, is_new_character, name FROM characters WHERE id = $1", charID) - if err != nil { - s.logger.Error("failed to retrieve save data for character", zap.Error(err), zap.Uint32("charID", charID)) + s.logger.Error("Failed to get savedata", zap.Error(err), zap.Uint32("charID", charID)) return nil, err } - defer result.Close() + if !result.Next() { + s.logger.Error("No savedata found", zap.Uint32("charID", charID)) + return nil, err + } saveData := &CharacterSaveData{} - var compressedBaseSave []byte - - if !result.Next() { - s.logger.Error("no results found for character save data", zap.Uint32("charID", charID)) - return nil, err - } - - err = result.Scan(&saveData.CharID, &compressedBaseSave, &saveData.IsNewCharacter, &saveData.Name) - + err = result.Scan(&saveData.CharID, &saveData.compSave, &saveData.IsNewCharacter, &saveData.Name) if err != nil { - s.logger.Error( - "failed to retrieve save data for character", - zap.Error(err), - zap.Uint32("charID", charID), - ) - + s.logger.Error("Failed to scan savedata", zap.Error(err), zap.Uint32("charID", charID)) return nil, err } - if compressedBaseSave == nil { + if saveData.compSave == nil { return saveData, nil } - decompressedBaseSave, err := nullcomp.Decompress(compressedBaseSave) - + err = saveData.Decompress() if err != nil { - s.logger.Error("Failed to decompress savedata from db", zap.Error(err)) + s.logger.Error("Failed to decompress savedata", zap.Error(err)) return nil, err } - saveData.SetBaseSaveData(decompressedBaseSave) - return saveData, nil } -func (save *CharacterSaveData) Save(s *Session, transaction *sql.Tx) error { +func (save *CharacterSaveData) Save(s *Session) { // We need to update the save data byte array before we save it back to the DB save.updateSaveDataWithStruct() - compressedData, err := save.CompressedBaseData(s) - + err := save.Compress() if err != nil { - return err + s.logger.Error("Failed to compress savedata", zap.Error(err)) + return } - updateSQL := "UPDATE characters SET savedata=$1, is_new_character=$3 WHERE id=$2" + updateSQL := `UPDATE characters SET savedata=$1, is_new_character=$3 WHERE id=$2` - if transaction != nil { - _, err = transaction.Exec(updateSQL, compressedData, save.CharID, save.IsNewCharacter) - } else { - _, err = s.server.db.Exec(updateSQL, compressedData, save.CharID, save.IsNewCharacter) - } + _, err = s.server.db.Exec(updateSQL, save.compSave, save.CharID, save.IsNewCharacter) + if err != nil { + s.logger.Error("Failed to update savedata", zap.Error(err), zap.Uint32("charID", save.CharID)) + } +} + +func (save *CharacterSaveData) Compress() error { + var err error + save.compSave, err = nullcomp.Compress(save.decompSave) if err != nil { - s.logger.Error("failed to save character data", zap.Error(err), zap.Uint32("charID", save.CharID)) return err } return nil } -func (save *CharacterSaveData) CompressedBaseData(s *Session) ([]byte, error) { - compressedData, err := nullcomp.Compress(save.baseSaveData) - +func (save *CharacterSaveData) Decompress() error { + var err error + save.decompSave, err = nullcomp.Decompress(save.compSave) if err != nil { - s.logger.Error("failed to compress saveData", zap.Error(err), zap.Uint32("charID", save.CharID)) - return nil, err + return err } - return compressedData, nil + return nil } -func (save *CharacterSaveData) BaseSaveData() []byte { - return save.baseSaveData -} - -func (save *CharacterSaveData) SetBaseSaveData(data []byte) { - save.baseSaveData = data - // After setting the new save byte array, we can extract the values to update our struct - // This will be useful when we save it back, we use the struct values to overwrite the saveData - save.updateStructWithSaveData() -} - -// This will update the save struct with the values stored in the raw savedata arrays +// This will update the character save with the values stored in the save struct func (save *CharacterSaveData) updateSaveDataWithStruct() { rpBytes := make([]byte, 2) binary.LittleEndian.PutUint16(rpBytes, save.RP) - copy(save.baseSaveData[CharacterSaveRPPointer:CharacterSaveRPPointer+2], rpBytes) + copy(save.decompSave[pointerRP:pointerRP+2], rpBytes) } -// This will update the character save struct with the values stored in the raw savedata arrays +// This will update the save struct with the values stored in the character save func (save *CharacterSaveData) updateStructWithSaveData() { - save.RP = binary.LittleEndian.Uint16(save.baseSaveData[CharacterSaveRPPointer : CharacterSaveRPPointer+2]) + if save.decompSave[pointerGender] == 1 { + save.Gender = true + } else { + save.Gender = false + } + save.RP = binary.LittleEndian.Uint16(save.decompSave[pointerRP : pointerRP+2]) + save.HouseTier = save.decompSave[pointerHouseTier : pointerHouseTier+5] + save.HouseData = save.decompSave[pointerHouseData : pointerHouseData+195] + save.BookshelfData = save.decompSave[pointerBookshelfData : pointerBookshelfData+5576] + save.GalleryData = save.decompSave[pointerGalleryData : pointerGalleryData+1748] + save.ToreData = save.decompSave[pointerToreData : pointerToreData+240] + save.GardenData = save.decompSave[pointerGardenData : pointerGardenData+68] + save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[pointerWeaponID : pointerWeaponID+2]) + save.HRP = binary.LittleEndian.Uint16(save.decompSave[pointerHRP : pointerHRP+2]) + save.GRP = binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4]) } func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) { diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 8ed55c54a..048aaff73 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -1,7 +1,6 @@ package channelserver import ( - "encoding/binary" "encoding/hex" "erupe-ce/common/stringsupport" "fmt" @@ -26,7 +25,6 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { return } // Var to hold the decompressed savedata for updating the launcher response fields. - var decompressedData []byte if pkt.SaveType == 1 { // Diff-based update. // diffs themselves are also potentially compressed @@ -36,43 +34,35 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { } // Perform diff. s.logger.Info("Diffing...") - characterSaveData.SetBaseSaveData(deltacomp.ApplyDataDiff(diff, characterSaveData.BaseSaveData())) + characterSaveData.decompSave = deltacomp.ApplyDataDiff(diff, characterSaveData.decompSave) } else { + dumpSaveData(s, pkt.RawDataPayload, "savedata") // Regular blob update. saveData, err := nullcomp.Decompress(pkt.RawDataPayload) if err != nil { s.logger.Fatal("Failed to decompress savedata from packet", zap.Error(err)) } s.logger.Info("Updating save with blob") - characterSaveData.SetBaseSaveData(saveData) + characterSaveData.decompSave = saveData } characterSaveData.IsNewCharacter = false - characterBaseSaveData := characterSaveData.BaseSaveData() - // Make a copy for updating the launcher fields. - decompressedData = make([]byte, len(characterBaseSaveData)) - copy(decompressedData, characterBaseSaveData) - err = characterSaveData.Save(s, nil) - if err != nil { - s.logger.Fatal("Failed to update savedata in db", zap.Error(err)) - } + characterSaveData.Save(s) s.logger.Info("Wrote recompressed savedata back to DB.") - dumpSaveData(s, pkt.RawDataPayload, "savedata") - _, err = s.server.db.Exec("UPDATE characters SET weapon_type=$1 WHERE id=$2", uint16(decompressedData[128789]), s.charID) + _, err = s.server.db.Exec("UPDATE characters SET weapon_type=$1 WHERE id=$2", uint16(characterSaveData.decompSave[128789]), s.charID) if err != nil { s.logger.Fatal("Failed to character weapon type in db", zap.Error(err)) } - s.myseries.houseTier = decompressedData[129900:129905] // 0x1FB6C + 5 - s.myseries.houseData = decompressedData[130561:130756] // 0x1FE01 + 195 - s.myseries.bookshelfData = decompressedData[139928:145504] // 0x22298 + 5576 - // Gallery data also exists at 0x21578, is this the contest submission? - s.myseries.galleryData = decompressedData[140064:141812] // 0x22320 + 1748 - s.myseries.toreData = decompressedData[130228:130468] // 0x1FCB4 + 240 - s.myseries.gardenData = decompressedData[142424:142492] // 0x22C58 + 68 + s.myseries.houseTier = characterSaveData.HouseTier + s.myseries.houseData = characterSaveData.HouseData + s.myseries.bookshelfData = characterSaveData.BookshelfData + s.myseries.galleryData = characterSaveData.GalleryData + s.myseries.toreData = characterSaveData.ToreData + s.myseries.gardenData = characterSaveData.GardenData - isFemale := decompressedData[81] // 0x51 - if isFemale == 1 { + isFemale := characterSaveData.Gender + if isFemale { _, err = s.server.db.Exec("UPDATE characters SET is_female=true WHERE id=$1", s.charID) } else { _, err = s.server.db.Exec("UPDATE characters SET is_female=false WHERE id=$1", s.charID) @@ -81,32 +71,26 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { s.logger.Fatal("Failed to character gender in db", zap.Error(err)) } - weaponId := binary.LittleEndian.Uint16(decompressedData[128522:128524]) // 0x1F60A - _, err = s.server.db.Exec("UPDATE characters SET weapon_id=$1 WHERE id=$2", weaponId, s.charID) + _, err = s.server.db.Exec("UPDATE characters SET weapon_id=$1 WHERE id=$2", characterSaveData.WeaponID, s.charID) if err != nil { s.logger.Fatal("Failed to update character weapon id in db", zap.Error(err)) } - hrp := binary.LittleEndian.Uint16(decompressedData[130550:130552]) // 0x1FDF6 - _, err = s.server.db.Exec("UPDATE characters SET hrp=$1 WHERE id=$2", hrp, s.charID) + _, err = s.server.db.Exec("UPDATE characters SET hrp=$1 WHERE id=$2", characterSaveData.HRP, s.charID) if err != nil { s.logger.Fatal("Failed to update character hrp in db", zap.Error(err)) } - grp := binary.LittleEndian.Uint32(decompressedData[130556:130560]) // 0x1FDFC - var gr uint16 - if grp > 0 { - gr = grpToGR(grp) - } else { - gr = 0 + if characterSaveData.GRP > 0 { + characterSaveData.GR = grpToGR(characterSaveData.GRP) } - _, err = s.server.db.Exec("UPDATE characters SET gr=$1 WHERE id=$2", gr, s.charID) + _, err = s.server.db.Exec("UPDATE characters SET gr=$1 WHERE id=$2", characterSaveData.GR, s.charID) if err != nil { s.logger.Fatal("Failed to update character gr in db", zap.Error(err)) } - characterName := s.clientContext.StrConv.MustDecode(bfutil.UpToNull(decompressedData[88:100])) - _, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterName, s.charID) + characterSaveData.Name = s.clientContext.StrConv.MustDecode(bfutil.UpToNull(characterSaveData.decompSave[88:100])) + _, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterSaveData.Name, s.charID) if err != nil { s.logger.Fatal("Failed to update character name in db", zap.Error(err)) } @@ -320,7 +304,7 @@ func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSaveScenarioData) - _, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE characters.id = $2", pkt.RawDataPayload, int(s.charID)) + _, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE id = $2", pkt.RawDataPayload, s.charID) if err != nil { s.logger.Fatal("Failed to update scenario data in db", zap.Error(err)) } @@ -337,7 +321,7 @@ func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoadScenarioData) var scenarioData []byte bf := byteframe.NewByteFrame() - err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE characters.id = $1", int(s.charID)).Scan(&scenarioData) + err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE id = $1", s.charID).Scan(&scenarioData) if err != nil { s.logger.Fatal("Failed to get scenario data contents in db", zap.Error(err)) } else { diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 327f35781..f34005a66 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -725,11 +725,7 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { rp := uint16(pkt.Data1.ReadUint32()) saveData, _ := GetCharacterSaveData(s, s.charID) saveData.RP -= rp - transaction, err := s.server.db.Begin() - err = saveData.Save(s, transaction) - if err != nil { - transaction.Rollback() - } + saveData.Save(s) bf.WriteUint32(uint32(saveData.RP)) default: panic(fmt.Sprintf("unhandled operate guild action '%d'", pkt.Action)) @@ -763,14 +759,7 @@ func handleDonateRP(s *Session, amount uint16, guild *Guild, isEvent bool) []byt return bf.Data() } saveData.RP -= amount - transaction, err := s.server.db.Begin() - err = saveData.Save(s, transaction) - if err != nil { - transaction.Rollback() - return bf.Data() - } else { - transaction.Commit() - } + saveData.Save(s) updateSQL := "UPDATE guilds SET rank_rp = rank_rp + $1 WHERE id = $2" if isEvent { updateSQL = "UPDATE guilds SET event_rp = event_rp + $1 WHERE id = $2" From 2e6aa1f1e4d0fa5b04305fa098dcaa0249993e8d Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 4 Sep 2022 03:32:43 +1000 Subject: [PATCH 06/95] remove unused config options --- config.json | 1 - config/config.go | 7 +------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/config.json b/config.json index 00e541adf..6c3b4ecd6 100644 --- a/config.json +++ b/config.json @@ -4,7 +4,6 @@ "DisableSoftCrash": false, "devmode": true, "devmodeoptions": { - "serverName" : "", "EnableLauncherServer": false, "hideLoginNotice": false, "loginNotice": "
Welcome to Erupe SU9.1 Beta!
Erupe is experimental software, we are not liable for any
issues caused by installing the software!

■Report bugs on Discord!

■Test everything!

■Don't talk to softlocking NPCs!

■Fork the code on GitHub!

Thank you to all of the contributors,

this wouldn't exist without you.", diff --git a/config/config.go b/config/config.go index bfbf8086a..33bf22abe 100644 --- a/config/config.go +++ b/config/config.go @@ -24,13 +24,11 @@ type Config struct { // DevModeOptions holds various debug/temporary options for use while developing Erupe. type DevModeOptions struct { - ServerName string // To get specific instance server about (Current Players/Event Week) EnableLauncherServer bool // Enables the launcher server to be served on port 80 HideLoginNotice bool // Hide the Erupe notice on login LoginNotice string // MHFML string of the login notice displayed CleanDB bool // Automatically wipes the DB on server reset. - MaxLauncherHR bool // Sets the HR returned in the launcher to HR9 so that you can join non-beginner worlds. - FixedStageID bool // Causes all move_stage to use the ID sl1Ns200p0a0u0 to get you into all stages + MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds. LogInboundMessages bool // Log all messages sent to the server LogOutboundMessages bool // Log all messages sent to the clients MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled @@ -53,10 +51,7 @@ type SaveDumpOptions struct { type Discord struct { Enabled bool BotToken string - ServerID string RealtimeChannelID string - DevRoles []string - DevMode bool } // Database holds the postgres database config. From dc874877d729498225dbc74c5cb5898db2ac1bf4 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sun, 4 Sep 2022 01:16:15 -0400 Subject: [PATCH 07/95] Added world_name and land columns to the servers table to provide easier identification for external and internal applications utilizing the database --- main.go | 6 +++++- patch-schema/servers_info.sql | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 patch-schema/servers_info.sql diff --git a/main.go b/main.go index b9dc62538..b222e0ec9 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,7 @@ import ( "erupe-ce/server/entranceserver" "erupe-ce/server/launcherserver" "erupe-ce/server/signserver" + "github.com/jmoiron/sqlx" _ "github.com/lib/pq" "go.uber.org/zap" @@ -173,6 +174,8 @@ func main() { ci := 0 count := 1 for _, ee := range erupeConfig.Entrance.Entries { + cn := 1 + for _, ce := range ee.Channels { sid := (4096 + si*256) + (16 + ci) c := *channelserver.NewServer(&channelserver.Config{ @@ -192,12 +195,13 @@ func main() { if err != nil { preventClose(fmt.Sprintf("Failed to start channel server: %s", err.Error())) } else { - channelQuery += fmt.Sprintf("INSERT INTO servers (server_id, season, current_players) VALUES (%d, %d, 0);", sid, si%3) + channelQuery += fmt.Sprintf("INSERT INTO servers (server_id, season, current_players, world_name, land) VALUES (%d, %d, 0, '%s', %d);", sid, si%3, ee.Name, cn) channels = append(channels, &c) logger.Info(fmt.Sprintf("Started channel server %d on port %d", count, ce.Port)) ci++ count++ } + cn++ } ci = 0 si++ diff --git a/patch-schema/servers_info.sql b/patch-schema/servers_info.sql new file mode 100644 index 000000000..6c24a035e --- /dev/null +++ b/patch-schema/servers_info.sql @@ -0,0 +1,10 @@ +--adds world_name and land columns + +CREATE TABLE IF NOT EXISTS public.servers +( + server_id integer NOT NULL, + season integer NOT NULL, + current_players integer NOT NULL, + world_name text COLLATE pg_catalog."default", + land integer +) \ No newline at end of file From 3ba56abfa8d98affe139ddf87f84df7e08816fba Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sun, 4 Sep 2022 01:48:38 -0400 Subject: [PATCH 08/95] Forgot to add alter lines if table already exists --- patch-schema/servers_info.sql | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/patch-schema/servers_info.sql b/patch-schema/servers_info.sql index 6c24a035e..b01672f89 100644 --- a/patch-schema/servers_info.sql +++ b/patch-schema/servers_info.sql @@ -7,4 +7,11 @@ CREATE TABLE IF NOT EXISTS public.servers current_players integer NOT NULL, world_name text COLLATE pg_catalog."default", land integer -) \ No newline at end of file +) + + +ALTER TABLE IF EXISTS public.servers + ADD COLUMN land integer; + +ALTER TABLE IF EXISTS public.servers + ADD COLUMN world_name text COLLATE pg_catalog."default"; \ No newline at end of file From 6c9e39a5cd68a77a2aa8c6181848f873f0111df1 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 4 Sep 2022 15:52:50 +1000 Subject: [PATCH 09/95] fix savedata bugs --- server/channelserver/handlers_character.go | 12 ++++--- server/channelserver/handlers_data.go | 40 ---------------------- 2 files changed, 7 insertions(+), 45 deletions(-) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index aa3ab5e72..825924508 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -18,6 +18,7 @@ const ( pointerGalleryData = 0x22320 // +1748 pointerToreData = 0x1FCB4 // +240 pointerGardenData = 0x22C58 // +68 + pointerWeaponType = 0x1F715 // +1 pointerWeaponID = 0x1F60A // +2 pointerHRP = 0x1FDF6 // +2 pointerGRP = 0x1FDFC // +4 @@ -36,9 +37,9 @@ type CharacterSaveData struct { GalleryData []byte ToreData []byte GardenData []byte + WeaponType uint8 WeaponID uint16 HRP uint16 - GRP uint32 GR uint16 compSave []byte @@ -80,6 +81,7 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error) func (save *CharacterSaveData) Save(s *Session) { // We need to update the save data byte array before we save it back to the DB save.updateSaveDataWithStruct() + save.updateStructWithSaveData() err := save.Compress() if err != nil { @@ -87,9 +89,8 @@ func (save *CharacterSaveData) Save(s *Session) { return } - updateSQL := `UPDATE characters SET savedata=$1, is_new_character=$3 WHERE id=$2` - - _, err = s.server.db.Exec(updateSQL, save.compSave, save.CharID, save.IsNewCharacter) + _, err = s.server.db.Exec(`UPDATE characters SET savedata=$1, is_new_character=$2, hrp=$3, gr=$4, is_female=$5, weapon_type=$6, weapon_id=$7 WHERE id=$8 + `, save.compSave, save.IsNewCharacter, save.HRP, save.GR, save.Gender, save.WeaponType, save.WeaponID, save.CharID) if err != nil { s.logger.Error("Failed to update savedata", zap.Error(err), zap.Uint32("charID", save.CharID)) } @@ -134,9 +135,10 @@ func (save *CharacterSaveData) updateStructWithSaveData() { save.GalleryData = save.decompSave[pointerGalleryData : pointerGalleryData+1748] save.ToreData = save.decompSave[pointerToreData : pointerToreData+240] save.GardenData = save.decompSave[pointerGardenData : pointerGardenData+68] + save.WeaponType = save.decompSave[pointerWeaponType] save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[pointerWeaponID : pointerWeaponID+2]) save.HRP = binary.LittleEndian.Uint16(save.decompSave[pointerHRP : pointerHRP+2]) - save.GRP = binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4]) + save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4])) } func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) { diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 048aaff73..57a2641f9 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -49,46 +49,6 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { characterSaveData.Save(s) s.logger.Info("Wrote recompressed savedata back to DB.") - _, err = s.server.db.Exec("UPDATE characters SET weapon_type=$1 WHERE id=$2", uint16(characterSaveData.decompSave[128789]), s.charID) - if err != nil { - s.logger.Fatal("Failed to character weapon type in db", zap.Error(err)) - } - - s.myseries.houseTier = characterSaveData.HouseTier - s.myseries.houseData = characterSaveData.HouseData - s.myseries.bookshelfData = characterSaveData.BookshelfData - s.myseries.galleryData = characterSaveData.GalleryData - s.myseries.toreData = characterSaveData.ToreData - s.myseries.gardenData = characterSaveData.GardenData - - isFemale := characterSaveData.Gender - if isFemale { - _, err = s.server.db.Exec("UPDATE characters SET is_female=true WHERE id=$1", s.charID) - } else { - _, err = s.server.db.Exec("UPDATE characters SET is_female=false WHERE id=$1", s.charID) - } - if err != nil { - s.logger.Fatal("Failed to character gender in db", zap.Error(err)) - } - - _, err = s.server.db.Exec("UPDATE characters SET weapon_id=$1 WHERE id=$2", characterSaveData.WeaponID, s.charID) - if err != nil { - s.logger.Fatal("Failed to update character weapon id in db", zap.Error(err)) - } - - _, err = s.server.db.Exec("UPDATE characters SET hrp=$1 WHERE id=$2", characterSaveData.HRP, s.charID) - if err != nil { - s.logger.Fatal("Failed to update character hrp in db", zap.Error(err)) - } - - if characterSaveData.GRP > 0 { - characterSaveData.GR = grpToGR(characterSaveData.GRP) - } - _, err = s.server.db.Exec("UPDATE characters SET gr=$1 WHERE id=$2", characterSaveData.GR, s.charID) - if err != nil { - s.logger.Fatal("Failed to update character gr in db", zap.Error(err)) - } - characterSaveData.Name = s.clientContext.StrConv.MustDecode(bfutil.UpToNull(characterSaveData.decompSave[88:100])) _, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterSaveData.Name, s.charID) if err != nil { From 925947631616326a222fee87c7b6c94cc2423033 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 4 Sep 2022 15:53:24 +1000 Subject: [PATCH 10/95] implement persistent house data --- patch-schema/persistent-house.sql | 19 +++ server/channelserver/handlers_character.go | 3 + server/channelserver/handlers_house.go | 157 ++++++++------------- server/channelserver/handlers_users.go | 8 +- 4 files changed, 88 insertions(+), 99 deletions(-) create mode 100644 patch-schema/persistent-house.sql diff --git a/patch-schema/persistent-house.sql b/patch-schema/persistent-house.sql new file mode 100644 index 000000000..ee26333ee --- /dev/null +++ b/patch-schema/persistent-house.sql @@ -0,0 +1,19 @@ +BEGIN; + +CREATE TABLE IF NOT EXISTS public.user_binary +( + id serial NOT NULL PRIMARY KEY, + type2 bytea, + type3 bytea, + house_tier bytea, + house_state int, + house_password text, + house_data bytea, + house_furniture bytea, + bookshelf bytea, + gallery bytea, + tore bytea, + garden bytea +); + +END; \ No newline at end of file diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index 825924508..13459bda9 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -94,6 +94,9 @@ func (save *CharacterSaveData) Save(s *Session) { if err != nil { s.logger.Error("Failed to update savedata", zap.Error(err), zap.Uint32("charID", save.CharID)) } + + s.server.db.Exec(`UPDATE user_binary SET house_tier=$1, house_data=$2, bookshelf=$3, gallery=$4, tore=$5, garden=$6 WHERE id=$7 + `, save.HouseTier, save.HouseData, save.BookshelfData, save.GalleryData, save.ToreData, save.GardenData, s.charID) } func (save *CharacterSaveData) Compress() error { diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index 280f27238..3198b4c88 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -38,24 +38,26 @@ FROM warehouse func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfUpdateInterior) - _, err := s.server.db.Exec("UPDATE characters SET house=$1 WHERE id=$2", pkt.InteriorData, s.charID) - if err != nil { - panic(err) - } + s.server.db.Exec(`UPDATE user_binary SET house_furniture=$1 WHERE id=$2`, pkt.InteriorData, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } type HouseData struct { - CharID uint32 `db:"id"` - HRP uint16 `db:"hrp"` - GR uint16 `db:"gr"` - Name string `db:"name"` + CharID uint32 `db:"id"` + HRP uint16 `db:"hrp"` + GR uint16 `db:"gr"` + Name string `db:"name"` + HouseState uint8 `db:"house_state"` + HousePassword string `db:"house_password"` } func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateHouse) bf := byteframe.NewByteFrame() + bf.WriteUint16(0) var houses []HouseData + houseQuery := `SELECT c.id, hrp, gr, name, COALESCE(ub.house_state, 2) as house_state, COALESCE(ub.house_password, '') as house_password + FROM characters c LEFT JOIN user_binary ub ON ub.id = c.id WHERE c.id=$1` switch pkt.Method { case 1: var friendsList string @@ -63,17 +65,15 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { cids := stringsupport.CSVElems(friendsList) for _, cid := range cids { house := HouseData{} - row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", cid) + row := s.server.db.QueryRowx(houseQuery, cid) err := row.StructScan(&house) - if err != nil { - panic(err) - } else { + if err == nil { houses = append(houses, house) } } case 2: guild, err := GetGuildInfoByCharacterId(s, s.charID) - if err != nil { + if err != nil || guild == nil { break } guildMembers, err := GetGuildMembers(s, guild.ID, false) @@ -82,58 +82,48 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { } for _, member := range guildMembers { house := HouseData{} - row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", member.CharID) - err := row.StructScan(&house) - if err != nil { - panic(err) - } else { + row := s.server.db.QueryRowx(houseQuery, member.CharID) + err = row.StructScan(&house) + if err == nil { houses = append(houses, house) } } case 3: + houseQuery = `SELECT c.id, hrp, gr, name, COALESCE(ub.house_state, 2) as house_state, COALESCE(ub.house_password, '') as house_password + FROM characters c LEFT JOIN user_binary ub ON ub.id = c.id WHERE name ILIKE $1` house := HouseData{} - row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE name ILIKE $1", fmt.Sprintf(`%%%s%%`, pkt.Name)) - err := row.StructScan(&house) - if err != nil { - panic(err) - } else { - houses = append(houses, house) + rows, _ := s.server.db.Queryx(houseQuery, fmt.Sprintf(`%%%s%%`, pkt.Name)) + for rows.Next() { + err := rows.StructScan(&house) + if err == nil { + houses = append(houses, house) + } } case 4: house := HouseData{} - row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", pkt.CharID) + row := s.server.db.QueryRowx(houseQuery, pkt.CharID) err := row.StructScan(&house) - if err != nil { - panic(err) - } else { + if err == nil { houses = append(houses, house) } case 5: // Recent visitors break } - var exists int for _, house := range houses { - for _, session := range s.server.sessions { - if session.charID == house.CharID { - exists++ - bf.WriteUint32(house.CharID) - bf.WriteUint8(session.myseries.state) - if len(session.myseries.password) > 0 { - bf.WriteUint8(3) - } else { - bf.WriteUint8(0) - } - bf.WriteUint16(house.HRP) - bf.WriteUint16(house.GR) - ps.Uint8(bf, house.Name, true) - break - } + bf.WriteUint32(house.CharID) + bf.WriteUint8(house.HouseState) + if len(house.HousePassword) > 0 { + bf.WriteUint8(3) + } else { + bf.WriteUint8(0) } + bf.WriteUint16(house.HRP) + bf.WriteUint16(house.GR) + ps.Uint8(bf, house.Name, true) } - resp := byteframe.NewByteFrame() - resp.WriteUint16(uint16(exists)) - resp.WriteBytes(bf.Data()) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + bf.Seek(0, 0) + bf.WriteUint16(uint16(len(houses))) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) { @@ -143,8 +133,7 @@ func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) { // 03 = open friends // 04 = open guild // 05 = open friends+guild - s.myseries.state = pkt.State - s.myseries.password = pkt.Password + s.server.db.Exec(`UPDATE user_binary SET house_state=$1, house_password=$2 WHERE id=$3`, pkt.State, pkt.Password, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } @@ -152,63 +141,41 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoadHouse) bf := byteframe.NewByteFrame() if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass { - for _, session := range s.server.sessions { - if session.charID == pkt.CharID && pkt.Password != session.myseries.password { - doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) - return - } + var password string + s.server.db.Select(&password, `SELECT house_password FROM user_binary WHERE id=$1`, pkt.CharID) + if pkt.Password != password { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return } } - var furniture []byte - err := s.server.db.QueryRow("SELECT house FROM characters WHERE id=$1", pkt.CharID).Scan(&furniture) - if err != nil { - panic(err) - } - if furniture == nil { - furniture = make([]byte, 20) + var houseTier, houseData, houseFurniture, bookshelf, gallery, tore, garden []byte + s.server.db.QueryRow(`SELECT house_tier, house_data, house_furniture, bookshelf, gallery, tore, garden FROM user_binary WHERE id=$1 + `, pkt.CharID).Scan(&houseTier, &houseData, &houseFurniture, &bookshelf, &gallery, &tore, &garden) + if houseFurniture == nil { + houseFurniture = make([]byte, 20) } switch pkt.Destination { case 3: // Others house - for _, session := range s.server.sessions { - if session.charID == pkt.CharID { - bf.WriteBytes(session.myseries.houseTier) - bf.WriteBytes(session.myseries.houseData) - bf.WriteBytes(make([]byte, 19)) // Padding? - bf.WriteBytes(furniture) - } - } + bf.WriteBytes(houseTier) + bf.WriteBytes(houseData) + bf.WriteBytes(make([]byte, 19)) // Padding? + bf.WriteBytes(houseFurniture) case 4: // Bookshelf - for _, session := range s.server.sessions { - if session.charID == pkt.CharID { - bf.WriteBytes(session.myseries.bookshelfData) - } - } + bf.WriteBytes(bookshelf) case 5: // Gallery - for _, session := range s.server.sessions { - if session.charID == pkt.CharID { - bf.WriteBytes(session.myseries.galleryData) - } - } + bf.WriteBytes(gallery) case 8: // Tore - for _, session := range s.server.sessions { - if session.charID == pkt.CharID { - bf.WriteBytes(session.myseries.toreData) - } - } + bf.WriteBytes(tore) case 9: // Own house - bf.WriteBytes(furniture) + bf.WriteBytes(houseFurniture) case 10: // Garden - for _, session := range s.server.sessions { - if session.charID == pkt.CharID { - bf.WriteBytes(session.myseries.gardenData) - c, d := getGookData(s, pkt.CharID) - bf.WriteUint16(c) - bf.WriteUint16(0) - bf.WriteBytes(d) - } - } + bf.WriteBytes(garden) + c, d := getGookData(s, pkt.CharID) + bf.WriteUint16(c) + bf.WriteUint16(0) + bf.WriteBytes(d) } if len(bf.Data()) == 0 { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) diff --git a/server/channelserver/handlers_users.go b/server/channelserver/handlers_users.go index 3bebcc97a..c360b82a6 100644 --- a/server/channelserver/handlers_users.go +++ b/server/channelserver/handlers_users.go @@ -17,12 +17,12 @@ func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) { s.server.userBinaryPartsLock.Unlock() var exists []byte - err := s.server.db.QueryRow("SELECT type2 FROM user_binaries WHERE id=$1", s.charID).Scan(&exists) + err := s.server.db.QueryRow("SELECT type2 FROM user_binary WHERE id=$1", s.charID).Scan(&exists) if err != nil { - s.server.db.Exec("INSERT INTO user_binaries (id) VALUES ($1)", s.charID) + s.server.db.Exec("INSERT INTO user_binary (id) VALUES ($1)", s.charID) } - s.server.db.Exec(fmt.Sprintf("UPDATE user_binaries SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.charID) + s.server.db.Exec(fmt.Sprintf("UPDATE user_binary SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.charID) msg := &mhfpacket.MsgSysNotifyUserBinary{ CharID: s.charID, @@ -42,7 +42,7 @@ func handleMsgSysGetUserBinary(s *Session, p mhfpacket.MHFPacket) { // If we can't get the real data, try to get it from the database. if !ok { - err := s.server.db.QueryRow(fmt.Sprintf("SELECT type%d FROM user_binaries WHERE id=$1", pkt.BinaryType), pkt.CharID).Scan(&data) + err := s.server.db.QueryRow(fmt.Sprintf("SELECT type%d FROM user_binary WHERE id=$1", pkt.BinaryType), pkt.CharID).Scan(&data) if err != nil { doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) } else { From 3c096fa8d7040408973beba44480bcd7433bc925 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sun, 4 Sep 2022 02:10:46 -0400 Subject: [PATCH 11/95] proper formating --- patch-schema/servers_info.sql | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/patch-schema/servers_info.sql b/patch-schema/servers_info.sql index b01672f89..c514b8e12 100644 --- a/patch-schema/servers_info.sql +++ b/patch-schema/servers_info.sql @@ -1,4 +1,5 @@ --adds world_name and land columns +BEGIN; CREATE TABLE IF NOT EXISTS public.servers ( @@ -14,4 +15,6 @@ ALTER TABLE IF EXISTS public.servers ADD COLUMN land integer; ALTER TABLE IF EXISTS public.servers - ADD COLUMN world_name text COLLATE pg_catalog."default"; \ No newline at end of file + ADD COLUMN world_name text COLLATE pg_catalog."default"; + +END; \ No newline at end of file From e0176ca774454a77eca9a1dde86b3f0703a0bd85 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 4 Sep 2022 16:40:06 +1000 Subject: [PATCH 12/95] indexing changes and add world description --- main.go | 7 ++----- patch-schema/servers_info.sql | 13 ++++++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/main.go b/main.go index b222e0ec9..a9c796f29 100644 --- a/main.go +++ b/main.go @@ -174,9 +174,7 @@ func main() { ci := 0 count := 1 for _, ee := range erupeConfig.Entrance.Entries { - cn := 1 - - for _, ce := range ee.Channels { + for i, ce := range ee.Channels { sid := (4096 + si*256) + (16 + ci) c := *channelserver.NewServer(&channelserver.Config{ ID: uint16(sid), @@ -195,13 +193,12 @@ func main() { if err != nil { preventClose(fmt.Sprintf("Failed to start channel server: %s", err.Error())) } else { - channelQuery += fmt.Sprintf("INSERT INTO servers (server_id, season, current_players, world_name, land) VALUES (%d, %d, 0, '%s', %d);", sid, si%3, ee.Name, cn) + channelQuery += fmt.Sprintf(`INSERT INTO servers (server_id, season, current_players, world_name, world_description, land) VALUES (%d, %d, 0, '%s', '%s', %d);`, sid, si%3, ee.Name, ee.Description, i+1) channels = append(channels, &c) logger.Info(fmt.Sprintf("Started channel server %d on port %d", count, ce.Port)) ci++ count++ } - cn++ } ci = 0 si++ diff --git a/patch-schema/servers_info.sql b/patch-schema/servers_info.sql index c514b8e12..06389b6ed 100644 --- a/patch-schema/servers_info.sql +++ b/patch-schema/servers_info.sql @@ -7,14 +7,17 @@ CREATE TABLE IF NOT EXISTS public.servers season integer NOT NULL, current_players integer NOT NULL, world_name text COLLATE pg_catalog."default", + world_description text, land integer -) +); +ALTER TABLE public.servers + ADD COLUMN IF NOT EXISTS land integer; -ALTER TABLE IF EXISTS public.servers - ADD COLUMN land integer; +ALTER TABLE public.servers + ADD COLUMN IF NOT EXISTS world_name text COLLATE pg_catalog."default"; -ALTER TABLE IF EXISTS public.servers - ADD COLUMN world_name text COLLATE pg_catalog."default"; +ALTER TABLE public.servers + ADD COLUMN IF NOT EXISTS world_description text; END; \ No newline at end of file From 377bb39be6298c5578b31fb875f0570f33480095 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 4 Sep 2022 17:45:05 +1000 Subject: [PATCH 13/95] fix house password checking --- server/channelserver/handlers_house.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index 3198b4c88..7d5bda529 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -142,7 +142,10 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass { var password string - s.server.db.Select(&password, `SELECT house_password FROM user_binary WHERE id=$1`, pkt.CharID) + err := s.server.db.Get(&password, `SELECT house_password FROM user_binary WHERE id=$1`, pkt.CharID) + if err != nil { + panic(err) + } if pkt.Password != password { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return From 670f8f7882fb2c8c03fcf8a2719656999b3ab740 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 4 Sep 2022 18:12:51 +1000 Subject: [PATCH 14/95] update schema to merge existing data, move trophy --- patch-schema/persistent-house.sql | 20 +++++++++++++++++++- server/channelserver/handlers_house.go | 14 +++----------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/patch-schema/persistent-house.sql b/patch-schema/persistent-house.sql index ee26333ee..43a02da91 100644 --- a/patch-schema/persistent-house.sql +++ b/patch-schema/persistent-house.sql @@ -13,7 +13,25 @@ CREATE TABLE IF NOT EXISTS public.user_binary bookshelf bytea, gallery bytea, tore bytea, - garden bytea + garden bytea, + mission bytea ); +-- Create entries for existing users +INSERT INTO public.user_binary (id) SELECT c.id FROM characters c; + +-- Copy existing data +UPDATE public.user_binary + SET house_furniture = (SELECT house FROM characters WHERE user_binary.id = characters.id); + +UPDATE public.user_binary + SET mission = (SELECT trophy FROM characters WHERE user_binary.id = characters.id); + +-- Drop old data location +ALTER TABLE public.characters + DROP COLUMN house; + +ALTER TABLE public.characters + DROP COLUMN trophy; + END; \ No newline at end of file diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index 7d5bda529..5236f197d 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -189,26 +189,18 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetMyhouseInfo) - var data []byte - err := s.server.db.QueryRow("SELECT trophy FROM characters WHERE id = $1", s.charID).Scan(&data) - if err != nil { - panic(err) - } + s.server.db.QueryRow(`SELECT mission FROM user_binary WHERE id=$1`, s.charID).Scan(&data) if len(data) > 0 { doAckBufSucceed(s, pkt.AckHandle, data) } else { - doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 9)) } } func handleMsgMhfUpdateMyhouseInfo(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfUpdateMyhouseInfo) - - _, err := s.server.db.Exec("UPDATE characters SET trophy=$1 WHERE id=$2", pkt.Unk0, s.charID) - if err != nil { - panic(err) - } + s.server.db.Exec("UPDATE user_binary SET mission=$1 WHERE id=$2", pkt.Unk0, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } From bb12a890743a677c6fb6edd835abe674276adbbd Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 5 Sep 2022 14:29:25 +1000 Subject: [PATCH 15/95] fix nil character data error --- server/channelserver/handlers_guild.go | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index f34005a66..cfdef3f15 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1005,17 +1005,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { } applicants, err := GetGuildMembers(s, guild.ID, true) - if err != nil { - resp := byteframe.NewByteFrame() - resp.WriteUint32(0) // Count - resp.WriteUint8(0) // Unk, read if count == 0. - - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - } - if err != nil || characterGuildData.IsApplicant { - bf.WriteUint16(0) - } else { bf.WriteUint16(uint16(len(applicants))) for _, applicant := range applicants { bf.WriteUint32(applicant.CharID) @@ -1025,9 +1015,11 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint16(applicant.GR) ps.Uint8(bf, applicant.Name, true) } + } else { + bf.WriteUint16(0) } - bf.WriteUint16(0x0000) + bf.WriteUint16(0x0000) // lenAllianceApplications /* alliance application format From 65d35a5188a082f6ef3138be73b01736ee879299 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 5 Sep 2022 14:34:48 +1000 Subject: [PATCH 16/95] dump navi savedata --- server/channelserver/handlers_mercenary.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/channelserver/handlers_mercenary.go b/server/channelserver/handlers_mercenary.go index 66c7da046..5e9e7b62e 100644 --- a/server/channelserver/handlers_mercenary.go +++ b/server/channelserver/handlers_mercenary.go @@ -104,6 +104,7 @@ func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) { s.logger.Info("Wrote recompressed hunternavi back to DB.") } else { + dumpSaveData(s, pkt.RawDataPayload, "hunternavi") // simply update database, no extra processing _, err := s.server.db.Exec("UPDATE characters SET hunternavi=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) if err != nil { From e38c8926140d73545e05761f37d2cc6b6d6bcffb Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 5 Sep 2022 15:24:07 +1000 Subject: [PATCH 17/95] fix guild application enumeration --- server/channelserver/handlers_guild.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index cfdef3f15..f7646926c 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1006,6 +1006,8 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { applicants, err := GetGuildMembers(s, guild.ID, true) if err != nil { + bf.WriteUint16(0) + } else { bf.WriteUint16(uint16(len(applicants))) for _, applicant := range applicants { bf.WriteUint32(applicant.CharID) @@ -1015,8 +1017,6 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint16(applicant.GR) ps.Uint8(bf, applicant.Name, true) } - } else { - bf.WriteUint16(0) } bf.WriteUint16(0x0000) // lenAllianceApplications From b1721684182545631572cf05ce3aedf671efa548 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 5 Sep 2022 15:26:57 +1000 Subject: [PATCH 18/95] implement proper house entry verification --- network/mhfpacket/msg_mhf_enumerate_house.go | 6 ++- server/channelserver/handlers_house.go | 47 +++++++++++++++++--- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/network/mhfpacket/msg_mhf_enumerate_house.go b/network/mhfpacket/msg_mhf_enumerate_house.go index 9bd1f30ef..da6a25de7 100644 --- a/network/mhfpacket/msg_mhf_enumerate_house.go +++ b/network/mhfpacket/msg_mhf_enumerate_house.go @@ -29,8 +29,10 @@ func (m *MsgMhfEnumerateHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli m.CharID = bf.ReadUint32() m.Method = bf.ReadUint8() m.Unk = bf.ReadUint16() - _ = bf.ReadUint8() // len - m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) + lenName := bf.ReadUint8() + if lenName > 0 { + m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) + } return nil } diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index 5236f197d..03d961ef3 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -140,18 +140,55 @@ func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoadHouse) bf := byteframe.NewByteFrame() + + var state uint8 + var password string + s.server.db.QueryRow(`SELECT COALESCE(house_state, 2) as house_state, COALESCE(house_password, '') as house_password FROM user_binary WHERE id=$1 + `, pkt.CharID).Scan(&state, &password) + if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass { - var password string - err := s.server.db.Get(&password, `SELECT house_password FROM user_binary WHERE id=$1`, pkt.CharID) - if err != nil { - panic(err) - } if pkt.Password != password { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return } } + if pkt.Destination != 9 && state > 2 { + allowed := false + + // Friends list verification + if state == 3 || state == 5 { + var friendsList string + s.server.db.QueryRow(`SELECT friends FROM characters WHERE id=$1`, pkt.CharID).Scan(&friendsList) + cids := stringsupport.CSVElems(friendsList) + for _, cid := range cids { + if uint32(cid) == s.charID { + allowed = true + break + } + } + } + + // Guild verification + if state > 3 { + ownGuild, err := GetGuildInfoByCharacterId(s, s.charID) + isApplicant, _ := ownGuild.HasApplicationForCharID(s, s.charID) + if err == nil && ownGuild != nil { + othersGuild, err := GetGuildInfoByCharacterId(s, pkt.CharID) + if err == nil && othersGuild != nil { + if othersGuild.ID == ownGuild.ID && !isApplicant { + allowed = true + } + } + } + } + + if !allowed { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return + } + } + var houseTier, houseData, houseFurniture, bookshelf, gallery, tore, garden []byte s.server.db.QueryRow(`SELECT house_tier, house_data, house_furniture, bookshelf, gallery, tore, garden FROM user_binary WHERE id=$1 `, pkt.CharID).Scan(&houseTier, &houseData, &houseFurniture, &bookshelf, &gallery, &tore, &garden) From 616d58e70e3e8025bc97ad1c373371a999906846 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 5 Sep 2022 15:29:24 +1000 Subject: [PATCH 19/95] dump other savedata types --- server/channelserver/handlers_data.go | 1 + server/channelserver/handlers_mercenary.go | 1 + server/channelserver/handlers_quest.go | 1 + 3 files changed, 3 insertions(+) diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 57a2641f9..ae0450419 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -264,6 +264,7 @@ func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSaveScenarioData) + dumpSaveData(s, pkt.RawDataPayload, "scenario") _, err := s.server.db.Exec("UPDATE characters SET scenariodata = $1 WHERE id = $2", pkt.RawDataPayload, s.charID) if err != nil { s.logger.Fatal("Failed to update scenario data in db", zap.Error(err)) diff --git a/server/channelserver/handlers_mercenary.go b/server/channelserver/handlers_mercenary.go index 5e9e7b62e..bdeb924de 100644 --- a/server/channelserver/handlers_mercenary.go +++ b/server/channelserver/handlers_mercenary.go @@ -163,6 +163,7 @@ func handleMsgMhfCreateMercenary(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveMercenary(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSaveMercenary) + dumpSaveData(s, pkt.MercData, "mercenary") if len(pkt.MercData) > 0 { s.server.db.Exec("UPDATE characters SET savemercenary=$1 WHERE id=$2", pkt.MercData, s.charID) } diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 86a0003b9..7ee552232 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -54,6 +54,7 @@ func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSaveFavoriteQuest) + dumpSaveData(s, pkt.Data, "favquest") s.server.db.Exec("UPDATE characters SET savefavoritequest=$1 WHERE id=$2", pkt.Data, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } From c60385e61f9052aea37ec421999b106e0c2cfe79 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 5 Sep 2022 15:36:01 +1000 Subject: [PATCH 20/95] dump other savedata types --- server/channelserver/handlers.go | 1 + server/channelserver/handlers_plate.go | 6 +++--- server/channelserver/handlers_rengoku.go | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index e5476ca5f..cf7aecba9 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -1772,6 +1772,7 @@ func handleMsgMhfGetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSetEnhancedMinidata) + dumpSaveData(s, pkt.RawDataPayload, "minidata") _, err := s.server.db.Exec("UPDATE characters SET minidata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) if err != nil { s.logger.Fatal("Failed to update minidata in db", zap.Error(err)) diff --git a/server/channelserver/handlers_plate.go b/server/channelserver/handlers_plate.go index 72121ef13..b1bfea5d2 100644 --- a/server/channelserver/handlers_plate.go +++ b/server/channelserver/handlers_plate.go @@ -25,7 +25,7 @@ func handleMsgMhfLoadPlateData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSavePlateData) - dumpSaveData(s, pkt.RawDataPayload, "_platedata") + dumpSaveData(s, pkt.RawDataPayload, "platedata") if pkt.IsDataDiff { var data []byte @@ -90,7 +90,7 @@ func handleMsgMhfLoadPlateBox(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSavePlateBox) - dumpSaveData(s, pkt.RawDataPayload, "_platebox") + dumpSaveData(s, pkt.RawDataPayload, "platebox") if pkt.IsDataDiff { var data []byte @@ -156,7 +156,7 @@ func handleMsgMhfLoadPlateMyset(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfSavePlateMyset(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSavePlateMyset) // looks to always return the full thing, simply update database, no extra processing - + dumpSaveData(s, pkt.RawDataPayload, "platemyset") _, err := s.server.db.Exec("UPDATE characters SET platemyset=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) if err != nil { s.logger.Fatal("Failed to update platemyset savedata in db", zap.Error(err)) diff --git a/server/channelserver/handlers_rengoku.go b/server/channelserver/handlers_rengoku.go index 6fdce7c22..9bfe464cf 100644 --- a/server/channelserver/handlers_rengoku.go +++ b/server/channelserver/handlers_rengoku.go @@ -15,6 +15,7 @@ func handleMsgMhfSaveRengokuData(s *Session, p mhfpacket.MHFPacket) { // saved every floor on road, holds values such as floors progressed, points etc. // can be safely handled by the client pkt := p.(*mhfpacket.MsgMhfSaveRengokuData) + dumpSaveData(s, pkt.RawDataPayload, "rengoku") _, err := s.server.db.Exec("UPDATE characters SET rengokudata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) if err != nil { s.logger.Fatal("Failed to update rengokudata savedata in db", zap.Error(err)) From 88815c0a05b84ed3a792dce7c7c2ef1c052b8a1e Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 5 Sep 2022 15:42:16 +1000 Subject: [PATCH 21/95] dump other savedata types --- server/channelserver/handlers.go | 1 + server/channelserver/handlers_house.go | 1 + 2 files changed, 2 insertions(+) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index cf7aecba9..2e348c138 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -1743,6 +1743,7 @@ func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) { byteInd := (bit / 8) bitInByte := bit % 8 data[startByte+byteInd] |= bits.Reverse8((1 << uint(bitInByte))) + dumpSaveData(s, data, "skinhist") _, err = s.server.db.Exec("UPDATE characters SET skin_hist=$1 WHERE id=$2", data, s.charID) if err != nil { panic(err) diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index 03d961ef3..b3aadf372 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -310,6 +310,7 @@ func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) { } loadData[1] = savedSets // update set count } + dumpSaveData(s, loadData, "decomyset") _, err := s.server.db.Exec("UPDATE characters SET decomyset=$1 WHERE id=$2", loadData, s.charID) if err != nil { s.logger.Fatal("Failed to update decomyset savedata in db", zap.Error(err)) From 580bfb12feeec68c32dccff6e011123c975639fd Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 8 Sep 2022 15:15:23 +1000 Subject: [PATCH 22/95] decode dsgn --- server/signserver/dsgn_resp.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go index a169d93a1..091abc687 100644 --- a/server/signserver/dsgn_resp.go +++ b/server/signserver/dsgn_resp.go @@ -112,14 +112,17 @@ func (s *Session) makeSignInResp(uid int) []byte { bf.WriteUint32(s.server.getLastCID(uid)) bf.WriteUint32(s.server.getUserRights(uid)) ps.Uint16(bf, "", false) // filters - bf.WriteUint32(0xCA104E20) - ps.Uint16(bf, "", false) // encryption + bf.WriteUint16(0xCA10) + bf.WriteUint16(0x4E20) + ps.Uint16(bf, "", false) // unk key bf.WriteUint8(0x00) - bf.WriteUint32(0xCA110001) - bf.WriteUint32(0x4E200000) + bf.WriteUint16(0xCA11) + bf.WriteUint16(0x0001) + bf.WriteUint16(0x4E20) + ps.Uint16(bf, "", false) // unk ipv4 bf.WriteUint32(uint32(returnExpiry.Unix())) bf.WriteUint32(0x00000000) - bf.WriteUint32(0x0A5197DF) + bf.WriteUint32(0x0A5197DF) // unk id mezfes := s.server.erupeConfig.DevModeOptions.MezFesEvent alt := s.server.erupeConfig.DevModeOptions.MezFesAlt From d81e55cab44b2de6f32741bab9187fa339b0e53d Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 8 Sep 2022 15:16:44 +1000 Subject: [PATCH 23/95] stub GetGemInfo --- network/mhfpacket/msg_mhf_get_gem_info.go | 19 +++++++++++++------ server/channelserver/handlers_tower.go | 5 ++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/network/mhfpacket/msg_mhf_get_gem_info.go b/network/mhfpacket/msg_mhf_get_gem_info.go index 516aea6be..36eb7948e 100644 --- a/network/mhfpacket/msg_mhf_get_gem_info.go +++ b/network/mhfpacket/msg_mhf_get_gem_info.go @@ -1,15 +1,19 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfGetGemInfo represents the MSG_MHF_GET_GEM_INFO -type MsgMhfGetGemInfo struct{} +type MsgMhfGetGemInfo struct { + AckHandle uint32 + Unk uint32 + Unk1 []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetGemInfo) Opcode() network.PacketID { @@ -18,7 +22,10 @@ func (m *MsgMhfGetGemInfo) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetGemInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk = bf.ReadUint32() + m.Unk1 = bf.ReadBytes(24) + return nil } // Build builds a binary packet from the current data. diff --git a/server/channelserver/handlers_tower.go b/server/channelserver/handlers_tower.go index 49029753f..10c3070f9 100644 --- a/server/channelserver/handlers_tower.go +++ b/server/channelserver/handlers_tower.go @@ -58,6 +58,9 @@ func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) { doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } -func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetGemInfo) + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 8)) +} func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) {} From 128f375cd2e3ae13ad2e92ddce3d67bde3e44b5a Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 10 Sep 2022 22:43:23 +1000 Subject: [PATCH 24/95] dump savedata without name --- network/mhfpacket/msg_mhf_get_tower_info.go | 10 +++++----- server/channelserver/handlers_data.go | 4 ++-- server/channelserver/handlers_tower.go | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/network/mhfpacket/msg_mhf_get_tower_info.go b/network/mhfpacket/msg_mhf_get_tower_info.go index 37ac8417b..a0b686485 100644 --- a/network/mhfpacket/msg_mhf_get_tower_info.go +++ b/network/mhfpacket/msg_mhf_get_tower_info.go @@ -1,11 +1,11 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // The server sends different responses based on these values. @@ -13,7 +13,7 @@ const ( TowerInfoTypeUnk0 = iota TowerInfoTypeTowerRankPoint TowerInfoTypeGetOwnTowerSkill - TowerInfoTypeUnk3 + TowerInfoTypeGetOwnTowerLevelV3 TowerInfoTypeTowerTouhaHistory TowerInfoTypeUnk5 ) diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index ae0450419..5d179e50c 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -219,8 +219,8 @@ func dumpSaveData(s *Session, data []byte, suffix string) { if !s.server.erupeConfig.DevModeOptions.SaveDumps.Enabled { return } else { - dir := filepath.Join(s.server.erupeConfig.DevModeOptions.SaveDumps.OutputDir, fmt.Sprintf("%d_%s", s.charID, s.Name)) - path := filepath.Join(s.server.erupeConfig.DevModeOptions.SaveDumps.OutputDir, fmt.Sprintf("%d_%s", s.charID, s.Name), fmt.Sprintf("%d_%s_%s.bin", s.charID, s.Name, suffix)) + dir := filepath.Join(s.server.erupeConfig.DevModeOptions.SaveDumps.OutputDir, fmt.Sprintf("%d", s.charID)) + path := filepath.Join(s.server.erupeConfig.DevModeOptions.SaveDumps.OutputDir, fmt.Sprintf("%d", s.charID), fmt.Sprintf("%d_%s.bin", s.charID, suffix)) if _, err := os.Stat(dir); os.IsNotExist(err) { os.Mkdir(dir, os.ModeDir) diff --git a/server/channelserver/handlers_tower.go b/server/channelserver/handlers_tower.go index 10c3070f9..24cc64033 100644 --- a/server/channelserver/handlers_tower.go +++ b/server/channelserver/handlers_tower.go @@ -13,7 +13,7 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) { type: 1 == TOWER_RANK_POINT, 2 == GET_OWN_TOWER_SKILL - 3 == ? + 3 == GET_OWN_TOWER_LEVEL_V3 4 == TOWER_TOUHA_HISTORY 5 = ? @@ -39,8 +39,8 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) { case mhfpacket.TowerInfoTypeGetOwnTowerSkill: //data, err = hex.DecodeString("0A218EAD000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") data, err = hex.DecodeString("0A218EAD0000000000000000000000010000001C0000000500050000000000020000000000000000000000000000000000030003000000000003000500050000000300030003000300030003000200030001000300020002000300010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") - case mhfpacket.TowerInfoTypeUnk3: - panic("No known response values for TowerInfoTypeUnk3") + case mhfpacket.TowerInfoTypeGetOwnTowerLevelV3: + panic("No known response values for GetOwnTowerLevelV3") case mhfpacket.TowerInfoTypeTowerTouhaHistory: data, err = hex.DecodeString("0A218EAD0000000000000000000000010000000000000000000000000000000000000000") case mhfpacket.TowerInfoTypeUnk5: From a35dfa21b5ee2471432c178c5380485f9acb94de Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 10 Sep 2022 23:15:08 +1000 Subject: [PATCH 25/95] create default response on rengoku ranking --- server/channelserver/handlers_rengoku.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_rengoku.go b/server/channelserver/handlers_rengoku.go index 9bfe464cf..d9f58df57 100644 --- a/server/channelserver/handlers_rengoku.go +++ b/server/channelserver/handlers_rengoku.go @@ -271,8 +271,20 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { bf.WriteBytes(make([]byte, 11)) } } - bf.WriteUint8(uint8(i) - 1) - bf.WriteBytes(scoreData.Data()) + if i == 1 { + bf.WriteUint32(1) + bf.WriteUint32(0) + ps.Uint8(bf, s.Name, true) + ps.Uint8(bf, "", false) + bf.WriteUint8(1) + bf.WriteUint32(1) + bf.WriteUint32(0) + ps.Uint8(bf, s.Name, true) + ps.Uint8(bf, "", false) + } else { + bf.WriteUint8(uint8(i) - 1) + bf.WriteBytes(scoreData.Data()) + } doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } From 44a42a3365ee8c46c9ccc42b283dd33419209a17 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Sun, 18 Sep 2022 14:15:11 -0400 Subject: [PATCH 26/95] Implemented the ability to enable and disable commands in configuration as well as increased scope of the config to the entire project. --- config.json | 25 ++ config/config.go | 55 ++++ go.mod | 2 +- go.sum | 9 + main.go | 54 ++- server/channelserver/handlers_cast_binary.go | 329 +++++++++++-------- 6 files changed, 309 insertions(+), 165 deletions(-) diff --git a/config.json b/config.json index 00e541adf..505249cf1 100644 --- a/config.json +++ b/config.json @@ -30,6 +30,31 @@ "bottoken": "", "realtimeChannelID": "" }, + "ServerCommands": { + "enabled": true, + "Commands": [ + { + "name": "Rights", + "enabled": true, + "prefix": "!rights" + }, + { + "name": "Ravi", + "enabled": true, + "prefix": "!ravi" + }, + { + "name": "Tele", + "enabled": true, + "prefix": "!tele" + }, + { + "name": "Reload", + "enabled": true, + "prefix": "!reload" + } + ] + }, "database": { "host": "localhost", "port": 5432, diff --git a/config/config.go b/config/config.go index bfbf8086a..45873074b 100644 --- a/config/config.go +++ b/config/config.go @@ -1,8 +1,11 @@ package config import ( + "fmt" "log" "net" + "os" + "time" "github.com/spf13/viper" ) @@ -16,6 +19,7 @@ type Config struct { DevModeOptions DevModeOptions Discord Discord + ServerCommands ServerCommands Database Database Launcher Launcher Sign Sign @@ -59,6 +63,18 @@ type Discord struct { DevMode bool } +// Server commands +type ServerCommands struct { + Enabled bool + Commands []ServerCommand +} + +type ServerCommand struct { + Name string + Enabled bool + Prefix string +} + // Database holds the postgres database config. type Database struct { Host string @@ -107,6 +123,28 @@ type EntranceChannelInfo struct { CurrentPlayers uint16 } +var ErupeConfig *Config + +func init() { + var err error + ErupeConfig, err = LoadConfig() + if err != nil { + preventClose(fmt.Sprintf("Failed to load config: %s", err.Error())) + } + +} + +func GetServerCommandByName(cmdName string) ServerCommand { + var val ServerCommand + for _, c := range ErupeConfig.ServerCommands.Commands { + if c.Name == cmdName { + return c + } + } + + return val +} + // getOutboundIP4 gets the preferred outbound ip4 of this machine // From https://stackoverflow.com/a/37382208 func getOutboundIP4() net.IP { @@ -148,3 +186,20 @@ func LoadConfig() (*Config, error) { return c, nil } + +func preventClose(text string) { + if ErupeConfig.DisableSoftCrash { + os.Exit(0) + } + fmt.Println("\nFailed to start Erupe:\n" + text) + go wait() + fmt.Println("\nPress Enter/Return to exit...") + fmt.Scanln() + os.Exit(0) +} + +func wait() { + for { + time.Sleep(time.Millisecond * 100) + } +} diff --git a/go.mod b/go.mod index 8107625a2..3ac44e932 100644 --- a/go.mod +++ b/go.mod @@ -19,5 +19,5 @@ require ( golang.org/x/crypto v0.0.0-20211202192323-5770296d904e golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect golang.org/x/text v0.3.7 - golang.org/x/tools v0.1.8 // indirect + honnef.co/go/tools v0.3.3 ) diff --git a/go.sum b/go.sum index 9750b4732..91403fd95 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -295,6 +297,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8= golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -307,6 +310,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -334,6 +338,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -510,6 +515,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg= +golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -638,6 +645,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA= +honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/main.go b/main.go index a9c796f29..a6074c7b2 100644 --- a/main.go +++ b/main.go @@ -20,8 +20,6 @@ import ( "go.uber.org/zap" ) -var erupeConfig *config.Config - // Temporary DB auto clean on startup for quick development & testing. func cleanDB(db *sqlx.DB) { _ = db.MustExec("DELETE FROM guild_characters") @@ -39,25 +37,19 @@ func main() { logger.Info("Starting Erupe") - // Load the configuration. - erupeConfig, err = config.LoadConfig() - if err != nil { - preventClose(fmt.Sprintf("Failed to load config: %s", err.Error())) - } - - if erupeConfig.Database.Password == "" { + if config.ErupeConfig.Database.Password == "" { preventClose("Database password is blank") } - if net.ParseIP(erupeConfig.Host) == nil { - ips, _ := net.LookupIP(erupeConfig.Host) + if net.ParseIP(config.ErupeConfig.Host) == nil { + ips, _ := net.LookupIP(config.ErupeConfig.Host) for _, ip := range ips { if ip != nil { - erupeConfig.Host = ip.String() + config.ErupeConfig.Host = ip.String() break } } - if net.ParseIP(erupeConfig.Host) == nil { + if net.ParseIP(config.ErupeConfig.Host) == nil { preventClose("Invalid host address") } } @@ -65,10 +57,10 @@ func main() { // Discord bot var discordBot *discordbot.DiscordBot = nil - if erupeConfig.Discord.Enabled { + if config.ErupeConfig.Discord.Enabled { bot, err := discordbot.NewDiscordBot(discordbot.Options{ Logger: logger, - Config: erupeConfig, + Config: config.ErupeConfig, }) if err != nil { @@ -91,11 +83,11 @@ func main() { // Create the postgres DB pool. connectString := fmt.Sprintf( "host=%s port=%d user=%s password=%s dbname= %s sslmode=disable", - erupeConfig.Database.Host, - erupeConfig.Database.Port, - erupeConfig.Database.User, - erupeConfig.Database.Password, - erupeConfig.Database.Database, + config.ErupeConfig.Database.Host, + config.ErupeConfig.Database.Port, + config.ErupeConfig.Database.User, + config.ErupeConfig.Database.Password, + config.ErupeConfig.Database.Database, ) db, err := sqlx.Open("postgres", connectString) @@ -117,7 +109,7 @@ func main() { _ = db.MustExec("UPDATE characters SET cafe_time=0") // Clean the DB if the option is on. - if erupeConfig.DevMode && erupeConfig.DevModeOptions.CleanDB { + if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.CleanDB { logger.Info("Cleaning DB") cleanDB(db) logger.Info("Done cleaning DB") @@ -127,13 +119,13 @@ func main() { // Launcher HTTP server. var launcherServer *launcherserver.Server - if erupeConfig.DevMode && erupeConfig.DevModeOptions.EnableLauncherServer { + if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.EnableLauncherServer { launcherServer = launcherserver.NewServer( &launcherserver.Config{ Logger: logger.Named("launcher"), - ErupeConfig: erupeConfig, + ErupeConfig: config.ErupeConfig, DB: db, - UseOriginalLauncherFiles: erupeConfig.Launcher.UseOriginalLauncherFiles, + UseOriginalLauncherFiles: config.ErupeConfig.Launcher.UseOriginalLauncherFiles, }) err = launcherServer.Start() if err != nil { @@ -146,7 +138,7 @@ func main() { entranceServer := entranceserver.NewServer( &entranceserver.Config{ Logger: logger.Named("entrance"), - ErupeConfig: erupeConfig, + ErupeConfig: config.ErupeConfig, DB: db, }) err = entranceServer.Start() @@ -159,7 +151,7 @@ func main() { signServer := signserver.NewServer( &signserver.Config{ Logger: logger.Named("sign"), - ErupeConfig: erupeConfig, + ErupeConfig: config.ErupeConfig, DB: db, }) err = signServer.Start() @@ -173,18 +165,18 @@ func main() { si := 0 ci := 0 count := 1 - for _, ee := range erupeConfig.Entrance.Entries { + for _, ee := range config.ErupeConfig.Entrance.Entries { for i, ce := range ee.Channels { sid := (4096 + si*256) + (16 + ci) c := *channelserver.NewServer(&channelserver.Config{ ID: uint16(sid), Logger: logger.Named("channel-" + fmt.Sprint(count)), - ErupeConfig: erupeConfig, + ErupeConfig: config.ErupeConfig, DB: db, DiscordBot: discordBot, }) if ee.IP == "" { - c.IP = erupeConfig.Host + c.IP = config.ErupeConfig.Host } else { c.IP = ee.IP } @@ -223,7 +215,7 @@ func main() { } signServer.Shutdown() entranceServer.Shutdown() - if erupeConfig.DevModeOptions.EnableLauncherServer { + if config.ErupeConfig.DevModeOptions.EnableLauncherServer { launcherServer.Shutdown() } @@ -237,7 +229,7 @@ func wait() { } func preventClose(text string) { - if erupeConfig.DisableSoftCrash { + if config.ErupeConfig.DisableSoftCrash { os.Exit(0) } fmt.Println("\nFailed to start Erupe:\n" + text) diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 35538e0fb..35c9adf0c 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -8,8 +8,11 @@ import ( "time" "erupe-ce/common/byteframe" + "erupe-ce/config" "erupe-ce/network/binpacket" "erupe-ce/network/mhfpacket" + + "go.uber.org/zap" ) // MSG_SYS_CAST[ED]_BINARY types enum @@ -29,6 +32,47 @@ const ( BroadcastTypeWorld = 0x0a ) +var raviCmd config.ServerCommand +var rightsCmd config.ServerCommand +var teleCmd config.ServerCommand +var reloadCmd config.ServerCommand +var logger *zap.Logger + +func init() { + zapLogger, _ := zap.NewDevelopment() + defer zapLogger.Sync() + logger = zapLogger.Named("channelserver") + + raviCmd = config.GetServerCommandByName("Ravi") + if raviCmd.Enabled { + logger.Info(raviCmd.Name + " command is enabled") + } else { + logger.Info(raviCmd.Name + " command is disabled") + } + + rightsCmd = config.GetServerCommandByName("Rights") + if rightsCmd.Enabled { + logger.Info(rightsCmd.Name + " command is enabled") + } else { + logger.Info(rightsCmd.Name + " command is disabled") + } + + teleCmd = config.GetServerCommandByName("Tele") + if teleCmd.Enabled { + logger.Info(teleCmd.Name + " command is enabled") + } else { + logger.Info(teleCmd.Name + " command is disabled") + } + + reloadCmd = config.GetServerCommandByName("Reload") + if reloadCmd.Enabled { + logger.Info(reloadCmd.Name + " command is enabled") + } else { + logger.Info(reloadCmd.Name + " command is disabled") + } + +} + func sendServerChatMessage(s *Session, message string) { // Make the inside of the casted binary bf := byteframe.NewByteFrame() @@ -165,78 +209,88 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { fmt.Printf("Got chat message: %+v\n", chatMessage) - // Flush all objects and users and reload - if strings.HasPrefix(chatMessage.Message, "!reload") { - sendServerChatMessage(s, "Reloading players...") - var temp mhfpacket.MHFPacket - deleteNotif := byteframe.NewByteFrame() - for _, object := range s.stage.objects { - if object.ownerCharID == s.charID { - continue + if strings.HasPrefix(chatMessage.Message, reloadCmd.Prefix) { + // Flush all objects and users and reload + if reloadCmd.Enabled { + sendServerChatMessage(s, "Reloading players...") + var temp mhfpacket.MHFPacket + deleteNotif := byteframe.NewByteFrame() + for _, object := range s.stage.objects { + if object.ownerCharID == s.charID { + continue + } + temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id} + deleteNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(deleteNotif, s.clientContext) } - temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id} - deleteNotif.WriteUint16(uint16(temp.Opcode())) - temp.Build(deleteNotif, s.clientContext) - } - for _, session := range s.server.sessions { - if s == session { - continue + for _, session := range s.server.sessions { + if s == session { + continue + } + temp = &mhfpacket.MsgSysDeleteUser{CharID: session.charID} + deleteNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(deleteNotif, s.clientContext) } - temp = &mhfpacket.MsgSysDeleteUser{CharID: session.charID} - deleteNotif.WriteUint16(uint16(temp.Opcode())) - temp.Build(deleteNotif, s.clientContext) - } - deleteNotif.WriteUint16(0x0010) - s.QueueSend(deleteNotif.Data()) - time.Sleep(500 * time.Millisecond) - reloadNotif := byteframe.NewByteFrame() - for _, session := range s.server.sessions { - if s == session { - continue + deleteNotif.WriteUint16(0x0010) + s.QueueSend(deleteNotif.Data()) + time.Sleep(500 * time.Millisecond) + reloadNotif := byteframe.NewByteFrame() + for _, session := range s.server.sessions { + if s == session { + continue + } + temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID} + reloadNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(reloadNotif, s.clientContext) + for i := 0; i < 3; i++ { + temp = &mhfpacket.MsgSysNotifyUserBinary{ + CharID: session.charID, + BinaryType: uint8(i + 1), + } + reloadNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(reloadNotif, s.clientContext) + } } - temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID} - reloadNotif.WriteUint16(uint16(temp.Opcode())) - temp.Build(reloadNotif, s.clientContext) - for i := 0; i < 3; i++ { - temp = &mhfpacket.MsgSysNotifyUserBinary{ - CharID: session.charID, - BinaryType: uint8(i + 1), + for _, obj := range s.stage.objects { + if obj.ownerCharID == s.charID { + continue + } + temp = &mhfpacket.MsgSysDuplicateObject{ + ObjID: obj.id, + X: obj.x, + Y: obj.y, + Z: obj.z, + Unk0: 0, + OwnerCharID: obj.ownerCharID, } reloadNotif.WriteUint16(uint16(temp.Opcode())) temp.Build(reloadNotif, s.clientContext) } + reloadNotif.WriteUint16(0x0010) + s.QueueSend(reloadNotif.Data()) + } else { + sendServerChatMessage(s, reloadCmd.Name+" command is disabled") } - for _, obj := range s.stage.objects { - if obj.ownerCharID == s.charID { - continue - } - temp = &mhfpacket.MsgSysDuplicateObject{ - ObjID: obj.id, - X: obj.x, - Y: obj.y, - Z: obj.z, - Unk0: 0, - OwnerCharID: obj.ownerCharID, - } - reloadNotif.WriteUint16(uint16(temp.Opcode())) - temp.Build(reloadNotif, s.clientContext) - } - reloadNotif.WriteUint16(0x0010) - s.QueueSend(reloadNotif.Data()) + } - // Set account rights - if strings.HasPrefix(chatMessage.Message, "!rights") { - var v uint32 - n, err := fmt.Sscanf(chatMessage.Message, "!rights %d", &v) - if err != nil || n != 1 { - sendServerChatMessage(s, "Error in command. Format: !rights n") - } else { - _, err = s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID) - if err == nil { - sendServerChatMessage(s, fmt.Sprintf("Set rights integer: %d", v)) + if strings.HasPrefix(chatMessage.Message, rightsCmd.Prefix) { + // Set account rights + if rightsCmd.Enabled { + var v uint32 + n, err := fmt.Sscanf(chatMessage.Message, "!rights %d", &v) + if err != nil || n != 1 { + sendServerChatMessage(s, "Error in command. Format: !rights n") + } else { + _, err = s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID) + if err == nil { + sendServerChatMessage(s, fmt.Sprintf("Set rights integer: %d", v)) + } } + } else { + sendServerChatMessage(s, rightsCmd.Name+" command is disabled") } + } // Discord integration @@ -244,88 +298,97 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { s.server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message) } - // RAVI COMMANDS V2 - if strings.HasPrefix(chatMessage.Message, "!ravi") { - if getRaviSemaphore(s) != "" { - s.server.raviente.Lock() - if !strings.HasPrefix(chatMessage.Message, "!ravi ") { - sendServerChatMessage(s, "No Raviente command specified!") - } else { - if strings.HasPrefix(chatMessage.Message, "!ravi start") { - if s.server.raviente.register.startTime == 0 { - s.server.raviente.register.startTime = s.server.raviente.register.postTime - sendServerChatMessage(s, "The Great Slaying will begin in a moment") - s.notifyRavi() - } else { - sendServerChatMessage(s, "The Great Slaying has already begun!") - } - } 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 > 32 { - sendServerChatMessage(s, "Raviente multiplier too high, defaulting to 32x") - s.server.raviente.state.damageMultiplier = 32 - } 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 + if strings.HasPrefix(chatMessage.Message, raviCmd.Prefix) { + // RAVI COMMANDS V2 + if raviCmd.Enabled { + if getRaviSemaphore(s) != "" { + s.server.raviente.Lock() + if !strings.HasPrefix(chatMessage.Message, "!ravi ") { + sendServerChatMessage(s, "No Raviente command specified!") } else { - sendServerChatMessage(s, "Raviente command not recognised!") + if strings.HasPrefix(chatMessage.Message, "!ravi start") { + if s.server.raviente.register.startTime == 0 { + s.server.raviente.register.startTime = s.server.raviente.register.postTime + sendServerChatMessage(s, "The Great Slaying will begin in a moment") + s.notifyRavi() + } else { + sendServerChatMessage(s, "The Great Slaying has already begun!") + } + } 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 > 32 { + sendServerChatMessage(s, "Raviente multiplier too high, defaulting to 32x") + s.server.raviente.state.damageMultiplier = 32 + } 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 { + sendServerChatMessage(s, "Raviente command not recognised!") + } } + s.server.raviente.Unlock() + } else { + sendServerChatMessage(s, "No one has joined the Great Slaying!") } - s.server.raviente.Unlock() } else { - sendServerChatMessage(s, "No one has joined the Great Slaying!") + sendServerChatMessage(s, raviCmd.Name+" command is disabled") } } + // END RAVI COMMANDS V2 - if strings.HasPrefix(chatMessage.Message, "!tele ") { - var x, y int16 - n, err := fmt.Sscanf(chatMessage.Message, "!tele %d %d", &x, &y) - if err != nil || n != 2 { - sendServerChatMessage(s, "Invalid command. Usage:\"!tele 500 500\"") + if strings.HasPrefix(chatMessage.Message, teleCmd.Prefix) { + if teleCmd.Enabled { + var x, y int16 + n, err := fmt.Sscanf(chatMessage.Message, "!tele %d %d", &x, &y) + if err != nil || n != 2 { + sendServerChatMessage(s, "Invalid command. Usage:\"!tele 500 500\"") + } else { + sendServerChatMessage(s, fmt.Sprintf("Teleporting to %d %d", x, y)) + + // Make the inside of the casted binary + payload := byteframe.NewByteFrame() + payload.SetLE() + payload.WriteUint8(2) // SetState type(position == 2) + payload.WriteInt16(x) // X + payload.WriteInt16(y) // Y + payloadBytes := payload.Data() + + s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{ + CharID: s.charID, + MessageType: BinaryMessageTypeState, + RawDataPayload: payloadBytes, + }) + } } else { - sendServerChatMessage(s, fmt.Sprintf("Teleporting to %d %d", x, y)) - - // Make the inside of the casted binary - payload := byteframe.NewByteFrame() - payload.SetLE() - payload.WriteUint8(2) // SetState type(position == 2) - payload.WriteInt16(x) // X - payload.WriteInt16(y) // Y - payloadBytes := payload.Data() - - s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{ - CharID: s.charID, - MessageType: BinaryMessageTypeState, - RawDataPayload: payloadBytes, - }) + sendServerChatMessage(s, teleCmd.Name+" command is disabled") } } } From 2f123d96df3904571004e4cedd8b8c1faee0a8a3 Mon Sep 17 00:00:00 2001 From: Eclipse Date: Thu, 22 Sep 2022 20:51:18 -0400 Subject: [PATCH 27/95] Implemented the ability to enable/disable entrance, sign, and channel servers --- config.json | 6 ++ config/config.go | 10 +++- go.mod | 2 +- go.sum | 23 ++------ main.go | 144 +++++++++++++++++++++++++++-------------------- 5 files changed, 103 insertions(+), 82 deletions(-) diff --git a/config.json b/config.json index 505249cf1..8d500907c 100644 --- a/config.json +++ b/config.json @@ -63,13 +63,19 @@ "database": "erupe" }, "launcher": { + "enabled": true, "port": 80, "UseOriginalLauncherFiles": false }, "sign": { + "enabled": true, "port": 53312 }, + "channel": { + "enabled": true + }, "entrance": { + "enabled": true, "port": 53310, "entries": [ { diff --git a/config/config.go b/config/config.go index 45873074b..27bcff6f0 100644 --- a/config/config.go +++ b/config/config.go @@ -23,6 +23,7 @@ type Config struct { Database Database Launcher Launcher Sign Sign + Channel Channel Entrance Entrance } @@ -86,17 +87,24 @@ type Database struct { // Launcher holds the launcher server config. type Launcher struct { + Enabled bool Port int UseOriginalLauncherFiles bool } // Sign holds the sign server config. type Sign struct { - Port int + Enabled bool + Port int +} + +type Channel struct { + Enabled bool } // Entrance holds the entrance server config. type Entrance struct { + Enabled bool Port uint16 Entries []EntranceServerInfo } diff --git a/go.mod b/go.mod index 3ac44e932..f4e7f1033 100644 --- a/go.mod +++ b/go.mod @@ -19,5 +19,5 @@ require ( golang.org/x/crypto v0.0.0-20211202192323-5770296d904e golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect golang.org/x/text v0.3.7 - honnef.co/go/tools v0.3.3 + golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect ) diff --git a/go.sum b/go.sum index 91403fd95..1e7747306 100644 --- a/go.sum +++ b/go.sum @@ -38,8 +38,6 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= -github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -80,9 +78,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -191,9 +188,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -204,9 +200,8 @@ github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaW github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= -github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -224,9 +219,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -310,7 +304,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -337,7 +330,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -513,8 +505,6 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg= golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -624,9 +614,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -645,8 +634,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA= -honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/main.go b/main.go index a6074c7b2..60b64dac1 100644 --- a/main.go +++ b/main.go @@ -135,72 +135,83 @@ func main() { } // Entrance server. - entranceServer := entranceserver.NewServer( - &entranceserver.Config{ - Logger: logger.Named("entrance"), - ErupeConfig: config.ErupeConfig, - DB: db, - }) - err = entranceServer.Start() - if err != nil { - preventClose(fmt.Sprintf("Failed to start entrance server: %s", err.Error())) - } - logger.Info("Started entrance server") - // Sign server. - signServer := signserver.NewServer( - &signserver.Config{ - Logger: logger.Named("sign"), - ErupeConfig: config.ErupeConfig, - DB: db, - }) - err = signServer.Start() - if err != nil { - preventClose(fmt.Sprintf("Failed to start sign server: %s", err.Error())) - } - logger.Info("Started sign server") - - var channels []*channelserver.Server - channelQuery := "" - si := 0 - ci := 0 - count := 1 - for _, ee := range config.ErupeConfig.Entrance.Entries { - for i, ce := range ee.Channels { - sid := (4096 + si*256) + (16 + ci) - c := *channelserver.NewServer(&channelserver.Config{ - ID: uint16(sid), - Logger: logger.Named("channel-" + fmt.Sprint(count)), + var entranceServer *entranceserver.Server + if config.ErupeConfig.Entrance.Enabled { + entranceServer = entranceserver.NewServer( + &entranceserver.Config{ + Logger: logger.Named("entrance"), ErupeConfig: config.ErupeConfig, DB: db, - DiscordBot: discordBot, }) - if ee.IP == "" { - c.IP = config.ErupeConfig.Host - } else { - c.IP = ee.IP - } - c.Port = ce.Port - err = c.Start() - if err != nil { - preventClose(fmt.Sprintf("Failed to start channel server: %s", err.Error())) - } else { - channelQuery += fmt.Sprintf(`INSERT INTO servers (server_id, season, current_players, world_name, world_description, land) VALUES (%d, %d, 0, '%s', '%s', %d);`, sid, si%3, ee.Name, ee.Description, i+1) - channels = append(channels, &c) - logger.Info(fmt.Sprintf("Started channel server %d on port %d", count, ce.Port)) - ci++ - count++ - } + err = entranceServer.Start() + if err != nil { + preventClose(fmt.Sprintf("Failed to start entrance server: %s", err.Error())) } - ci = 0 - si++ + logger.Info("Started entrance server") } - // Register all servers in DB - _ = db.MustExec(channelQuery) + // Sign server. - for _, c := range channels { - c.Channels = channels + var signServer *signserver.Server + if config.ErupeConfig.Sign.Enabled { + signServer = signserver.NewServer( + &signserver.Config{ + Logger: logger.Named("sign"), + ErupeConfig: config.ErupeConfig, + DB: db, + }) + err = signServer.Start() + if err != nil { + preventClose(fmt.Sprintf("Failed to start sign server: %s", err.Error())) + } + logger.Info("Started sign server") + } + + var channels []*channelserver.Server + + if config.ErupeConfig.Channel.Enabled { + channelQuery := "" + si := 0 + ci := 0 + count := 1 + for _, ee := range config.ErupeConfig.Entrance.Entries { + for i, ce := range ee.Channels { + sid := (4096 + si*256) + (16 + ci) + c := *channelserver.NewServer(&channelserver.Config{ + ID: uint16(sid), + Logger: logger.Named("channel-" + fmt.Sprint(count)), + ErupeConfig: config.ErupeConfig, + DB: db, + DiscordBot: discordBot, + }) + if ee.IP == "" { + c.IP = config.ErupeConfig.Host + } else { + c.IP = ee.IP + } + c.Port = ce.Port + err = c.Start() + if err != nil { + preventClose(fmt.Sprintf("Failed to start channel server: %s", err.Error())) + } else { + channelQuery += fmt.Sprintf(`INSERT INTO servers (server_id, season, current_players, world_name, world_description, land) VALUES (%d, %d, 0, '%s', '%s', %d);`, sid, si%3, ee.Name, ee.Description, i+1) + channels = append(channels, &c) + logger.Info(fmt.Sprintf("Started channel server %d on port %d", count, ce.Port)) + ci++ + count++ + } + } + ci = 0 + si++ + } + + // Register all servers in DB + _ = db.MustExec(channelQuery) + + for _, c := range channels { + c.Channels = channels + } } // Wait for exit or interrupt with ctrl+C. @@ -210,11 +221,20 @@ func main() { logger.Info("Trying to shutdown gracefully") - for _, c := range channels { - c.Shutdown() + if config.ErupeConfig.Channel.Enabled { + for _, c := range channels { + c.Shutdown() + } } - signServer.Shutdown() - entranceServer.Shutdown() + + if config.ErupeConfig.Sign.Enabled { + signServer.Shutdown() + } + + if config.ErupeConfig.Entrance.Enabled { + entranceServer.Shutdown() + } + if config.ErupeConfig.DevModeOptions.EnableLauncherServer { launcherServer.Shutdown() } From 9b1f3f80120bb684b274920accce647782d3d2cf Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 30 Sep 2022 02:54:37 +1000 Subject: [PATCH 28/95] revise command rework --- config.json | 44 +++++----- config/config.go | 22 +---- server/channelserver/handlers_cast_binary.go | 86 +++++++------------- 3 files changed, 53 insertions(+), 99 deletions(-) diff --git a/config.json b/config.json index 8d500907c..5f04778c1 100644 --- a/config.json +++ b/config.json @@ -30,31 +30,25 @@ "bottoken": "", "realtimeChannelID": "" }, - "ServerCommands": { - "enabled": true, - "Commands": [ - { - "name": "Rights", - "enabled": true, - "prefix": "!rights" - }, - { - "name": "Ravi", - "enabled": true, - "prefix": "!ravi" - }, - { - "name": "Tele", - "enabled": true, - "prefix": "!tele" - }, - { - "name": "Reload", - "enabled": true, - "prefix": "!reload" - } - ] - }, + "Commands": [ + { + "name": "Rights", + "enabled": true, + "prefix": "!rights" + }, { + "name": "Raviente", + "enabled": true, + "prefix": "!ravi" + }, { + "name": "Teleport", + "enabled": true, + "prefix": "!tele" + }, { + "name": "Reload", + "enabled": true, + "prefix": "!reload" + } + ], "database": { "host": "localhost", "port": 5432, diff --git a/config/config.go b/config/config.go index 27bcff6f0..5355b6e42 100644 --- a/config/config.go +++ b/config/config.go @@ -19,7 +19,7 @@ type Config struct { DevModeOptions DevModeOptions Discord Discord - ServerCommands ServerCommands + Commands []Command Database Database Launcher Launcher Sign Sign @@ -64,13 +64,8 @@ type Discord struct { DevMode bool } -// Server commands -type ServerCommands struct { - Enabled bool - Commands []ServerCommand -} - -type ServerCommand struct { +// Command is a channelserver chat command +type Command struct { Name string Enabled bool Prefix string @@ -142,17 +137,6 @@ func init() { } -func GetServerCommandByName(cmdName string) ServerCommand { - var val ServerCommand - for _, c := range ErupeConfig.ServerCommands.Commands { - if c.Name == cmdName { - return c - } - } - - return val -} - // getOutboundIP4 gets the preferred outbound ip4 of this machine // From https://stackoverflow.com/a/37382208 func getOutboundIP4() net.IP { diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 35c9adf0c..6910a01ae 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -32,45 +32,26 @@ const ( BroadcastTypeWorld = 0x0a ) -var raviCmd config.ServerCommand -var rightsCmd config.ServerCommand -var teleCmd config.ServerCommand -var reloadCmd config.ServerCommand -var logger *zap.Logger +var commands map[string]config.Command func init() { + commands = make(map[string]config.Command) zapLogger, _ := zap.NewDevelopment() defer zapLogger.Sync() - logger = zapLogger.Named("channelserver") - - raviCmd = config.GetServerCommandByName("Ravi") - if raviCmd.Enabled { - logger.Info(raviCmd.Name + " command is enabled") - } else { - logger.Info(raviCmd.Name + " command is disabled") - } - - rightsCmd = config.GetServerCommandByName("Rights") - if rightsCmd.Enabled { - logger.Info(rightsCmd.Name + " command is enabled") - } else { - logger.Info(rightsCmd.Name + " command is disabled") - } - - teleCmd = config.GetServerCommandByName("Tele") - if teleCmd.Enabled { - logger.Info(teleCmd.Name + " command is enabled") - } else { - logger.Info(teleCmd.Name + " command is disabled") - } - - reloadCmd = config.GetServerCommandByName("Reload") - if reloadCmd.Enabled { - logger.Info(reloadCmd.Name + " command is enabled") - } else { - logger.Info(reloadCmd.Name + " command is disabled") + logger := zapLogger.Named("commands") + cmds := config.ErupeConfig.Commands + for _, cmd := range cmds { + commands[cmd.Name] = cmd + if cmd.Enabled { + logger.Info(fmt.Sprintf("%s command is enabled, prefix: %s", cmd.Name, cmd.Prefix)) + } else { + logger.Info(fmt.Sprintf("%s command is disabled", cmd.Name)) + } } +} +func sendDisabledCommandMessage(s *Session, cmd config.Command) { + sendServerChatMessage(s, fmt.Sprintf("%s command is disabled", cmd.Name)) } func sendServerChatMessage(s *Session, message string) { @@ -209,9 +190,14 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { fmt.Printf("Got chat message: %+v\n", chatMessage) - if strings.HasPrefix(chatMessage.Message, reloadCmd.Prefix) { + // Discord integration + if (pkt.BroadcastType == BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == BroadcastTypeWorld { + s.server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message) + } + + if strings.HasPrefix(chatMessage.Message, commands["Reload"].Prefix) { // Flush all objects and users and reload - if reloadCmd.Enabled { + if commands["Reload"].Enabled { sendServerChatMessage(s, "Reloading players...") var temp mhfpacket.MHFPacket deleteNotif := byteframe.NewByteFrame() @@ -269,14 +255,13 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { reloadNotif.WriteUint16(0x0010) s.QueueSend(reloadNotif.Data()) } else { - sendServerChatMessage(s, reloadCmd.Name+" command is disabled") + sendDisabledCommandMessage(s, commands["Reload"]) } - } - if strings.HasPrefix(chatMessage.Message, rightsCmd.Prefix) { + if strings.HasPrefix(chatMessage.Message, commands["Rights"].Prefix) { // Set account rights - if rightsCmd.Enabled { + if commands["Rights"].Enabled { var v uint32 n, err := fmt.Sscanf(chatMessage.Message, "!rights %d", &v) if err != nil || n != 1 { @@ -288,19 +273,12 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { } } } else { - sendServerChatMessage(s, rightsCmd.Name+" command is disabled") + sendDisabledCommandMessage(s, commands["Rights"]) } - } - // Discord integration - if (pkt.BroadcastType == BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == BroadcastTypeWorld { - s.server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message) - } - - if strings.HasPrefix(chatMessage.Message, raviCmd.Prefix) { - // RAVI COMMANDS V2 - if raviCmd.Enabled { + if strings.HasPrefix(chatMessage.Message, commands["Raviente"].Prefix) { + if commands["Raviente"].Enabled { if getRaviSemaphore(s) != "" { s.server.raviente.Lock() if !strings.HasPrefix(chatMessage.Message, "!ravi ") { @@ -358,14 +336,12 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { sendServerChatMessage(s, "No one has joined the Great Slaying!") } } else { - sendServerChatMessage(s, raviCmd.Name+" command is disabled") + sendDisabledCommandMessage(s, commands["Raviente"]) } } - // END RAVI COMMANDS V2 - - if strings.HasPrefix(chatMessage.Message, teleCmd.Prefix) { - if teleCmd.Enabled { + if strings.HasPrefix(chatMessage.Message, commands["Teleport"].Prefix) { + if commands["Teleport"].Enabled { var x, y int16 n, err := fmt.Sscanf(chatMessage.Message, "!tele %d %d", &x, &y) if err != nil || n != 2 { @@ -388,7 +364,7 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { }) } } else { - sendServerChatMessage(s, teleCmd.Name+" command is disabled") + sendDisabledCommandMessage(s, commands["Teleport"]) } } } From e90e3da142c062892de3acc02d6a6afc78c6b678 Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 30 Sep 2022 03:47:59 +1000 Subject: [PATCH 29/95] add KQF command --- config.json | 4 +++ server/channelserver/handlers_cast_binary.go | 31 ++++++++++++++++---- server/channelserver/handlers_character.go | 13 +++++++- server/channelserver/sys_session.go | 2 ++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/config.json b/config.json index ba952620b..98ea1c0ef 100644 --- a/config.json +++ b/config.json @@ -46,6 +46,10 @@ "name": "Reload", "enabled": true, "prefix": "!reload" + }, { + "name": "KeyQuest", + "enabled": false, + "prefix": "!kqf" } ], "database": { diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 6910a01ae..3791ea241 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -1,17 +1,17 @@ package channelserver import ( + "encoding/hex" + "erupe-ce/common/byteframe" + "erupe-ce/config" + "erupe-ce/network/binpacket" + "erupe-ce/network/mhfpacket" "fmt" "math" "math/rand" "strings" "time" - "erupe-ce/common/byteframe" - "erupe-ce/config" - "erupe-ce/network/binpacket" - "erupe-ce/network/mhfpacket" - "go.uber.org/zap" ) @@ -259,6 +259,27 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { } } + if strings.HasPrefix(chatMessage.Message, commands["KeyQuest"].Prefix) { + if commands["KeyQuest"].Enabled { + if strings.HasPrefix(chatMessage.Message, "!kqf get") { + sendServerChatMessage(s, fmt.Sprintf("KQF: %x", s.kqf)) + } else if strings.HasPrefix(chatMessage.Message, "!kqf set") { + var hexs string + n, numerr := fmt.Sscanf(chatMessage.Message, "!kqf set %s", &hexs) + if numerr != nil || n != 1 || len(hexs) != 16 { + sendServerChatMessage(s, "Error in command. Format: !kqf set xxxxxxxxxxxxxxxx") + } else { + hexd, _ := hex.DecodeString(hexs) + s.kqf = hexd + s.kqfOverride = true + sendServerChatMessage(s, "KQF set, please switch Land/World") + } + } + } else { + sendDisabledCommandMessage(s, commands["KeyQuest"]) + } + } + if strings.HasPrefix(chatMessage.Message, commands["Rights"].Prefix) { // Set account rights if commands["Rights"].Enabled { diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index 13459bda9..b3ad40fcd 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -22,6 +22,7 @@ const ( pointerWeaponID = 0x1F60A // +2 pointerHRP = 0x1FDF6 // +2 pointerGRP = 0x1FDFC // +4 + pointerKQF = 0x23D20 // +8 ) type CharacterSaveData struct { @@ -41,6 +42,7 @@ type CharacterSaveData struct { WeaponID uint16 HRP uint16 GR uint16 + KQF []byte compSave []byte decompSave []byte @@ -80,9 +82,16 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error) func (save *CharacterSaveData) Save(s *Session) { // We need to update the save data byte array before we save it back to the DB - save.updateSaveDataWithStruct() save.updateStructWithSaveData() + if !s.kqfOverride { + s.kqf = save.KQF + } else { + save.KQF = s.kqf + } + + save.updateSaveDataWithStruct() + err := save.Compress() if err != nil { s.logger.Error("Failed to compress savedata", zap.Error(err)) @@ -122,6 +131,7 @@ func (save *CharacterSaveData) updateSaveDataWithStruct() { rpBytes := make([]byte, 2) binary.LittleEndian.PutUint16(rpBytes, save.RP) copy(save.decompSave[pointerRP:pointerRP+2], rpBytes) + copy(save.decompSave[pointerKQF:pointerKQF+8], save.KQF) } // This will update the save struct with the values stored in the character save @@ -142,6 +152,7 @@ func (save *CharacterSaveData) updateStructWithSaveData() { save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[pointerWeaponID : pointerWeaponID+2]) save.HRP = binary.LittleEndian.Uint16(save.decompSave[pointerHRP : pointerHRP+2]) save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4])) + save.KQF = save.decompSave[pointerKQF : pointerKQF+8] } func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) { diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index 20fc432f8..ec122a521 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -39,6 +39,8 @@ type Session struct { sessionStart int64 rights uint32 token string + kqf []byte + kqfOverride bool semaphore *Semaphore // Required for the stateful MsgSysUnreserveStage packet. From e0c658363c1db1fe7e8361ecc39169877ae7d4b9 Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 30 Sep 2022 17:40:23 +1000 Subject: [PATCH 30/95] fix struct save data --- server/channelserver/handlers_character.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index b3ad40fcd..78a0b4754 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -77,13 +77,12 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error) return nil, err } + saveData.updateStructWithSaveData() + return saveData, nil } func (save *CharacterSaveData) Save(s *Session) { - // We need to update the save data byte array before we save it back to the DB - save.updateStructWithSaveData() - if !s.kqfOverride { s.kqf = save.KQF } else { From ca9f2de457440b17943765c64eb399bb81a2a02f Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 30 Sep 2022 17:59:56 +1000 Subject: [PATCH 31/95] fix return not expiring --- server/signserver/dsgn_resp.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go index 091abc687..cbad6405c 100644 --- a/server/signserver/dsgn_resp.go +++ b/server/signserver/dsgn_resp.go @@ -120,7 +120,12 @@ func (s *Session) makeSignInResp(uid int) []byte { bf.WriteUint16(0x0001) bf.WriteUint16(0x4E20) ps.Uint16(bf, "", false) // unk ipv4 - bf.WriteUint32(uint32(returnExpiry.Unix())) + if returnExpiry.Before(time.Now()) { + // Hack to make Return work while having a non-adjusted expiry + bf.WriteUint32(0) + } else { + bf.WriteUint32(uint32(returnExpiry.Unix())) + } bf.WriteUint32(0x00000000) bf.WriteUint32(0x0A5197DF) // unk id From 40a86364d9a91cceb524b1479f13ac7d04c65689 Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 30 Sep 2022 23:05:10 +1000 Subject: [PATCH 32/95] handle alliance enumeration --- network/mhfpacket/msg_mhf_info_joint.go | 19 ++- server/channelserver/handlers_guild.go | 110 +++++++++++++----- .../channelserver/handlers_guild_alliance.go | 51 +++++++- 3 files changed, 146 insertions(+), 34 deletions(-) diff --git a/network/mhfpacket/msg_mhf_info_joint.go b/network/mhfpacket/msg_mhf_info_joint.go index 6426b9211..17e468c7c 100644 --- a/network/mhfpacket/msg_mhf_info_joint.go +++ b/network/mhfpacket/msg_mhf_info_joint.go @@ -1,15 +1,19 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfInfoJoint represents the MSG_MHF_INFO_JOINT -type MsgMhfInfoJoint struct{} +type MsgMhfInfoJoint struct { + AckHandle uint32 + AllianceID uint32 + Unk uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfInfoJoint) Opcode() network.PacketID { @@ -18,7 +22,10 @@ func (m *MsgMhfInfoJoint) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfInfoJoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.AllianceID = bf.ReadUint32() + m.Unk = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index f7646926c..5f56baf6d 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1065,6 +1065,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateGuild) var guilds []*Guild + var alliances []*GuildAlliance var rows *sqlx.Rows var err error bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) @@ -1159,41 +1160,98 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { guilds = append(guilds, guild) } } - case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME: - // - case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_NAME: - // - case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_ID: - // - case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_MEMBERS: - // - case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_REGISTRATION: - // - default: - panic(fmt.Sprintf("no handler for guild search type '%d'", pkt.Type)) } - if err != nil || guilds == nil { + if pkt.Type > 8 { + var tempAlliances []*GuildAlliance + rows, err = s.server.db.Queryx(allianceInfoSelectQuery) + if err == nil { + for rows.Next() { + alliance, _ := buildAllianceObjectFromDbResult(rows, err, s) + tempAlliances = append(tempAlliances, alliance) + } + } + switch pkt.Type { + case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME: + bf.ReadBytes(10) + searchTerm := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) + for _, alliance := range tempAlliances { + if strings.Contains(alliance.Name, searchTerm) { + alliances = append(alliances, alliance) + } + } + case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_NAME: + bf.ReadBytes(10) + searchTerm := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) + for _, alliance := range tempAlliances { + if strings.Contains(alliance.ParentGuild.LeaderName, searchTerm) { + alliances = append(alliances, alliance) + } + } + case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_ID: + bf.ReadBytes(2) + ID := bf.ReadUint32() + for _, alliance := range tempAlliances { + if alliance.ParentGuild.LeaderCharID == ID { + alliances = append(alliances, alliance) + } + } + case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_MEMBERS: + sort.Slice(tempAlliances, func(i, j int) bool { + return tempAlliances[i].TotalMembers < tempAlliances[j].TotalMembers + }) + alliances = tempAlliances + case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_REGISTRATION: + sort.Slice(tempAlliances, func(i, j int) bool { + return tempAlliances[i].CreatedAt.Unix() < tempAlliances[j].CreatedAt.Unix() + }) + alliances = tempAlliances + } + } + + if err != nil || (guilds == nil && alliances == nil) { stubEnumerateNoResults(s, pkt.AckHandle) return } bf = byteframe.NewByteFrame() - bf.WriteUint16(uint16(len(guilds))) - bf.WriteUint8(0x01) // Unk - - for _, guild := range guilds { - bf.WriteUint32(guild.ID) - bf.WriteUint32(guild.LeaderCharID) - bf.WriteUint16(guild.MemberCount) - bf.WriteUint16(0x0000) // Unk - bf.WriteUint16(guild.Rank) // OR guilds in alliance - bf.WriteUint32(uint32(guild.CreatedAt.Unix())) - ps.Uint8(bf, guild.Name, true) - ps.Uint8(bf, guild.LeaderName, true) + if pkt.Type > 8 { + bf.WriteUint16(uint16(len(alliances))) + for _, alliance := range alliances { + bf.WriteUint8(0x00) // Unk + bf.WriteUint32(alliance.ID) + bf.WriteUint32(alliance.ParentGuild.LeaderCharID) + bf.WriteUint16(alliance.TotalMembers) + bf.WriteUint16(0x0000) + if alliance.SubGuild1ID == 0 && alliance.SubGuild2ID == 0 { + bf.WriteUint16(1) + } else if alliance.SubGuild1ID > 0 && alliance.SubGuild2ID == 0 || alliance.SubGuild1ID == 0 && alliance.SubGuild2ID > 0 { + bf.WriteUint16(2) + } else { + bf.WriteUint16(3) + } + bf.WriteUint32(uint32(alliance.CreatedAt.Unix())) + ps.Uint8(bf, alliance.Name, true) + ps.Uint8(bf, alliance.ParentGuild.LeaderName, true) + bf.WriteUint8(0x01) // Unk + bf.WriteBool(true) // TODO: Enable GuildAlliance applications + } + } else { bf.WriteUint8(0x01) // Unk - bf.WriteBool(!guild.Recruiting) + bf.WriteUint16(uint16(len(guilds))) + for _, guild := range guilds { + bf.WriteUint32(guild.ID) + bf.WriteUint32(guild.LeaderCharID) + bf.WriteUint16(guild.MemberCount) + bf.WriteUint16(0x0000) // Unk + bf.WriteUint16(guild.Rank) // OR guilds in alliance + bf.WriteUint32(uint32(guild.CreatedAt.Unix())) + ps.Uint8(bf, guild.Name, true) + ps.Uint8(bf, guild.LeaderName, true) + bf.WriteUint8(0x01) // Unk + bf.WriteBool(!guild.Recruiting) + } } doAckBufSucceed(s, pkt.AckHandle, bf.Data()) diff --git a/server/channelserver/handlers_guild_alliance.go b/server/channelserver/handlers_guild_alliance.go index 77f204adc..8f3a6313e 100644 --- a/server/channelserver/handlers_guild_alliance.go +++ b/server/channelserver/handlers_guild_alliance.go @@ -1,6 +1,8 @@ package channelserver import ( + "erupe-ce/common/byteframe" + ps "erupe-ce/common/pascalstring" "fmt" "time" @@ -149,9 +151,54 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) } default: - panic(fmt.Sprintf("Unhandled operate joint action '%d'", pkt.Action)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + panic(fmt.Sprintf("Unhandled operate joint action '%d'", pkt.Action)) } } -func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfInfoJoint) + bf := byteframe.NewByteFrame() + alliance, err := GetAllianceData(s, pkt.AllianceID) + if err != nil { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + } else { + bf.WriteUint32(alliance.ID) + bf.WriteUint32(uint32(alliance.CreatedAt.Unix())) + bf.WriteUint16(alliance.TotalMembers) + bf.WriteUint16(0x0000) // Unk + ps.Uint16(bf, alliance.Name, true) + if alliance.SubGuild1ID > 0 { + if alliance.SubGuild2ID > 0 { + bf.WriteUint8(3) + } else { + bf.WriteUint8(2) + } + } else { + bf.WriteUint8(1) + } + bf.WriteUint32(alliance.ParentGuildID) + bf.WriteUint32(alliance.ParentGuild.LeaderCharID) + bf.WriteUint16(alliance.ParentGuild.Rank) + bf.WriteUint16(alliance.ParentGuild.MemberCount) + ps.Uint16(bf, alliance.ParentGuild.Name, true) + ps.Uint16(bf, alliance.ParentGuild.LeaderName, true) + if alliance.SubGuild1ID > 0 { + bf.WriteUint32(alliance.SubGuild1ID) + bf.WriteUint32(alliance.SubGuild1.LeaderCharID) + bf.WriteUint16(alliance.SubGuild1.Rank) + bf.WriteUint16(alliance.SubGuild1.MemberCount) + ps.Uint16(bf, alliance.SubGuild1.Name, true) + ps.Uint16(bf, alliance.SubGuild1.LeaderName, true) + } + if alliance.SubGuild2ID > 0 { + bf.WriteUint32(alliance.SubGuild2ID) + bf.WriteUint32(alliance.SubGuild2.LeaderCharID) + bf.WriteUint16(alliance.SubGuild2.Rank) + bf.WriteUint16(alliance.SubGuild2.MemberCount) + ps.Uint16(bf, alliance.SubGuild2.Name, true) + ps.Uint16(bf, alliance.SubGuild2.LeaderName, true) + } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) + } +} From 34f0eb83158c3d97e14fb5ce0784554ff6a25021 Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 30 Sep 2022 23:54:16 +1000 Subject: [PATCH 33/95] handle leaving alliance --- server/channelserver/handlers_guild_alliance.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_guild_alliance.go b/server/channelserver/handlers_guild_alliance.go index 8f3a6313e..1d0960780 100644 --- a/server/channelserver/handlers_guild_alliance.go +++ b/server/channelserver/handlers_guild_alliance.go @@ -141,8 +141,15 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) { } case mhfpacket.OPERATE_JOINT_LEAVE: if guild.LeaderCharID == s.charID { - // delete alliance application - // or leave alliance + if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 { + s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID) + } else if guild.ID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 { + s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID) + } else { + s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID) + } + // TODO: Handle deleting Alliance applications + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } else { s.logger.Warn( "Non-owner of guild attempted alliance leave", From 665c2dd32fc7b5f9f5c912132064f9fce2e61e00 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 1 Oct 2022 00:10:00 +1000 Subject: [PATCH 34/95] handle alliance kicking --- network/mhfpacket/msg_mhf_operate_joint.go | 36 +++++++++---------- .../channelserver/handlers_guild_alliance.go | 20 +++++++++++ 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/network/mhfpacket/msg_mhf_operate_joint.go b/network/mhfpacket/msg_mhf_operate_joint.go index 9733a2278..1fa360d01 100644 --- a/network/mhfpacket/msg_mhf_operate_joint.go +++ b/network/mhfpacket/msg_mhf_operate_joint.go @@ -1,28 +1,28 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) type OperateJointAction uint8 const ( - OPERATE_JOINT_DISBAND = 0x01 - OPERATE_JOINT_LEAVE = 0x03 - OPERATE_JOINT_KICK = 0x09 + OPERATE_JOINT_DISBAND = 0x01 + OPERATE_JOINT_LEAVE = 0x03 + OPERATE_JOINT_KICK = 0x09 ) // MsgMhfOperateJoint represents the MSG_MHF_OPERATE_JOINT type MsgMhfOperateJoint struct { - AckHandle uint32 - AllianceID uint32 - GuildID uint32 - Action OperateJointAction - UnkData []byte + AckHandle uint32 + AllianceID uint32 + GuildID uint32 + Action OperateJointAction + UnkData *byteframe.ByteFrame } // Opcode returns the ID associated with this packet type. @@ -32,13 +32,13 @@ func (m *MsgMhfOperateJoint) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfOperateJoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.AckHandle = bf.ReadUint32() - m.AllianceID = bf.ReadUint32() - m.GuildID = bf.ReadUint32() - m.Action = OperateJointAction(bf.ReadUint8()) - m.UnkData = bf.DataFromCurrent() - bf.Seek(int64(len(bf.Data()) - 2), 0) - return nil + m.AckHandle = bf.ReadUint32() + m.AllianceID = bf.ReadUint32() + m.GuildID = bf.ReadUint32() + m.Action = OperateJointAction(bf.ReadUint8()) + m.UnkData = byteframe.NewByteFrameFromBytes(bf.DataFromCurrent()) + bf.Seek(int64(len(bf.Data())-2), 0) + return nil } // Build builds a binary packet from the current data. diff --git a/server/channelserver/handlers_guild_alliance.go b/server/channelserver/handlers_guild_alliance.go index 1d0960780..7e2a9a2ac 100644 --- a/server/channelserver/handlers_guild_alliance.go +++ b/server/channelserver/handlers_guild_alliance.go @@ -157,6 +157,26 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) { ) doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) } + case mhfpacket.OPERATE_JOINT_KICK: + if alliance.ParentGuild.LeaderCharID == s.charID { + _ = pkt.UnkData.ReadUint8() + kickedGuildID := pkt.UnkData.ReadUint32() + if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 { + s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID) + } else if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 { + s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = NULL WHERE id = $1`, alliance.ID) + } else { + s.server.db.Exec(`UPDATE guild_alliances SET sub2_id = NULL WHERE id = $1`, alliance.ID) + } + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + } else { + s.logger.Warn( + "Non-owner of alliance attempted kick", + zap.Uint32("CharID", s.charID), + zap.Uint32("AllyID", alliance.ID), + ) + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + } default: doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) panic(fmt.Sprintf("Unhandled operate joint action '%d'", pkt.Action)) From 8f9648d9d8af169151375b49c8a74e7e5e687def Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 1 Oct 2022 01:26:00 +1000 Subject: [PATCH 35/95] fix alliance enumeration bugs --- server/channelserver/handlers_guild.go | 28 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 5f56baf6d..53df91adb 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1197,14 +1197,28 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } } case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_MEMBERS: - sort.Slice(tempAlliances, func(i, j int) bool { - return tempAlliances[i].TotalMembers < tempAlliances[j].TotalMembers - }) + sorting := bf.ReadBool() + if sorting { + sort.Slice(tempAlliances, func(i, j int) bool { + return tempAlliances[i].TotalMembers > tempAlliances[j].TotalMembers + }) + } else { + sort.Slice(tempAlliances, func(i, j int) bool { + return tempAlliances[i].TotalMembers < tempAlliances[j].TotalMembers + }) + } alliances = tempAlliances case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_REGISTRATION: - sort.Slice(tempAlliances, func(i, j int) bool { - return tempAlliances[i].CreatedAt.Unix() < tempAlliances[j].CreatedAt.Unix() - }) + sorting := bf.ReadBool() + if sorting { + sort.Slice(tempAlliances, func(i, j int) bool { + return tempAlliances[i].CreatedAt.Unix() > tempAlliances[j].CreatedAt.Unix() + }) + } else { + sort.Slice(tempAlliances, func(i, j int) bool { + return tempAlliances[i].CreatedAt.Unix() < tempAlliances[j].CreatedAt.Unix() + }) + } alliances = tempAlliances } } @@ -1218,8 +1232,8 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { if pkt.Type > 8 { bf.WriteUint16(uint16(len(alliances))) + bf.WriteUint8(0x00) // Unk for _, alliance := range alliances { - bf.WriteUint8(0x00) // Unk bf.WriteUint32(alliance.ID) bf.WriteUint32(alliance.ParentGuild.LeaderCharID) bf.WriteUint16(alliance.TotalMembers) From a5b47310d134d7d027712f7c83f778e05c91d695 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 4 Oct 2022 20:23:13 +1100 Subject: [PATCH 36/95] clean up guild queries --- server/channelserver/handlers_guild.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 53df91adb..8891f23ee 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -164,7 +164,7 @@ func (guild *Guild) Save(s *Session) error { func (guild *Guild) CreateApplication(s *Session, charID uint32, applicationType GuildApplicationType, transaction *sql.Tx) error { - sql := ` + query := ` INSERT INTO guild_applications (guild_id, character_id, actor_id, application_type) VALUES ($1, $2, $3, $4) ` @@ -172,9 +172,9 @@ func (guild *Guild) CreateApplication(s *Session, charID uint32, applicationType var err error if transaction == nil { - _, err = s.server.db.Exec(sql, guild.ID, charID, s.charID, applicationType) + _, err = s.server.db.Exec(query, guild.ID, charID, s.charID, applicationType) } else { - _, err = transaction.Exec(sql, guild.ID, charID, s.charID, applicationType) + _, err = transaction.Exec(query, guild.ID, charID, s.charID, applicationType) } if err != nil { @@ -222,7 +222,7 @@ func (guild *Guild) Disband(s *Session) error { return err } - _, err = transaction.Exec("UPDATE guild_alliances SET sub1_id=NULL WHERE sub1_id=$1", guild.ID) + _, err = transaction.Exec("UPDATE guild_alliances SET sub1_id=sub2_id, sub2_id=NULL WHERE sub1_id=$1", guild.ID) if err != nil { s.logger.Error("failed to remove guild from alliance", zap.Error(err), zap.Uint32("guildID", guild.ID)) From c4505ce30dd021b9be2a41d5d546edb8e35ae570 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 4 Oct 2022 21:25:08 +1100 Subject: [PATCH 37/95] fix event exchange response --- server/channelserver/handlers_guild.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 8891f23ee..d5dc94264 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -723,10 +723,9 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, true)) case mhfpacket.OPERATE_GUILD_EVENT_EXCHANGE: rp := uint16(pkt.Data1.ReadUint32()) - saveData, _ := GetCharacterSaveData(s, s.charID) - saveData.RP -= rp - saveData.Save(s) - bf.WriteUint32(uint32(saveData.RP)) + 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) + bf.WriteUint32(balance) default: panic(fmt.Sprintf("unhandled operate guild action '%d'", pkt.Action)) } From 4fe56cd6e3044c4151c8b47307c272b484cde279 Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 5 Oct 2022 13:08:53 +1100 Subject: [PATCH 38/95] implement guild poogie outfits --- network/mhfpacket/msg_mhf_operate_guild.go | 10 +++-- patch-schema/guild-poogie-outfits.sql | 15 +++++++ server/channelserver/handlers_guild.go | 46 ++++++++++++++++++---- 3 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 patch-schema/guild-poogie-outfits.sql diff --git a/network/mhfpacket/msg_mhf_operate_guild.go b/network/mhfpacket/msg_mhf_operate_guild.go index f141796cb..a79719290 100644 --- a/network/mhfpacket/msg_mhf_operate_guild.go +++ b/network/mhfpacket/msg_mhf_operate_guild.go @@ -28,9 +28,13 @@ const ( OPERATE_GUILD_CHANGE_PUGI_1 = 0x0f OPERATE_GUILD_CHANGE_PUGI_2 = 0x10 OPERATE_GUILD_CHANGE_PUGI_3 = 0x11 - // pugi something - OPERATE_GUILD_DONATE_EVENT = 0x15 - OPERATE_GUILD_EVENT_EXCHANGE = 0x16 + OPERATE_GUILD_UNLOCK_OUTFIT = 0x12 + // 0x13 Unk + // 0x14 Unk + OPERATE_GUILD_DONATE_EVENT = 0x15 + OPERATE_GUILD_EVENT_EXCHANGE = 0x16 + // 0x17 Unk + // 0x18 Unk OPERATE_GUILD_CHANGE_DIVA_PUGI_1 = 0x19 OPERATE_GUILD_CHANGE_DIVA_PUGI_2 = 0x1a OPERATE_GUILD_CHANGE_DIVA_PUGI_3 = 0x1b diff --git a/patch-schema/guild-poogie-outfits.sql b/patch-schema/guild-poogie-outfits.sql new file mode 100644 index 000000000..b6ce2e4fa --- /dev/null +++ b/patch-schema/guild-poogie-outfits.sql @@ -0,0 +1,15 @@ +BEGIN; + +ALTER TABLE IF EXISTS public.guilds + ADD COLUMN IF NOT EXISTS pugi_outfit_1 int NOT NULL DEFAULT 0; + +ALTER TABLE IF EXISTS public.guilds + ADD COLUMN IF NOT EXISTS pugi_outfit_2 int NOT NULL DEFAULT 0; + +ALTER TABLE IF EXISTS public.guilds + ADD COLUMN IF NOT EXISTS pugi_outfit_3 int NOT NULL DEFAULT 0; + +ALTER TABLE IF EXISTS public.guilds + ADD COLUMN IF NOT EXISTS pugi_outfits int NOT NULL DEFAULT 0; + +END; \ No newline at end of file diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index d5dc94264..535d054f8 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -8,6 +8,7 @@ import ( "encoding/json" "errors" "fmt" + "math" "sort" "strings" "time" @@ -54,6 +55,10 @@ type Guild struct { PugiName1 string `db:"pugi_name_1"` PugiName2 string `db:"pugi_name_2"` PugiName3 string `db:"pugi_name_3"` + PugiOutfit1 uint8 `db:"pugi_outfit_1"` + PugiOutfit2 uint8 `db:"pugi_outfit_2"` + PugiOutfit3 uint8 `db:"pugi_outfit_3"` + PugiOutfits uint32 `db:"pugi_outfits"` Recruiting bool `db:"recruiting"` FestivalColour FestivalColour `db:"festival_colour"` Souls uint32 `db:"souls"` @@ -125,6 +130,10 @@ SELECT COALESCE(pugi_name_1, '') AS pugi_name_1, COALESCE(pugi_name_2, '') AS pugi_name_2, COALESCE(pugi_name_3, '') AS pugi_name_3, + pugi_outfit_1, + pugi_outfit_2, + pugi_outfit_3, + pugi_outfits, recruiting, COALESCE((SELECT team FROM festa_registrations fr WHERE fr.guild_id = g.id), 'none') AS festival_colour, (SELECT SUM(souls) FROM guild_characters gc WHERE gc.guild_id = g.id) AS souls, @@ -151,8 +160,10 @@ SELECT func (guild *Guild) Save(s *Session) error { _, err := s.server.db.Exec(` - UPDATE guilds SET main_motto=$2, sub_motto=$3, comment=$4, pugi_name_1=$5, pugi_name_2=$6, pugi_name_3=$7, icon=$8, leader_id=$9 WHERE id=$1 - `, guild.ID, guild.MainMotto, guild.SubMotto, guild.Comment, guild.PugiName1, guild.PugiName2, guild.PugiName3, guild.Icon, guild.GuildLeader.LeaderCharID) + UPDATE guilds SET main_motto=$2, sub_motto=$3, comment=$4, pugi_name_1=$5, pugi_name_2=$6, pugi_name_3=$7, + pugi_outfit_1=$8, pugi_outfit_2=$9, pugi_outfit_3=$10, pugi_outfits=$11, icon=$12, leader_id=$13 WHERE id=$1 + `, guild.ID, guild.MainMotto, guild.SubMotto, guild.Comment, guild.PugiName1, guild.PugiName2, guild.PugiName3, + guild.PugiOutfit1, guild.PugiOutfit2, guild.PugiOutfit3, guild.PugiOutfits, guild.Icon, guild.GuildLeader.LeaderCharID) if err != nil { s.logger.Error("failed to update guild data", zap.Error(err), zap.Uint32("guildID", guild.ID)) @@ -716,9 +727,14 @@ func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) { case mhfpacket.OPERATE_GUILD_RENAME_PUGI_3: handleRenamePugi(s, pkt.Data2, guild, 3) case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_1: - // TODO: decode guild poogie outfits + handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 1) case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_2: + handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 2) case mhfpacket.OPERATE_GUILD_CHANGE_PUGI_3: + handleChangePugi(s, uint8(pkt.Data1.ReadUint32()), guild, 3) + case mhfpacket.OPERATE_GUILD_UNLOCK_OUTFIT: + // 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: bf.WriteBytes(handleDonateRP(s, uint16(pkt.Data1.ReadUint32()), guild, true)) case mhfpacket.OPERATE_GUILD_EVENT_EXCHANGE: @@ -750,6 +766,18 @@ func handleRenamePugi(s *Session, bf *byteframe.ByteFrame, guild *Guild, num int guild.Save(s) } +func handleChangePugi(s *Session, outfit uint8, guild *Guild, num int) { + switch num { + case 1: + guild.PugiOutfit1 = outfit + case 2: + guild.PugiOutfit2 = outfit + case 3: + guild.PugiOutfit3 = outfit + } + guild.Save(s) +} + func handleDonateRP(s *Session, amount uint16, guild *Guild, isEvent bool) []byte { bf := byteframe.NewByteFrame() bf.WriteUint32(0) @@ -929,11 +957,13 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, guild.PugiName1, true) ps.Uint8(bf, guild.PugiName2, true) ps.Uint8(bf, guild.PugiName3, true) - - // probably guild pugi properties, should be status, stamina and luck outfits - bf.WriteBytes([]byte{ - 0x04, 0x02, 0x03, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0x4E, - }) + bf.WriteUint8(guild.PugiOutfit1) + bf.WriteUint8(guild.PugiOutfit2) + bf.WriteUint8(guild.PugiOutfit3) + 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 From d9541a6d1adb13d8138d3d9cad6b766ff696eaad Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 5 Oct 2022 13:33:14 +1100 Subject: [PATCH 39/95] rewrite dumpSaveData --- server/channelserver/handlers_data.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 5d179e50c..2cd8c7824 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -221,13 +221,22 @@ func dumpSaveData(s *Session, data []byte, suffix string) { } else { dir := filepath.Join(s.server.erupeConfig.DevModeOptions.SaveDumps.OutputDir, fmt.Sprintf("%d", s.charID)) path := filepath.Join(s.server.erupeConfig.DevModeOptions.SaveDumps.OutputDir, fmt.Sprintf("%d", s.charID), fmt.Sprintf("%d_%s.bin", s.charID, suffix)) - - if _, err := os.Stat(dir); os.IsNotExist(err) { - os.Mkdir(dir, os.ModeDir) - } - err := ioutil.WriteFile(path, data, 0644) + _, err := os.Stat(dir) if err != nil { - s.logger.Fatal("Error dumping savedata", zap.Error(err)) + if os.IsNotExist(err) { + err = os.Mkdir(dir, os.ModeDir) + if err != nil { + s.logger.Warn("Error dumping savedata, could not create folder") + return + } + } else { + s.logger.Warn("Error dumping savedata") + return + } + } + err = os.WriteFile(path, data, 0644) + if err != nil { + s.logger.Warn("Error dumping savedata, could not write file", zap.Error(err)) } } } From 4f2a94cc50934fa6ec79f27e2e12df94e6d1d4fb Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 6 Oct 2022 02:23:01 +1100 Subject: [PATCH 40/95] partially decode TerminalLog --- network/mhfpacket/msg_sys_terminal_log.go | 29 +++++++++++------------ server/channelserver/handlers.go | 9 +++++-- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/network/mhfpacket/msg_sys_terminal_log.go b/network/mhfpacket/msg_sys_terminal_log.go index 862462e59..536d35f18 100644 --- a/network/mhfpacket/msg_sys_terminal_log.go +++ b/network/mhfpacket/msg_sys_terminal_log.go @@ -1,17 +1,19 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // TerminalLogEntry represents an entry in the MSG_SYS_TERMINAL_LOG packet. type TerminalLogEntry struct { - // Unknown fields - U0, U1, U2, U3, U4, U5, U6, U7, U8 uint32 + Index uint32 + Type1 uint8 + Type2 uint8 + Data []int16 } // MsgSysTerminalLog represents the MSG_SYS_TERMINAL_LOG @@ -37,15 +39,12 @@ func (m *MsgSysTerminalLog) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client for i := 0; i < int(m.EntryCount); i++ { e := &TerminalLogEntry{} - e.U0 = bf.ReadUint32() - e.U1 = bf.ReadUint32() - e.U2 = bf.ReadUint32() - e.U3 = bf.ReadUint32() - e.U4 = bf.ReadUint32() - e.U5 = bf.ReadUint32() - e.U6 = bf.ReadUint32() - e.U7 = bf.ReadUint32() - e.U8 = bf.ReadUint32() + e.Index = bf.ReadUint32() + e.Type1 = bf.ReadUint8() + e.Type2 = bf.ReadUint8() + for j := 0; j < 15; j++ { + e.Data = append(e.Data, bf.ReadInt16()) + } m.Entries = append(m.Entries, e) } diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 2e348c138..3bde5d2bf 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -118,9 +118,14 @@ func handleMsgSysAck(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysTerminalLog(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysTerminalLog) + for i := range pkt.Entries { + s.server.logger.Info("SysTerminalLog", + zap.Uint8("Type1", pkt.Entries[i].Type1), + zap.Uint8("Type2", pkt.Entries[i].Type2), + zap.Int16s("Data", pkt.Entries[i].Data)) + } resp := byteframe.NewByteFrame() - - resp.WriteUint32(0x98bd51a9) // LogID to use for requests after this. + resp.WriteUint32(pkt.LogID + 1) // LogID to use for requests after this. doAckSimpleSucceed(s, pkt.AckHandle, resp.Data()) } From 6ee9234745b5af2b29d23521eaff2f97c5f7424d Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 8 Oct 2022 13:59:48 +1100 Subject: [PATCH 41/95] fix various savedata bugs --- server/channelserver/handlers_character.go | 31 ++++++++++++---------- server/channelserver/handlers_data.go | 2 +- server/signserver/dbutils.go | 2 +- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index 78a0b4754..118308aef 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -97,8 +97,8 @@ func (save *CharacterSaveData) Save(s *Session) { return } - _, err = s.server.db.Exec(`UPDATE characters SET savedata=$1, is_new_character=$2, hrp=$3, gr=$4, is_female=$5, weapon_type=$6, weapon_id=$7 WHERE id=$8 - `, save.compSave, save.IsNewCharacter, save.HRP, save.GR, save.Gender, save.WeaponType, save.WeaponID, save.CharID) + _, err = s.server.db.Exec(`UPDATE characters SET savedata=$1, is_new_character=false, hrp=$2, gr=$3, is_female=$4, weapon_type=$5, weapon_id=$6 WHERE id=$7 + `, save.compSave, save.HRP, save.GR, save.Gender, save.WeaponType, save.WeaponID, save.CharID) if err != nil { s.logger.Error("Failed to update savedata", zap.Error(err), zap.Uint32("charID", save.CharID)) } @@ -140,18 +140,21 @@ func (save *CharacterSaveData) updateStructWithSaveData() { } else { save.Gender = false } - save.RP = binary.LittleEndian.Uint16(save.decompSave[pointerRP : pointerRP+2]) - save.HouseTier = save.decompSave[pointerHouseTier : pointerHouseTier+5] - save.HouseData = save.decompSave[pointerHouseData : pointerHouseData+195] - save.BookshelfData = save.decompSave[pointerBookshelfData : pointerBookshelfData+5576] - save.GalleryData = save.decompSave[pointerGalleryData : pointerGalleryData+1748] - save.ToreData = save.decompSave[pointerToreData : pointerToreData+240] - save.GardenData = save.decompSave[pointerGardenData : pointerGardenData+68] - save.WeaponType = save.decompSave[pointerWeaponType] - save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[pointerWeaponID : pointerWeaponID+2]) - save.HRP = binary.LittleEndian.Uint16(save.decompSave[pointerHRP : pointerHRP+2]) - save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4])) - save.KQF = save.decompSave[pointerKQF : pointerKQF+8] + if !save.IsNewCharacter { + save.RP = binary.LittleEndian.Uint16(save.decompSave[pointerRP : pointerRP+2]) + save.HouseTier = save.decompSave[pointerHouseTier : pointerHouseTier+5] + save.HouseData = save.decompSave[pointerHouseData : pointerHouseData+195] + save.BookshelfData = save.decompSave[pointerBookshelfData : pointerBookshelfData+5576] + save.GalleryData = save.decompSave[pointerGalleryData : pointerGalleryData+1748] + save.ToreData = save.decompSave[pointerToreData : pointerToreData+240] + save.GardenData = save.decompSave[pointerGardenData : pointerGardenData+68] + save.WeaponType = save.decompSave[pointerWeaponType] + save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[pointerWeaponID : pointerWeaponID+2]) + save.HRP = binary.LittleEndian.Uint16(save.decompSave[pointerHRP : pointerHRP+2]) + save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4])) + save.KQF = save.decompSave[pointerKQF : pointerKQF+8] + } + return } func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) { diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 2cd8c7824..b641d3973 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -45,7 +45,7 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { s.logger.Info("Updating save with blob") characterSaveData.decompSave = saveData } - characterSaveData.IsNewCharacter = false + characterSaveData.updateStructWithSaveData() characterSaveData.Save(s) s.logger.Info("Wrote recompressed savedata back to DB.") diff --git a/server/signserver/dbutils.go b/server/signserver/dbutils.go index d39d96c92..5e99d4c85 100644 --- a/server/signserver/dbutils.go +++ b/server/signserver/dbutils.go @@ -63,7 +63,7 @@ func (s *Server) registerDBAccount(username string, password string) error { INSERT INTO characters ( user_id, is_female, is_new_character, name, unk_desc_string, hrp, gr, weapon_type, last_login) - VALUES($1, False, True, '', '', 1, 0, 0, $2)`, + VALUES($1, False, True, '', '', 0, 0, 0, $2)`, id, uint32(time.Now().Unix()), ) From bc7b30afed61ef0eec2e7c2cdf2b31b5234b6476 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 9 Oct 2022 00:47:09 +1100 Subject: [PATCH 42/95] dump goocoo savedata --- server/channelserver/handlers.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 3bde5d2bf..bda3eb352 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -753,6 +753,7 @@ func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint8(gook.NameLen) bf.WriteBytes(gook.Name) s.server.db.Exec(fmt.Sprintf("UPDATE gook SET gook%d=$1 WHERE id=$2", gook.Index), bf.Data(), s.charID) + dumpSaveData(s, bf.Data(), fmt.Sprintf("goocoo-%d", gook.Index)) } } doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) From 748d2542e2675074954a31209dabf0315795d735 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 9 Oct 2022 04:30:02 +1100 Subject: [PATCH 43/95] fix guild enumeration --- server/channelserver/handlers_guild.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 535d054f8..a45dfd4a4 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1281,8 +1281,8 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteBool(true) // TODO: Enable GuildAlliance applications } } else { - bf.WriteUint8(0x01) // Unk bf.WriteUint16(uint16(len(guilds))) + bf.WriteUint8(0x01) // Unk for _, guild := range guilds { bf.WriteUint32(guild.ID) bf.WriteUint32(guild.LeaderCharID) From 1152ec89709ae9545c2144fcdab91a9aa795ebbc Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 9 Oct 2022 05:14:11 +1100 Subject: [PATCH 44/95] fix default GR1 --- server/channelserver/handlers_character.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index 118308aef..a3e671969 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -151,7 +151,9 @@ func (save *CharacterSaveData) updateStructWithSaveData() { save.WeaponType = save.decompSave[pointerWeaponType] save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[pointerWeaponID : pointerWeaponID+2]) save.HRP = binary.LittleEndian.Uint16(save.decompSave[pointerHRP : pointerHRP+2]) - save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4])) + if save.HRP == uint16(999) { + save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[pointerGRP : pointerGRP+4])) + } save.KQF = save.decompSave[pointerKQF : pointerKQF+8] } return From 6cffb84606d76c33fe951554ed44ba5528f9a7f5 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 9 Oct 2022 05:49:38 +1100 Subject: [PATCH 45/95] repository cleanup --- .github/workflows/go.yml | 4 +- bin/questlists/.gitkeep | 0 bin/questlists/psql.txt | 16 -- bundled-schema/FestaDefaults.sql | 260 ++++++++++++++++++ .../RoadShopItems.csv | 0 5 files changed, 262 insertions(+), 18 deletions(-) create mode 100644 bin/questlists/.gitkeep delete mode 100644 bin/questlists/psql.txt create mode 100644 bundled-schema/FestaDefaults.sql rename RoadShopItems.csv => bundled-schema/RoadShopItems.csv (100%) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 2f56c0f75..c33872e81 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -27,7 +27,7 @@ jobs: ./www/ ./savedata/ ./bin/ - ./RoadShopItems.csv + ./bundled-schema/ - name: Build Windows-amd64 run: env GOOS=windows GOARCH=amd64 go build -v @@ -42,4 +42,4 @@ jobs: ./www/ ./savedata/ ./bin/ - ./RoadShopItems.csv + ./bundled-schema/ diff --git a/bin/questlists/.gitkeep b/bin/questlists/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/bin/questlists/psql.txt b/bin/questlists/psql.txt deleted file mode 100644 index 7429718e4..000000000 --- a/bin/questlists/psql.txt +++ /dev/null @@ -1,16 +0,0 @@ -BEGIN; - -CREATE TABLE questlists ( - ind int NOT NULL PRIMARY KEY, - questlist bytea -); - -END; - -INSERT INTO questlists (ind, questlist) VALUES ('0', pg_read_binary_file('c:\save\quest_0_0.bin')); -INSERT INTO questlists (ind, questlist) VALUES ('42', pg_read_binary_file('c:\save\quest_42_2A.bin')); -INSERT INTO questlists (ind, questlist) VALUES ('84', pg_read_binary_file('c:\save\quest_84_54.bin')); -INSERT INTO questlists (ind, questlist) VALUES ('126', pg_read_binary_file('c:\save\quest_126_7E.bin')); -INSERT INTO questlists (ind, questlist) VALUES ('168', pg_read_binary_file('c:\save\quest_168_A8.bin')); - - diff --git a/bundled-schema/FestaDefaults.sql b/bundled-schema/FestaDefaults.sql new file mode 100644 index 000000000..b8a3d46fc --- /dev/null +++ b/bundled-schema/FestaDefaults.sql @@ -0,0 +1,260 @@ +BEGIN; + +-- Ripped prizes +INSERT INTO public.festa_prizes + (type, tier, souls_req, item_id, num_item) +VALUES + ('personal', 1, 1, 9647, 7), + ('personal', 2, 1, 9647, 7), + ('personal', 3, 1, 9647, 7), + ('personal', 1, 200, 11284, 4), + ('personal', 2, 200, 11284, 4), + ('personal', 3, 200, 11284, 4), + ('personal', 1, 400, 11381, 3), + ('personal', 2, 400, 11381, 3), + ('personal', 3, 400, 11381, 3), + ('personal', 1, 600, 11284, 8), + ('personal', 2, 600, 11284, 8), + ('personal', 3, 600, 11284, 8), + ('personal', 1, 800, 11384, 3), + ('personal', 2, 800, 11384, 3), + ('personal', 3, 800, 11384, 3), + ('personal', 1, 1000, 11284, 12), + ('personal', 2, 1000, 11284, 12), + ('personal', 3, 1000, 11284, 12), + ('personal', 1, 1200, 11381, 5), + ('personal', 2, 1200, 11381, 5), + ('personal', 3, 1200, 11381, 5), + ('personal', 1, 1400, 11284, 16), + ('personal', 2, 1400, 11284, 16), + ('personal', 3, 1400, 11284, 16), + ('personal', 1, 1700, 11384, 5), + ('personal', 2, 1700, 11384, 5), + ('personal', 3, 1700, 11384, 5), + ('personal', 1, 2000, 11284, 16), + ('personal', 2, 2000, 11284, 16), + ('personal', 3, 2000, 11284, 16), + ('personal', 1, 2500, 11382, 4), + ('personal', 2, 2500, 11382, 4), + ('personal', 3, 2500, 11382, 4), + ('personal', 1, 3000, 11284, 24), + ('personal', 2, 3000, 11284, 24), + ('personal', 3, 3000, 11284, 24), + ('personal', 1, 4000, 11385, 4), + ('personal', 2, 4000, 11385, 4), + ('personal', 3, 4000, 11385, 4), + ('personal', 1, 5000, 11381, 11), + ('personal', 2, 5000, 11381, 11), + ('personal', 3, 5000, 11381, 11), + ('personal', 1, 6000, 5177, 5), + ('personal', 2, 6000, 5177, 5), + ('personal', 3, 6000, 5177, 5), + ('personal', 1, 7000, 11384, 11), + ('personal', 2, 7000, 11384, 11), + ('personal', 3, 7000, 11384, 11), + ('personal', 1, 10000, 11382, 8), + ('personal', 2, 10000, 11382, 8), + ('personal', 3, 10000, 11382, 8), + ('personal', 1, 15000, 11385, 4), + ('personal', 2, 15000, 11385, 4), + ('personal', 3, 15000, 11385, 4), + ('personal', 1, 20000, 11381, 13), + ('personal', 2, 20000, 11381, 13), + ('personal', 3, 20000, 11381, 13), + ('personal', 1, 25000, 11385, 4), + ('personal', 2, 25000, 11385, 4), + ('personal', 3, 25000, 11385, 4), + ('personal', 1, 30000, 11383, 1), + ('personal', 2, 30000, 11383, 1), + ('personal', 3, 30000, 11383, 1); + +INSERT INTO public.festa_prizes +(type, tier, souls_req, item_id, num_item) +VALUES + ('guild', 1, 100, 7468, 5), + ('guild', 2, 100, 7468, 5), + ('guild', 3, 100, 7465, 5), + ('guild', 1, 300, 7469, 5), + ('guild', 2, 300, 7469, 5), + ('guild', 3, 300, 7466, 5), + ('guild', 1, 700, 7470, 5), + ('guild', 2, 700, 7470, 5), + ('guild', 3, 700, 7467, 5), + ('guild', 1, 1500, 13405, 14), + ('guild', 1, 1500, 1520, 3), + ('guild', 2, 1500, 13405, 14), + ('guild', 2, 1500, 1520, 3), + ('guild', 3, 1500, 7011, 3), + ('guild', 3, 1500, 13405, 14), + ('guild', 1, 3000, 10201, 10), + ('guild', 2, 3000, 10201, 10), + ('guild', 3, 3000, 10201, 10), + ('guild', 1, 6000, 13895, 14), + ('guild', 1, 6000, 1520, 6), + ('guild', 2, 6000, 13895, 14), + ('guild', 2, 6000, 1520, 6), + ('guild', 3, 6000, 13895, 14), + ('guild', 3, 6000, 7011, 4), + ('guild', 1, 12000, 13406, 14), + ('guild', 1, 12000, 1520, 9), + ('guild', 2, 12000, 13406, 14), + ('guild', 2, 12000, 1520, 9), + ('guild', 3, 12000, 13406, 14), + ('guild', 3, 12000, 7011, 5), + ('guild', 1, 25000, 10207, 10), + ('guild', 2, 25000, 10207, 10), + ('guild', 3, 25000, 10207, 10), + ('guild', 1, 50000, 1520, 12), + ('guild', 1, 50000, 13896, 14), + ('guild', 2, 50000, 1520, 12), + ('guild', 2, 50000, 13896, 14), + ('guild', 3, 50000, 7011, 6), + ('guild', 3, 50000, 13896, 14), + ('guild', 1, 100000, 10201, 10), + ('guild', 2, 100000, 10201, 10), + ('guild', 3, 100000, 10201, 10), + ('guild', 1, 200000, 13406, 16), + ('guild', 2, 200000, 13406, 16), + ('guild', 3, 200000, 13406, 16), + ('guild', 1, 300000, 13896, 16), + ('guild', 2, 300000, 13896, 16), + ('guild', 3, 300000, 13896, 16), + ('guild', 1, 400000, 10207, 10), + ('guild', 2, 400000, 10207, 10), + ('guild', 3, 400000, 10207, 10), + ('guild', 1, 500000, 13407, 6), + ('guild', 1, 500000, 13897, 6), + ('guild', 2, 500000, 13407, 6), + ('guild', 2, 500000, 13897, 6), + ('guild', 3, 500000, 13407, 6), + ('guild', 3, 500000, 13897, 6); + +-- Ripped trials +INSERT INTO public.festa_trials + (objective, goal_id, times_req, locale_req, reward) +VALUES + (1,27,1,0,1), + (5,53034,0,0,400), + (5,22042,0,0,89), + (5,23397,0,0,89), + (1,28,1,0,1), + (1,68,1,0,1), + (1,6,1,0,2), + (1,38,1,0,2), + (1,20,1,0,3), + (1,39,1,0,4), + (1,48,1,0,4), + (1,67,1,0,4), + (1,93,1,0,4), + (1,22,1,0,5), + (1,52,1,0,5), + (1,101,1,0,5), + (1,1,1,0,5), + (1,37,1,0,5), + (1,15,1,0,5), + (1,45,1,0,5), + (1,74,1,0,5), + (1,78,1,0,5), + (1,103,1,0,5), + (1,51,1,0,6), + (1,17,1,0,6), + (1,21,1,0,6), + (1,92,1,0,6), + (1,47,1,0,7), + (1,46,1,0,7), + (1,26,1,0,7), + (1,14,1,0,7), + (1,11,1,0,7), + (1,44,1,0,8), + (1,43,1,0,8), + (1,49,1,0,8), + (1,40,1,0,8), + (1,76,1,0,8), + (1,89,1,0,8), + (1,94,1,0,8), + (1,96,1,0,8), + (1,75,1,0,8), + (1,91,1,0,8), + (1,53,1,0,9), + (1,80,1,0,9), + (1,42,1,0,9), + (1,79,1,0,9), + (1,81,1,0,10), + (1,41,1,0,10), + (1,82,1,0,10), + (1,90,1,0,10), + (1,149,1,0,10), + (1,85,1,0,11), + (1,95,1,0,11), + (1,121,1,0,11), + (1,142,1,0,11), + (1,141,1,0,11), + (1,146,1,0,12), + (1,147,1,0,12), + (1,148,1,0,12), + (1,151,1,0,12), + (1,152,1,0,12), + (1,159,1,0,12), + (1,153,1,0,12), + (1,162,1,0,12), + (1,111,1,0,13), + (1,110,1,0,13), + (1,112,1,0,13), + (1,109,1,0,14), + (1,169,1,0,15), + (2,33,1,0,6), + (2,104,1,0,8), + (2,119,1,0,8), + (2,120,1,0,8), + (2,54,1,0,8), + (2,59,1,0,8), + (2,64,1,0,8), + (2,65,1,0,8), + (2,99,1,0,9), + (2,83,1,0,9), + (2,84,1,0,10), + (2,77,1,0,10), + (2,106,1,0,10), + (2,55,1,0,10), + (2,58,1,0,10), + (2,7,1,0,10), + (2,50,1,0,11), + (2,131,1,0,11), + (2,129,1,0,11), + (2,140,1,0,11), + (2,122,1,0,11), + (2,126,1,0,11), + (2,127,1,0,11), + (2,128,1,0,11), + (2,130,1,0,11), + (2,139,1,0,11), + (2,144,1,0,11), + (2,150,1,0,11), + (2,158,1,0,11), + (2,164,1,0,15), + (2,165,1,0,15), + (2,2,1,7,15), + (2,36,1,0,15), + (2,71,1,0,15), + (2,108,1,0,15), + (2,116,1,0,15), + (2,107,1,0,15), + (2,154,1,0,17), + (2,166,1,0,17), + (2,170,1,0,18), + (3,31,1,0,1), + (3,8,1,0,3), + (3,123,1,0,8), + (3,105,1,0,9), + (3,125,1,0,11), + (3,115,1,0,12), + (3,114,1,0,12), + (3,161,1,0,12), + (4,670,1,0,1), + (4,671,1,0,1), + (4,672,1,0,1), + (4,675,1,0,1), + (4,673,1,0,1), + (4,674,1,0,1); + +END; \ No newline at end of file diff --git a/RoadShopItems.csv b/bundled-schema/RoadShopItems.csv similarity index 100% rename from RoadShopItems.csv rename to bundled-schema/RoadShopItems.csv From ced173be5e9c8c4e30714f888ec3105378e6a452 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 9 Oct 2022 06:33:18 +1100 Subject: [PATCH 46/95] translate RoadShopItems to SQL --- bundled-schema/RoadShopItems.csv | 911 ------------------------------ bundled-schema/RoadShopItems.sql | 918 +++++++++++++++++++++++++++++++ 2 files changed, 918 insertions(+), 911 deletions(-) delete mode 100644 bundled-schema/RoadShopItems.csv create mode 100644 bundled-schema/RoadShopItems.sql diff --git a/bundled-schema/RoadShopItems.csv b/bundled-schema/RoadShopItems.csv deleted file mode 100644 index 23e1b2102..000000000 --- a/bundled-schema/RoadShopItems.csv +++ /dev/null @@ -1,911 +0,0 @@ -10,6,1,2146,25,1,0,0,1,1,0,1,0,0 -10,6,2,2147,25,1,0,0,1,1,0,1,0,0 -10,6,3,2148,25,1,0,0,1,1,0,1,0,0 -10,6,4,2149,25,1,0,0,1,1,0,1,0,0 -10,6,5,2150,25,1,0,0,1,1,0,1,0,0 -10,6,6,2151,25,1,0,0,1,1,0,1,0,0 -10,6,7,2152,25,1,0,0,1,1,0,1,0,0 -10,6,8,2153,25,1,0,0,1,1,0,1,0,0 -10,6,9,2154,25,1,0,0,1,1,0,1,0,0 -10,6,10,2155,25,1,0,0,1,1,0,1,0,0 -10,6,11,4398,25,1,0,0,1,1,0,1,0,0 -10,6,12,12460,25,1,0,0,1,1,0,1,0,0 -10,6,13,12461,25,1,0,0,1,1,0,1,0,0 -10,6,14,12462,25,1,0,0,1,1,0,1,0,0 -10,6,15,12463,25,1,0,0,1,1,0,1,0,0 -10,6,16,12464,25,1,0,0,1,1,0,1,0,0 -10,6,17,12465,25,1,0,0,1,1,0,1,0,0 -10,6,18,12466,25,1,0,0,1,1,0,1,0,0 -10,6,19,12467,25,1,0,0,1,1,0,1,0,0 -10,6,20,12468,25,1,0,0,1,1,0,1,0,0 -10,6,21,12469,25,1,0,0,1,1,0,1,0,0 -10,6,22,15109,1000,1,0,0,1,1,0,1,0,0 -10,6,23,15110,1000,1,0,0,1,1,0,1,0,0 -10,6,24,2158,200,100,0,0,1,1,0,1,0,0 -10,6,25,12306,2,1,0,0,1,1,0,1,80,0 -10,6,26,12306,20000,10000,0,0,1,1,0,1,80,0 -10,4,27,11664,20000,1,0,0,1,1,0,1,0,0 -10,4,28,11665,20000,1,0,0,1,1,0,1,0,0 -10,4,29,11666,20000,1,0,0,1,1,0,1,0,0 -10,4,30,11667,20000,1,0,0,1,1,0,1,0,0 -10,4,31,11668,20000,1,0,0,1,1,0,1,0,0 -10,4,32,11669,20000,1,0,0,1,1,0,1,0,0 -10,4,33,11670,20000,1,0,0,1,1,0,1,0,0 -10,4,34,11671,20000,1,0,0,1,1,0,1,0,0 -10,4,35,11672,20000,1,0,0,1,1,0,1,0,0 -10,4,36,11673,20000,1,0,0,1,1,0,1,0,0 -10,4,37,11674,20000,1,0,0,1,1,0,1,0,0 -10,4,38,11675,20000,1,0,0,1,1,0,1,0,0 -10,4,39,11676,20000,1,0,0,1,1,0,1,0,0 -10,4,40,11677,20000,1,0,0,1,1,0,1,0,0 -10,4,41,11678,20000,1,0,0,1,1,0,1,0,0 -10,4,42,11679,20000,1,0,0,1,1,0,1,0,0 -10,4,43,11680,20000,1,0,0,1,1,0,1,0,0 -10,4,44,11681,20000,1,0,0,1,1,0,1,0,0 -10,4,45,11682,20000,1,0,0,1,1,0,1,0,0 -10,4,46,11683,20000,1,0,0,1,1,0,1,0,0 -10,4,47,11684,20000,1,0,0,1,1,0,1,0,0 -10,4,48,11685,20000,1,0,0,1,1,0,1,0,0 -10,4,49,11686,20000,1,0,0,1,1,0,1,0,0 -10,4,50,11687,20000,1,0,0,1,1,0,1,0,0 -10,4,51,11688,20000,1,0,0,1,1,0,1,0,0 -10,4,52,11689,20000,1,0,0,1,1,0,1,0,0 -10,4,53,11690,20000,1,0,0,1,1,0,1,0,0 -10,4,54,11691,20000,1,0,0,1,1,0,1,0,0 -10,4,55,11692,20000,1,0,0,1,1,0,1,0,0 -10,4,56,11693,20000,1,0,0,1,1,0,1,0,0 -10,4,57,11694,20000,1,0,0,1,1,0,1,0,0 -10,4,58,11695,20000,1,0,0,1,1,0,1,0,0 -10,4,59,11696,20000,1,0,0,1,1,0,1,0,0 -10,4,60,11697,20000,1,0,0,1,1,0,1,0,0 -10,4,61,12893,20000,1,0,0,1,1,0,1,0,0 -10,4,62,12894,20000,1,0,0,1,1,0,1,0,0 -10,4,63,12895,20000,1,0,0,1,1,0,1,0,0 -10,4,64,12896,20000,1,0,0,1,1,0,1,0,0 -10,4,65,12897,20000,1,0,0,1,1,0,1,0,0 -10,4,66,12898,20000,1,0,0,1,1,0,1,0,0 -10,4,67,12899,20000,1,0,0,1,1,0,1,0,0 -10,4,68,14337,20000,1,0,0,1,1,0,1,0,0 -10,4,69,14338,20000,1,0,0,1,1,0,1,0,0 -10,4,70,14339,20000,1,0,0,1,1,0,1,0,0 -10,4,71,14340,20000,1,0,0,1,1,0,1,0,0 -10,4,72,14341,20000,1,0,0,1,1,0,1,0,0 -10,4,73,14342,20000,1,0,0,1,1,0,1,0,0 -10,4,74,14343,20000,1,0,0,1,1,0,1,0,0 -10,4,75,14344,20000,1,0,0,1,1,0,1,0,0 -10,4,76,14345,20000,1,0,0,1,1,0,1,0,0 -10,4,77,9254,10000,1,0,0,1,1,0,1,0,0 -10,4,78,9255,10000,1,0,0,1,1,0,1,0,0 -10,4,79,9256,10000,1,0,0,1,1,0,1,0,0 -10,4,80,9257,10000,1,0,0,1,1,0,1,0,0 -10,4,81,9258,10000,1,0,0,1,1,0,1,0,0 -10,4,82,9259,10000,1,0,0,1,1,0,1,0,0 -10,4,83,9260,10000,1,0,0,1,1,0,1,0,0 -10,4,84,9261,10000,1,0,0,1,1,0,1,0,0 -10,4,85,9262,10000,1,0,0,1,1,0,1,0,0 -10,4,86,9263,10000,1,0,0,1,1,0,1,0,0 -10,4,87,9264,10000,1,0,0,1,1,0,1,0,0 -10,4,88,9265,10000,1,0,0,1,1,0,1,0,0 -10,4,89,9266,10000,1,0,0,1,1,0,1,0,0 -10,4,90,9267,10000,1,0,0,1,1,0,1,0,0 -10,4,91,9268,10000,1,0,0,1,1,0,1,0,0 -10,4,92,9269,10000,1,0,0,1,1,0,1,0,0 -10,4,93,9270,10000,1,0,0,1,1,0,1,0,0 -10,4,94,9271,10000,1,0,0,1,1,0,1,0,0 -10,4,95,9272,10000,1,0,0,1,1,0,1,0,0 -10,4,96,9273,10000,1,0,0,1,1,0,1,0,0 -10,4,97,9274,10000,1,0,0,1,1,0,1,0,0 -10,4,98,9275,10000,1,0,0,1,1,0,1,0,0 -10,4,99,9276,10000,1,0,0,1,1,0,1,0,0 -10,4,100,9277,10000,1,0,0,1,1,0,1,0,0 -10,4,101,9278,10000,1,0,0,1,1,0,1,0,0 -10,4,102,9279,10000,1,0,0,1,1,0,1,0,0 -10,4,103,9280,10000,1,0,0,1,1,0,1,0,0 -10,4,104,9281,10000,1,0,0,1,1,0,1,0,0 -10,4,105,9282,10000,1,0,0,1,1,0,1,0,0 -10,4,106,9283,10000,1,0,0,1,1,0,1,0,0 -10,4,107,9284,10000,1,0,0,1,1,0,1,0,0 -10,4,108,9285,10000,1,0,0,1,1,0,1,0,0 -10,4,109,9286,10000,1,0,0,1,1,0,1,0,0 -10,4,110,9287,10000,1,0,0,1,1,0,1,0,0 -10,4,111,9288,10000,1,0,0,1,1,0,1,0,0 -10,4,112,9289,10000,1,0,0,1,1,0,1,0,0 -10,4,113,9290,10000,1,0,0,1,1,0,1,0,0 -10,4,114,9291,10000,1,0,0,1,1,0,1,0,0 -10,4,115,9292,10000,1,0,0,1,1,0,1,0,0 -10,4,116,9293,10000,1,0,0,1,1,0,1,0,0 -10,4,117,9294,10000,1,0,0,1,1,0,1,0,0 -10,4,118,9295,10000,1,0,0,1,1,0,1,0,0 -10,4,119,9296,10000,1,0,0,1,1,0,1,0,0 -10,4,120,9297,10000,1,0,0,1,1,0,1,0,0 -10,4,121,9298,10000,1,0,0,1,1,0,1,0,0 -10,4,122,9299,10000,1,0,0,1,1,0,1,0,0 -10,4,123,9300,10000,1,0,0,1,1,0,1,0,0 -10,4,124,9301,10000,1,0,0,1,1,0,1,0,0 -10,4,125,13196,10000,1,0,0,1,1,0,1,0,0 -10,4,126,13197,10000,1,0,0,1,1,0,1,0,0 -10,4,127,13198,10000,1,0,0,1,1,0,1,0,0 -10,4,128,13199,10000,1,0,0,1,1,0,1,0,0 -10,4,129,15542,10000,1,0,0,1,1,0,1,0,0 -10,4,130,15543,10000,1,0,0,1,1,0,1,0,0 -10,4,131,15544,10000,1,0,0,1,1,0,1,0,0 -10,4,132,15545,10000,1,0,0,1,1,0,1,0,0 -10,4,133,13640,20000,1,0,0,1,1,0,1,0,0 -10,4,134,13641,20000,1,0,0,1,1,0,1,0,0 -10,4,135,13642,20000,1,0,0,1,1,0,1,0,0 -10,4,136,13643,20000,1,0,0,1,1,0,1,0,0 -10,4,137,13644,20000,1,0,0,1,1,0,1,0,0 -10,4,138,13645,20000,1,0,0,1,1,0,1,0,0 -10,4,139,13646,20000,1,0,0,1,1,0,1,0,0 -10,4,140,13647,20000,1,0,0,1,1,0,1,0,0 -10,4,141,13648,20000,1,0,0,1,1,0,1,0,0 -10,4,142,13649,20000,1,0,0,1,1,0,1,0,0 -10,4,143,13650,20000,1,0,0,1,1,0,1,0,0 -10,4,144,13651,20000,1,0,0,1,1,0,1,0,0 -10,4,145,13652,20000,1,0,0,1,1,0,1,0,0 -10,4,146,13653,20000,1,0,0,1,1,0,1,0,0 -10,4,147,13654,20000,1,0,0,1,1,0,1,0,0 -10,4,148,13655,20000,1,0,0,1,1,0,1,0,0 -10,4,149,13656,20000,1,0,0,1,1,0,1,0,0 -10,4,150,13657,20000,1,0,0,1,1,0,1,0,0 -10,4,151,13658,20000,1,0,0,1,1,0,1,0,0 -10,4,152,13659,20000,1,0,0,1,1,0,1,0,0 -10,4,153,13660,20000,1,0,0,1,1,0,1,0,0 -10,4,154,13661,20000,1,0,0,1,1,0,1,0,0 -10,4,155,13662,20000,1,0,0,1,1,0,1,0,0 -10,4,156,13663,20000,1,0,0,1,1,0,1,0,0 -10,4,157,13664,20000,1,0,0,1,1,0,1,0,0 -10,4,158,13665,20000,1,0,0,1,1,0,1,0,0 -10,4,159,13666,20000,1,0,0,1,1,0,1,0,0 -10,4,160,13667,20000,1,0,0,1,1,0,1,0,0 -10,4,161,13668,20000,1,0,0,1,1,0,1,0,0 -10,4,162,13669,20000,1,0,0,1,1,0,1,0,0 -10,4,163,13670,20000,1,0,0,1,1,0,1,0,0 -10,4,164,13671,20000,1,0,0,1,1,0,1,0,0 -10,4,165,13672,20000,1,0,0,1,1,0,1,0,0 -10,4,166,13673,20000,1,0,0,1,1,0,1,0,0 -10,4,167,13674,20000,1,0,0,1,1,0,1,0,0 -10,4,168,13675,20000,1,0,0,1,1,0,1,0,0 -10,4,169,13676,20000,1,0,0,1,1,0,1,0,0 -10,4,170,13677,20000,1,0,0,1,1,0,1,0,0 -10,4,171,13678,20000,1,0,0,1,1,0,1,0,0 -10,4,172,13679,20000,1,0,0,1,1,0,1,0,0 -10,4,173,13680,20000,1,0,0,1,1,0,1,0,0 -10,4,174,13681,20000,1,0,0,1,1,0,1,0,0 -10,4,175,13682,20000,1,0,0,1,1,0,1,0,0 -10,4,176,13683,20000,1,0,0,1,1,0,1,0,0 -10,4,177,13684,20000,1,0,0,1,1,0,1,0,0 -10,4,178,13685,20000,1,0,0,1,1,0,1,0,0 -10,4,179,13686,20000,1,0,0,1,1,0,1,0,0 -10,4,180,13687,20000,1,0,0,1,1,0,1,0,0 -10,4,181,13688,20000,1,0,0,1,1,0,1,0,0 -10,4,182,13689,20000,1,0,0,1,1,0,1,0,0 -10,4,183,13690,20000,1,0,0,1,1,0,1,0,0 -10,4,184,13691,20000,1,0,0,1,1,0,1,0,0 -10,4,185,15546,20000,1,0,0,1,1,0,1,0,0 -10,4,186,15547,20000,1,0,0,1,1,0,1,0,0 -10,4,187,15548,20000,1,0,0,1,1,0,1,0,0 -10,4,188,15549,20000,1,0,0,1,1,0,1,0,0 -10,4,189,16162,35000,1,0,0,1,1,0,1,0,0 -10,4,190,16163,35000,1,0,0,1,1,0,1,0,0 -10,4,191,16164,35000,1,0,0,1,1,0,1,0,0 -10,4,192,16165,35000,1,0,0,1,1,0,1,0,0 -10,4,193,16166,35000,1,0,0,1,1,0,1,0,0 -10,4,194,16167,35000,1,0,0,1,1,0,1,0,0 -10,4,195,16168,35000,1,0,0,1,1,0,1,0,0 -10,4,196,16169,35000,1,0,0,1,1,0,1,0,0 -10,4,197,16172,35000,1,0,0,1,1,0,1,0,0 -10,4,198,16173,35000,1,0,0,1,1,0,1,0,0 -10,4,199,16174,35000,1,0,0,1,1,0,1,0,0 -10,4,200,16175,35000,1,0,0,1,1,0,1,0,0 -10,4,201,16176,35000,1,0,0,1,1,0,1,0,0 -10,4,202,16177,35000,1,0,0,1,1,0,1,0,0 -10,4,203,16178,35000,1,0,0,1,1,0,1,0,0 -10,4,204,16179,35000,1,0,0,1,1,0,1,0,0 -10,4,205,16182,35000,1,0,0,1,1,0,1,0,0 -10,4,206,16183,35000,1,0,0,1,1,0,1,0,0 -10,4,207,16184,35000,1,0,0,1,1,0,1,0,0 -10,4,208,16185,35000,1,0,0,1,1,0,1,0,0 -10,4,209,16186,35000,1,0,0,1,1,0,1,0,0 -10,4,210,16187,35000,1,0,0,1,1,0,1,0,0 -10,4,211,16188,35000,1,0,0,1,1,0,1,0,0 -10,4,212,16189,35000,1,0,0,1,1,0,1,0,0 -10,4,213,16192,35000,1,0,0,1,1,0,1,0,0 -10,4,214,16193,35000,1,0,0,1,1,0,1,0,0 -10,4,215,16194,35000,1,0,0,1,1,0,1,0,0 -10,4,216,16195,35000,1,0,0,1,1,0,1,0,0 -10,4,217,16196,35000,1,0,0,1,1,0,1,0,0 -10,4,218,16197,35000,1,0,0,1,1,0,1,0,0 -10,4,219,16198,35000,1,0,0,1,1,0,1,0,0 -10,4,220,16199,35000,1,0,0,1,1,0,1,0,0 -10,4,221,16202,35000,1,0,0,1,1,0,1,0,0 -10,4,222,16203,35000,1,0,0,1,1,0,1,0,0 -10,4,223,16204,35000,1,0,0,1,1,0,1,0,0 -10,4,224,16205,35000,1,0,0,1,1,0,1,0,0 -10,4,225,16206,35000,1,0,0,1,1,0,1,0,0 -10,4,226,16207,35000,1,0,0,1,1,0,1,0,0 -10,4,227,16208,35000,1,0,0,1,1,0,1,0,0 -10,4,228,16209,35000,1,0,0,1,1,0,1,0,0 -10,4,229,16212,35000,1,0,0,1,1,0,1,0,0 -10,4,230,16213,35000,1,0,0,1,1,0,1,0,0 -10,4,231,16214,35000,1,0,0,1,1,0,1,0,0 -10,4,232,16215,35000,1,0,0,1,1,0,1,0,0 -10,4,233,16216,35000,1,0,0,1,1,0,1,0,0 -10,4,234,16217,35000,1,0,0,1,1,0,1,0,0 -10,4,235,16218,35000,1,0,0,1,1,0,1,0,0 -10,4,236,16219,35000,1,0,0,1,1,0,1,0,0 -10,4,237,16222,35000,1,0,0,1,1,0,1,0,0 -10,4,238,16223,35000,1,0,0,1,1,0,1,0,0 -10,4,239,16224,35000,1,0,0,1,1,0,1,0,0 -10,4,240,16225,35000,1,0,0,1,1,0,1,0,0 -10,4,241,16226,35000,1,0,0,1,1,0,1,0,0 -10,4,242,16227,35000,1,0,0,1,1,0,1,0,0 -10,4,243,16228,35000,1,0,0,1,1,0,1,0,0 -10,4,244,16229,35000,1,0,0,1,1,0,1,0,0 -10,4,245,16232,35000,1,0,0,1,1,0,1,0,0 -10,4,246,16233,35000,1,0,0,1,1,0,1,0,0 -10,4,247,16234,35000,1,0,0,1,1,0,1,0,0 -10,4,248,16235,35000,1,0,0,1,1,0,1,0,0 -10,4,249,16236,35000,1,0,0,1,1,0,1,0,0 -10,4,250,16237,35000,1,0,0,1,1,0,1,0,0 -10,4,251,16238,35000,1,0,0,1,1,0,1,0,0 -10,4,252,16239,35000,1,0,0,1,1,0,1,0,0 -10,4,253,16242,35000,1,0,0,1,1,0,1,0,0 -10,4,254,16243,35000,1,0,0,1,1,0,1,0,0 -10,4,255,16244,35000,1,0,0,1,1,0,1,0,0 -10,4,256,16245,35000,1,0,0,1,1,0,1,0,0 -10,4,257,16246,35000,1,0,0,1,1,0,1,0,0 -10,4,258,16247,35000,1,0,0,1,1,0,1,0,0 -10,4,259,16248,35000,1,0,0,1,1,0,1,0,0 -10,4,260,16249,35000,1,0,0,1,1,0,1,0,0 -10,4,261,16252,35000,1,0,0,1,1,0,1,0,0 -10,4,262,16253,35000,1,0,0,1,1,0,1,0,0 -10,4,263,16254,35000,1,0,0,1,1,0,1,0,0 -10,4,264,16255,35000,1,0,0,1,1,0,1,0,0 -10,4,265,16256,35000,1,0,0,1,1,0,1,0,0 -10,4,266,16257,35000,1,0,0,1,1,0,1,0,0 -10,4,267,16258,35000,1,0,0,1,1,0,1,0,0 -10,4,268,16259,35000,1,0,0,1,1,0,1,0,0 -10,4,269,16262,35000,1,0,0,1,1,0,1,0,0 -10,4,270,16263,35000,1,0,0,1,1,0,1,0,0 -10,4,271,16264,35000,1,0,0,1,1,0,1,0,0 -10,4,272,16265,35000,1,0,0,1,1,0,1,0,0 -10,4,273,16266,35000,1,0,0,1,1,0,1,0,0 -10,4,274,16267,35000,1,0,0,1,1,0,1,0,0 -10,4,275,16268,35000,1,0,0,1,1,0,1,0,0 -10,4,276,16269,35000,1,0,0,1,1,0,1,0,0 -10,4,277,16272,35000,1,0,0,1,1,0,1,0,0 -10,4,278,16273,35000,1,0,0,1,1,0,1,0,0 -10,4,279,16274,35000,1,0,0,1,1,0,1,0,0 -10,4,280,16275,35000,1,0,0,1,1,0,1,0,0 -10,4,281,16276,35000,1,0,0,1,1,0,1,0,0 -10,4,282,16277,35000,1,0,0,1,1,0,1,0,0 -10,4,283,16278,35000,1,0,0,1,1,0,1,0,0 -10,4,284,16279,35000,1,0,0,1,1,0,1,0,0 -10,4,285,16282,35000,1,0,0,1,1,0,1,0,0 -10,4,286,16283,35000,1,0,0,1,1,0,1,0,0 -10,4,287,16284,35000,1,0,0,1,1,0,1,0,0 -10,4,288,16285,35000,1,0,0,1,1,0,1,0,0 -10,4,289,16286,35000,1,0,0,1,1,0,1,0,0 -10,4,290,16287,35000,1,0,0,1,1,0,1,0,0 -10,4,291,16288,35000,1,0,0,1,1,0,1,0,0 -10,4,292,16289,35000,1,0,0,1,1,0,1,0,0 -10,4,293,16292,35000,1,0,0,1,1,0,1,0,0 -10,4,294,16293,35000,1,0,0,1,1,0,1,0,0 -10,4,295,16294,35000,1,0,0,1,1,0,1,0,0 -10,4,296,16295,35000,1,0,0,1,1,0,1,0,0 -10,4,297,16296,35000,1,0,0,1,1,0,1,0,0 -10,4,298,16297,35000,1,0,0,1,1,0,1,0,0 -10,4,299,16298,35000,1,0,0,1,1,0,1,0,0 -10,4,300,16299,35000,1,0,0,1,1,0,1,0,0 -10,8,301,14136,15000,1,0,0,1,1,0,1,0,0 -10,8,302,14137,15000,1,0,0,1,1,0,1,0,0 -10,8,303,14138,15000,1,0,0,1,1,0,1,0,0 -10,8,304,14139,15000,1,0,0,1,1,0,1,0,0 -10,8,305,14140,15000,1,0,0,1,1,0,1,0,0 -10,8,306,14141,15000,1,0,0,1,1,0,1,0,0 -10,8,307,14142,15000,1,0,0,1,1,0,1,0,0 -10,8,308,14143,15000,1,0,0,1,1,0,1,0,0 -10,8,309,14144,15000,1,0,0,1,1,0,1,0,0 -10,8,310,14145,15000,1,0,0,1,1,0,1,0,0 -10,8,311,14454,30000,1,0,0,1,1,0,1,0,0 -10,8,312,14455,30000,1,0,0,1,1,0,1,0,0 -10,8,313,14456,30000,1,0,0,1,1,0,1,0,0 -10,8,314,14457,30000,1,0,0,1,1,0,1,0,0 -10,8,315,14458,30000,1,0,0,1,1,0,1,0,0 -10,8,316,14459,30000,1,0,0,1,1,0,1,0,0 -10,8,317,14460,30000,1,0,0,1,1,0,1,0,0 -10,8,318,14461,30000,1,0,0,1,1,0,1,0,0 -10,8,319,14462,30000,1,0,0,1,1,0,1,0,0 -10,8,320,14463,30000,1,0,0,1,1,0,1,0,0 -10,8,321,12724,50000,1,0,0,1,1,0,1,0,0 -10,8,322,12725,50000,1,0,0,1,1,0,1,0,0 -10,8,323,12726,50000,1,0,0,1,1,0,1,0,0 -10,8,324,12727,50000,1,0,0,1,1,0,1,0,0 -10,8,325,12728,50000,1,0,0,1,1,0,1,0,0 -10,8,326,12729,50000,1,0,0,1,1,0,1,0,0 -10,8,327,12730,50000,1,0,0,1,1,0,1,0,0 -10,8,328,12731,50000,1,0,0,1,1,0,1,0,0 -10,8,329,12732,50000,1,0,0,1,1,0,1,0,0 -10,8,330,12733,50000,1,0,0,1,1,0,1,0,0 -10,8,331,12734,50000,1,0,0,1,1,0,1,0,0 -10,8,332,12735,50000,1,0,0,1,1,0,1,0,0 -10,8,333,12736,50000,1,0,0,1,1,0,1,0,0 -10,8,334,12737,50000,1,0,0,1,1,0,1,0,0 -10,8,335,12738,50000,1,0,0,1,1,0,1,0,0 -10,8,336,12739,50000,1,0,0,1,1,0,1,0,0 -10,8,337,12740,50000,1,0,0,1,1,0,1,0,0 -10,8,338,12741,50000,1,0,0,1,1,0,1,0,0 -10,8,339,12742,50000,1,0,0,1,1,0,1,0,0 -10,8,340,12743,50000,1,0,0,1,1,0,1,0,0 -10,8,341,12744,50000,1,0,0,1,1,0,1,0,0 -10,8,342,12745,50000,1,0,0,1,1,0,1,0,0 -10,8,343,12746,50000,1,0,0,1,1,0,1,0,0 -10,8,344,12747,50000,1,0,0,1,1,0,1,0,0 -10,8,345,12748,50000,1,0,0,1,1,0,1,0,0 -10,8,346,12749,50000,1,0,0,1,1,0,1,0,0 -10,8,347,12750,50000,1,0,0,1,1,0,1,0,0 -10,8,348,12751,50000,1,0,0,1,1,0,1,0,0 -10,8,349,12752,50000,1,0,0,1,1,0,1,0,0 -10,8,350,12753,50000,1,0,0,1,1,0,1,0,0 -10,8,351,15070,50000,1,0,0,1,1,0,1,0,0 -10,8,352,15071,50000,1,0,0,1,1,0,1,0,0 -10,8,353,15072,50000,1,0,0,1,1,0,1,0,0 -10,8,354,15073,50000,1,0,0,1,1,0,1,0,0 -10,8,355,15074,50000,1,0,0,1,1,0,1,0,0 -10,8,356,15075,50000,1,0,0,1,1,0,1,0,0 -10,8,357,15076,50000,1,0,0,1,1,0,1,0,0 -10,8,358,15077,50000,1,0,0,1,1,0,1,0,0 -10,8,359,15078,50000,1,0,0,1,1,0,1,0,0 -10,8,360,15079,50000,1,0,0,1,1,0,1,0,0 -10,8,361,15567,20000,1,0,0,1,1,0,1,0,0 -10,8,362,15568,20000,1,0,0,1,1,0,1,0,0 -10,8,363,15569,20000,1,0,0,1,1,0,1,0,0 -10,8,364,15570,20000,1,0,0,1,1,0,1,0,0 -10,8,365,15571,20000,1,0,0,1,1,0,1,0,0 -10,8,366,15572,20000,1,0,0,1,1,0,1,0,0 -10,8,367,15573,20000,1,0,0,1,1,0,1,0,0 -10,8,368,15574,20000,1,0,0,1,1,0,1,0,0 -10,8,369,15575,20000,1,0,0,1,1,0,1,0,0 -10,8,370,15576,20000,1,0,0,1,1,0,1,0,0 -10,8,371,15577,20000,1,0,0,1,1,0,1,0,0 -10,8,372,15578,20000,1,0,0,1,1,0,1,0,0 -10,8,373,15579,20000,1,0,0,1,1,0,1,0,0 -10,8,374,15580,20000,1,0,0,1,1,0,1,0,0 -10,8,375,15581,20000,1,0,0,1,1,0,1,0,0 -10,8,376,15582,20000,1,0,0,1,1,0,1,0,0 -10,8,377,15583,20000,1,0,0,1,1,0,1,0,0 -10,8,378,15584,20000,1,0,0,1,1,0,1,0,0 -10,8,379,15585,20000,1,0,0,1,1,0,1,0,0 -10,8,380,15586,20000,1,0,0,1,1,0,1,0,0 -10,8,381,15587,20000,1,0,0,1,1,0,1,0,0 -10,8,382,15588,20000,1,0,0,1,1,0,1,0,0 -10,8,383,15589,20000,1,0,0,1,1,0,1,0,0 -10,8,384,15590,20000,1,0,0,1,1,0,1,0,0 -10,8,385,15591,20000,1,0,0,1,1,0,1,0,0 -10,8,386,15592,20000,1,0,0,1,1,0,1,0,0 -10,8,387,15593,20000,1,0,0,1,1,0,1,0,0 -10,8,388,15594,20000,1,0,0,1,1,0,1,0,0 -10,8,389,15595,20000,1,0,0,1,1,0,1,0,0 -10,8,390,15596,20000,1,0,0,1,1,0,1,0,0 -10,8,391,15597,20000,1,0,0,1,1,0,1,0,0 -10,8,392,15598,20000,1,0,0,1,1,0,1,0,0 -10,8,393,15599,20000,1,0,0,1,1,0,1,0,0 -10,8,394,15600,20000,1,0,0,1,1,0,1,0,0 -10,8,395,15601,20000,1,0,0,1,1,0,1,0,0 -10,8,396,15602,20000,1,0,0,1,1,0,1,0,0 -10,8,397,15603,20000,1,0,0,1,1,0,1,0,0 -10,8,398,15604,20000,1,0,0,1,1,0,1,0,0 -10,8,399,15605,20000,1,0,0,1,1,0,1,0,0 -10,8,400,15606,20000,1,0,0,1,1,0,1,0,0 -10,8,401,15607,20000,1,0,0,1,1,0,1,0,0 -10,8,402,15608,20000,1,0,0,1,1,0,1,0,0 -10,8,403,15609,20000,1,0,0,1,1,0,1,0,0 -10,8,404,15610,20000,1,0,0,1,1,0,1,0,0 -10,8,405,15611,20000,1,0,0,1,1,0,1,0,0 -10,8,406,15612,20000,1,0,0,1,1,0,1,0,0 -10,8,407,15613,20000,1,0,0,1,1,0,1,0,0 -10,8,408,15614,20000,1,0,0,1,1,0,1,0,0 -10,8,409,15615,20000,1,0,0,1,1,0,1,0,0 -10,8,410,15616,20000,1,0,0,1,1,0,1,0,0 -10,8,411,15617,20000,1,0,0,1,1,0,1,0,0 -10,8,412,15618,20000,1,0,0,1,1,0,1,0,0 -10,8,413,15619,20000,1,0,0,1,1,0,1,0,0 -10,8,414,15620,20000,1,0,0,1,1,0,1,0,0 -10,8,415,15621,20000,1,0,0,1,1,0,1,0,0 -10,8,416,15622,20000,1,0,0,1,1,0,1,0,0 -10,8,417,15623,20000,1,0,0,1,1,0,1,0,0 -10,8,418,15624,20000,1,0,0,1,1,0,1,0,0 -10,8,419,15625,20000,1,0,0,1,1,0,1,0,0 -10,8,420,15626,20000,1,0,0,1,1,0,1,0,0 -10,8,421,15627,20000,1,0,0,1,1,0,1,0,0 -10,8,422,15628,20000,1,0,0,1,1,0,1,0,0 -10,8,423,15629,20000,1,0,0,1,1,0,1,0,0 -10,8,424,15630,20000,1,0,0,1,1,0,1,0,0 -10,8,425,15631,20000,1,0,0,1,1,0,1,0,0 -10,8,426,15632,20000,1,0,0,1,1,0,1,0,0 -10,8,427,15633,20000,1,0,0,1,1,0,1,0,0 -10,8,428,15634,20000,1,0,0,1,1,0,1,0,0 -10,8,429,15635,20000,1,0,0,1,1,0,1,0,0 -10,8,430,15636,20000,1,0,0,1,1,0,1,0,0 -10,8,431,15637,20000,1,0,0,1,1,0,1,0,0 -10,8,432,15638,20000,1,0,0,1,1,0,1,0,0 -10,8,433,15639,20000,1,0,0,1,1,0,1,0,0 -10,8,434,15640,20000,1,0,0,1,1,0,1,0,0 -10,8,435,15641,20000,1,0,0,1,1,0,1,0,0 -10,8,436,15642,20000,1,0,0,1,1,0,1,0,0 -10,8,437,15643,20000,1,0,0,1,1,0,1,0,0 -10,8,438,15644,20000,1,0,0,1,1,0,1,0,0 -10,8,439,15645,20000,1,0,0,1,1,0,1,0,0 -10,8,440,15646,20000,1,0,0,1,1,0,1,0,0 -10,8,441,15647,20000,1,0,0,1,1,0,1,0,0 -10,8,442,15648,20000,1,0,0,1,1,0,1,0,0 -10,8,443,15649,20000,1,0,0,1,1,0,1,0,0 -10,8,444,15650,20000,1,0,0,1,1,0,1,0,0 -10,8,445,15651,20000,1,0,0,1,1,0,1,0,0 -10,8,446,15652,20000,1,0,0,1,1,0,1,0,0 -10,8,447,15653,20000,1,0,0,1,1,0,1,0,0 -10,8,448,15654,20000,1,0,0,1,1,0,1,0,0 -10,8,449,15655,20000,1,0,0,1,1,0,1,0,0 -10,8,450,15656,20000,1,0,0,1,1,0,1,0,0 -10,8,451,15657,20000,1,0,0,1,1,0,1,0,0 -10,8,452,15658,20000,1,0,0,1,1,0,1,0,0 -10,8,453,15659,20000,1,0,0,1,1,0,1,0,0 -10,8,454,15660,20000,1,0,0,1,1,0,1,0,0 -10,8,455,15661,20000,1,0,0,1,1,0,1,0,0 -10,8,456,15662,20000,1,0,0,1,1,0,1,0,0 -10,8,457,15663,20000,1,0,0,1,1,0,1,0,0 -10,8,458,15664,20000,1,0,0,1,1,0,1,0,0 -10,8,459,15665,20000,1,0,0,1,1,0,1,0,0 -10,8,460,15666,20000,1,0,0,1,1,0,1,0,0 -10,8,461,15667,20000,1,0,0,1,1,0,1,0,0 -10,8,462,15668,20000,1,0,0,1,1,0,1,0,0 -10,8,463,15669,20000,1,0,0,1,1,0,1,0,0 -10,8,464,15670,20000,1,0,0,1,1,0,1,0,0 -10,8,465,15671,20000,1,0,0,1,1,0,1,0,0 -10,8,466,15672,20000,1,0,0,1,1,0,1,0,0 -10,8,467,15673,20000,1,0,0,1,1,0,1,0,0 -10,8,468,15674,20000,1,0,0,1,1,0,1,0,0 -10,8,469,15675,20000,1,0,0,1,1,0,1,0,0 -10,8,470,15676,20000,1,0,0,1,1,0,1,0,0 -10,8,471,15677,20000,1,0,0,1,1,0,1,0,0 -10,8,472,15678,20000,1,0,0,1,1,0,1,0,0 -10,8,473,15679,20000,1,0,0,1,1,0,1,0,0 -10,8,474,15680,20000,1,0,0,1,1,0,1,0,0 -10,8,475,15681,20000,1,0,0,1,1,0,1,0,0 -10,8,476,15682,20000,1,0,0,1,1,0,1,0,0 -10,8,477,15683,20000,1,0,0,1,1,0,1,0,0 -10,8,478,15684,20000,1,0,0,1,1,0,1,0,0 -10,8,479,15685,20000,1,0,0,1,1,0,1,0,0 -10,8,480,15686,20000,1,0,0,1,1,0,1,0,0 -10,8,481,15687,20000,1,0,0,1,1,0,1,0,0 -10,8,482,15688,20000,1,0,0,1,1,0,1,0,0 -10,8,483,15689,20000,1,0,0,1,1,0,1,0,0 -10,8,484,15690,20000,1,0,0,1,1,0,1,0,0 -10,8,485,15691,20000,1,0,0,1,1,0,1,0,0 -10,8,486,15692,20000,1,0,0,1,1,0,1,0,0 -10,8,487,15693,20000,1,0,0,1,1,0,1,0,0 -10,8,488,15694,20000,1,0,0,1,1,0,1,0,0 -10,8,489,15695,20000,1,0,0,1,1,0,1,0,0 -10,8,490,15696,20000,1,0,0,1,1,0,1,0,0 -10,8,491,15697,20000,1,0,0,1,1,0,1,0,0 -10,8,492,15698,20000,1,0,0,1,1,0,1,0,0 -10,8,493,15699,20000,1,0,0,1,1,0,1,0,0 -10,8,494,15700,20000,1,0,0,1,1,0,1,0,0 -10,8,495,15701,20000,1,0,0,1,1,0,1,0,0 -10,8,496,15702,20000,1,0,0,1,1,0,1,0,0 -10,8,497,15703,20000,1,0,0,1,1,0,1,0,0 -10,8,498,15704,20000,1,0,0,1,1,0,1,0,0 -10,8,499,15705,20000,1,0,0,1,1,0,1,0,0 -10,8,500,15706,20000,1,0,0,1,1,0,1,0,0 -10,8,501,15707,20000,1,0,0,1,1,0,1,0,0 -10,8,502,15708,20000,1,0,0,1,1,0,1,0,0 -10,8,503,15709,20000,1,0,0,1,1,0,1,0,0 -10,8,504,15710,20000,1,0,0,1,1,0,1,0,0 -10,8,505,15711,20000,1,0,0,1,1,0,1,0,0 -10,8,506,15712,20000,1,0,0,1,1,0,1,0,0 -10,8,507,15713,20000,1,0,0,1,1,0,1,0,0 -10,8,508,15714,20000,1,0,0,1,1,0,1,0,0 -10,8,509,15715,20000,1,0,0,1,1,0,1,0,0 -10,8,510,15716,20000,1,0,0,1,1,0,1,0,0 -10,8,511,15717,20000,1,0,0,1,1,0,1,0,0 -10,8,512,15718,20000,1,0,0,1,1,0,1,0,0 -10,8,513,15719,20000,1,0,0,1,1,0,1,0,0 -10,8,514,15720,20000,1,0,0,1,1,0,1,0,0 -10,8,515,15721,20000,1,0,0,1,1,0,1,0,0 -10,8,516,15722,20000,1,0,0,1,1,0,1,0,0 -10,8,517,15723,20000,1,0,0,1,1,0,1,0,0 -10,8,518,15724,20000,1,0,0,1,1,0,1,0,0 -10,8,519,15725,20000,1,0,0,1,1,0,1,0,0 -10,8,520,15726,20000,1,0,0,1,1,0,1,0,0 -10,8,521,15727,20000,1,0,0,1,1,0,1,0,0 -10,8,522,15728,20000,1,0,0,1,1,0,1,0,0 -10,8,523,15729,20000,1,0,0,1,1,0,1,0,0 -10,8,524,15730,20000,1,0,0,1,1,0,1,0,0 -10,8,525,15731,20000,1,0,0,1,1,0,1,0,0 -10,8,526,15732,20000,1,0,0,1,1,0,1,0,0 -10,8,527,15733,20000,1,0,0,1,1,0,1,0,0 -10,8,528,15734,20000,1,0,0,1,1,0,1,0,0 -10,8,529,15735,20000,1,0,0,1,1,0,1,0,0 -10,8,530,15736,20000,1,0,0,1,1,0,1,0,0 -10,8,531,15737,20000,1,0,0,1,1,0,1,0,0 -10,8,532,15738,20000,1,0,0,1,1,0,1,0,0 -10,8,533,15739,20000,1,0,0,1,1,0,1,0,0 -10,8,534,15740,20000,1,0,0,1,1,0,1,0,0 -10,8,535,15741,20000,1,0,0,1,1,0,1,0,0 -10,8,536,15742,20000,1,0,0,1,1,0,1,0,0 -10,8,537,15743,20000,1,0,0,1,1,0,1,0,0 -10,8,538,15744,20000,1,0,0,1,1,0,1,0,0 -10,8,539,15745,20000,1,0,0,1,1,0,1,0,0 -10,8,540,15746,20000,1,0,0,1,1,0,1,0,0 -10,8,541,15747,20000,1,0,0,1,1,0,1,0,0 -10,8,542,15748,20000,1,0,0,1,1,0,1,0,0 -10,8,543,15749,20000,1,0,0,1,1,0,1,0,0 -10,8,544,15750,20000,1,0,0,1,1,0,1,0,0 -10,8,545,15751,20000,1,0,0,1,1,0,1,0,0 -10,8,546,15752,20000,1,0,0,1,1,0,1,0,0 -10,8,547,15753,20000,1,0,0,1,1,0,1,0,0 -10,8,548,15754,20000,1,0,0,1,1,0,1,0,0 -10,8,549,15755,20000,1,0,0,1,1,0,1,0,0 -10,8,550,15756,20000,1,0,0,1,1,0,1,0,0 -10,8,551,15757,20000,1,0,0,1,1,0,1,0,0 -10,8,552,15758,20000,1,0,0,1,1,0,1,0,0 -10,8,553,15759,20000,1,0,0,1,1,0,1,0,0 -10,8,554,15760,20000,1,0,0,1,1,0,1,0,0 -10,8,555,15761,20000,1,0,0,1,1,0,1,0,0 -10,8,556,15762,20000,1,0,0,1,1,0,1,0,0 -10,8,557,15763,20000,1,0,0,1,1,0,1,0,0 -10,8,558,15764,20000,1,0,0,1,1,0,1,0,0 -10,8,559,15765,20000,1,0,0,1,1,0,1,0,0 -10,8,560,15766,20000,1,0,0,1,1,0,1,0,0 -10,8,561,15919,20000,1,0,0,1,1,0,1,0,0 -10,8,562,15920,20000,1,0,0,1,1,0,1,0,0 -10,8,563,15921,20000,1,0,0,1,1,0,1,0,0 -10,8,564,15922,20000,1,0,0,1,1,0,1,0,0 -10,8,565,15923,20000,1,0,0,1,1,0,1,0,0 -10,8,566,15924,20000,1,0,0,1,1,0,1,0,0 -10,8,567,15925,20000,1,0,0,1,1,0,1,0,0 -10,8,568,15926,20000,1,0,0,1,1,0,1,0,0 -10,8,569,15927,20000,1,0,0,1,1,0,1,0,0 -10,8,570,15928,20000,1,0,0,1,1,0,1,0,0 -10,8,571,15929,20000,1,0,0,1,1,0,1,0,0 -10,8,572,15930,20000,1,0,0,1,1,0,1,0,0 -10,8,573,15931,20000,1,0,0,1,1,0,1,0,0 -10,8,574,15932,20000,1,0,0,1,1,0,1,0,0 -10,8,575,15933,20000,1,0,0,1,1,0,1,0,0 -10,8,576,15934,20000,1,0,0,1,1,0,1,0,0 -10,8,577,15935,20000,1,0,0,1,1,0,1,0,0 -10,8,578,15936,20000,1,0,0,1,1,0,1,0,0 -10,8,579,15937,20000,1,0,0,1,1,0,1,0,0 -10,8,580,15938,20000,1,0,0,1,1,0,1,0,0 -10,8,581,15939,20000,1,0,0,1,1,0,1,0,0 -10,8,582,15940,20000,1,0,0,1,1,0,1,0,0 -10,8,583,15941,20000,1,0,0,1,1,0,1,0,0 -10,8,584,15942,20000,1,0,0,1,1,0,1,0,0 -10,8,585,15943,20000,1,0,0,1,1,0,1,0,0 -10,8,586,15944,20000,1,0,0,1,1,0,1,0,0 -10,8,587,15945,20000,1,0,0,1,1,0,1,0,0 -10,8,588,15946,20000,1,0,0,1,1,0,1,0,0 -10,8,589,15947,20000,1,0,0,1,1,0,1,0,0 -10,8,590,15948,20000,1,0,0,1,1,0,1,0,0 -10,8,591,15949,20000,1,0,0,1,1,0,1,0,0 -10,8,592,15950,20000,1,0,0,1,1,0,1,0,0 -10,8,593,15951,20000,1,0,0,1,1,0,1,0,0 -10,8,594,15952,20000,1,0,0,1,1,0,1,0,0 -10,8,595,15953,20000,1,0,0,1,1,0,1,0,0 -10,8,596,15954,20000,1,0,0,1,1,0,1,0,0 -10,8,597,15955,20000,1,0,0,1,1,0,1,0,0 -10,8,598,15956,20000,1,0,0,1,1,0,1,0,0 -10,8,599,15957,20000,1,0,0,1,1,0,1,0,0 -10,8,600,15958,20000,1,0,0,1,1,0,1,0,0 -10,8,601,15959,20000,1,0,0,1,1,0,1,0,0 -10,8,602,15960,20000,1,0,0,1,1,0,1,0,0 -10,8,603,15961,20000,1,0,0,1,1,0,1,0,0 -10,8,604,15962,20000,1,0,0,1,1,0,1,0,0 -10,8,605,15963,20000,1,0,0,1,1,0,1,0,0 -10,8,606,15964,20000,1,0,0,1,1,0,1,0,0 -10,8,607,15965,20000,1,0,0,1,1,0,1,0,0 -10,8,608,15966,20000,1,0,0,1,1,0,1,0,0 -10,8,609,15967,20000,1,0,0,1,1,0,1,0,0 -10,8,610,15968,20000,1,0,0,1,1,0,1,0,0 -10,7,611,13506,250,1,0,0,1,1,0,1,50,0 -10,7,612,15011,250,1,0,0,1,1,0,1,50,0 -10,7,613,13636,250,1,0,0,1,1,0,1,50,0 -10,7,614,1227,250,1,0,0,1,1,0,1,50,0 -10,7,615,15022,250,1,0,0,1,1,0,1,50,0 -10,8,616,4407,1000,1,0,0,1,1,0,1,0,0 -10,8,617,4408,1000,1,0,0,1,1,0,1,0,0 -10,8,618,4409,1000,1,0,0,1,1,0,1,0,0 -10,8,619,4410,1000,1,0,0,1,1,0,1,0,0 -10,8,620,4411,1000,1,0,0,1,1,0,1,0,0 -10,8,621,4412,1000,1,0,0,1,1,0,1,0,0 -10,8,622,4413,1000,1,0,0,1,1,0,1,0,0 -10,8,623,4414,1000,1,0,0,1,1,0,1,0,0 -10,8,624,4823,1000,1,0,0,1,1,0,1,0,0 -10,8,625,4824,1000,1,0,0,1,1,0,1,0,0 -10,8,626,4825,1000,1,0,0,1,1,0,1,0,0 -10,8,627,4826,1000,1,0,0,1,1,0,1,0,0 -10,8,628,4827,1000,1,0,0,1,1,0,1,0,0 -10,8,629,4828,1000,1,0,0,1,1,0,1,0,0 -10,8,630,4829,1000,1,0,0,1,1,0,1,0,0 -10,8,631,4830,1000,1,0,0,1,1,0,1,0,0 -10,8,632,5194,1000,1,0,0,1,1,0,1,0,0 -10,8,633,5195,1000,1,0,0,1,1,0,1,0,0 -10,8,634,5196,1000,1,0,0,1,1,0,1,0,0 -10,8,635,5197,1000,1,0,0,1,1,0,1,0,0 -10,8,636,5198,1000,1,0,0,1,1,0,1,0,0 -10,8,637,5199,1000,1,0,0,1,1,0,1,0,0 -10,8,638,5200,1000,1,0,0,1,1,0,1,0,0 -10,8,639,5201,1000,1,0,0,1,1,0,1,0,0 -10,8,640,13630,1000,1,0,0,1,1,0,1,0,0 -10,8,641,13631,1000,1,0,0,1,1,0,1,0,0 -10,8,642,13632,1000,1,0,0,1,1,0,1,0,0 -10,8,643,13633,1000,1,0,0,1,1,0,1,0,0 -10,8,644,13634,1000,1,0,0,1,1,0,1,0,0 -10,8,645,13635,1000,1,0,0,1,1,0,1,0,0 -10,8,646,15103,1000,1,0,0,1,1,0,1,0,0 -10,8,647,15104,1000,1,0,0,1,1,0,1,0,0 -10,8,648,15105,1000,1,0,0,1,1,0,1,0,0 -10,8,649,15106,1000,1,0,0,1,1,0,1,0,0 -10,8,650,15107,1000,1,0,0,1,1,0,1,0,0 -10,8,651,15108,1000,1,0,0,1,1,0,1,0,0 -10,8,652,16459,1000,1,0,0,1,1,0,1,0,0 -10,8,653,16460,1000,1,0,0,1,1,0,1,0,0 -10,8,654,16461,1000,1,0,0,1,1,0,1,0,0 -10,8,655,16462,1000,1,0,0,1,1,0,1,0,0 -10,8,656,16463,1000,1,0,0,1,1,0,1,0,0 -10,8,657,16464,1000,1,0,0,1,1,0,1,0,0 -10,8,658,16465,1000,1,0,0,1,1,0,1,0,0 -10,8,659,16466,1000,1,0,0,1,1,0,1,0,0 -10,8,660,16467,1000,1,0,0,1,1,0,1,0,0 -10,8,661,16468,1000,1,0,0,1,1,0,1,0,0 -10,8,662,16469,1000,1,0,0,1,1,0,1,0,0 -10,8,663,16470,1000,1,0,0,1,1,0,1,0,0 -10,8,664,16471,1000,1,0,0,1,1,0,1,0,0 -10,8,665,16472,1000,1,0,0,1,1,0,1,0,0 -10,8,666,13416,1000,1,0,0,1,1,0,1,0,0 -10,8,667,13417,1000,1,0,0,1,1,0,1,0,0 -10,8,668,13418,1000,1,0,0,1,1,0,1,0,0 -10,8,669,13419,1000,1,0,0,1,1,0,1,0,0 -10,8,670,13420,1000,1,0,0,1,1,0,1,0,0 -10,8,671,14283,1000,1,0,0,1,1,0,1,0,0 -10,8,672,14284,1000,1,0,0,1,1,0,1,0,0 -10,8,673,14285,1000,1,0,0,1,1,0,1,0,0 -10,8,674,14286,1000,1,0,0,1,1,0,1,0,0 -10,8,675,13182,1000,1,0,0,1,1,0,1,0,0 -10,8,676,13507,1000,1,0,0,1,1,0,1,0,0 -10,8,677,13981,1000,1,0,0,1,1,0,1,0,0 -10,8,678,14744,1000,1,0,0,1,1,0,1,0,0 -10,8,679,14893,1000,1,0,0,1,1,0,1,0,0 -10,8,680,15785,1000,1,0,0,1,1,0,1,0,0 -10,8,681,16419,1000,1,0,0,1,1,0,1,0,0 -10,8,682,11470,1000,1,0,0,1,1,0,1,0,0 -10,8,683,12512,1000,1,0,0,1,1,0,1,0,0 -10,8,684,12884,1000,1,0,0,1,1,0,1,0,0 -10,8,685,12513,1000,1,0,0,1,1,0,1,0,0 -10,8,686,12514,1000,1,0,0,1,1,0,1,0,0 -10,8,687,12515,1000,1,0,0,1,1,0,1,0,0 -10,8,688,12516,1000,1,0,0,1,1,0,1,0,0 -10,8,689,12517,1000,1,0,0,1,1,0,1,0,0 -10,8,690,12518,1000,1,0,0,1,1,0,1,0,0 -10,8,691,12519,1000,1,0,0,1,1,0,1,0,0 -10,8,692,12520,1000,1,0,0,1,1,0,1,0,0 -10,8,693,12521,1000,1,0,0,1,1,0,1,0,0 -10,8,694,8179,1000,1,0,0,1,1,0,1,0,0 -10,8,695,9704,1000,1,0,0,1,1,0,1,0,0 -10,8,696,15448,1000,1,0,0,1,1,0,1,0,0 -10,8,697,11162,1000,1,0,0,1,1,0,1,0,0 -10,8,698,11163,1000,1,0,0,1,1,0,1,0,0 -10,8,699,11164,1000,1,0,0,1,1,0,1,0,0 -10,8,700,11165,1000,1,0,0,1,1,0,1,0,0 -10,8,701,11661,1000,1,0,0,1,1,0,1,0,0 -10,8,702,11662,1000,1,0,0,1,1,0,1,0,0 -10,8,703,14639,1000,1,0,0,1,1,0,1,0,0 -10,8,704,13607,10,1,0,0,1,1,0,1,0,0 -10,7,705,15774,3000,1,0,0,1,1,0,1,100,0 -10,7,706,15775,3000,1,0,0,1,1,0,1,100,0 -10,7,707,11420,3000,1,0,0,1,1,0,1,100,0 -10,7,708,14704,3000,1,0,0,1,1,0,1,100,0 -10,7,709,13177,3000,1,0,0,1,1,0,1,100,0 -10,7,710,14191,3000,1,0,0,1,1,0,1,100,0 -10,7,711,13449,3000,1,0,0,1,1,0,1,100,0 -10,7,712,14192,3000,1,0,0,1,1,0,1,100,0 -10,7,713,15772,3000,1,0,0,1,1,0,1,100,0 -10,7,714,13791,3000,1,0,0,1,1,0,1,100,0 -10,7,715,14006,3000,1,0,0,1,1,0,1,100,0 -10,7,716,15768,3000,1,0,0,1,1,0,1,100,0 -10,7,717,14069,3000,1,0,0,1,1,0,1,100,0 -10,7,718,14124,3000,1,0,0,1,1,0,1,100,0 -10,7,719,15507,3000,1,0,0,1,1,0,1,100,0 -10,7,720,15508,3000,1,0,0,1,1,0,1,100,0 -10,7,721,14855,3000,1,0,0,1,1,0,1,100,0 -10,7,722,14894,3000,1,0,0,1,1,0,1,100,0 -10,7,723,16444,3000,1,0,0,1,1,0,1,100,0 -10,7,724,16445,3000,1,0,0,1,1,0,1,100,0 -10,7,725,12509,3000,1,0,0,1,1,0,1,100,0 -10,7,726,14126,3000,1,0,0,1,1,0,1,100,0 -10,7,727,15062,3000,1,0,0,1,1,0,1,100,0 -10,7,728,15063,3000,1,0,0,1,1,0,1,100,0 -10,7,729,14891,3000,1,0,0,1,1,0,1,100,0 -10,7,730,14895,3000,1,0,0,1,1,0,1,100,0 -10,7,731,14091,3000,1,0,0,1,1,0,1,100,0 -10,7,732,14092,3000,1,0,0,1,1,0,1,100,0 -10,7,733,14501,3000,1,0,0,1,1,0,1,100,0 -10,7,734,14506,3000,1,0,0,1,1,0,1,100,0 -10,7,735,15285,3000,1,0,0,1,1,0,1,100,0 -10,7,736,15286,3000,1,0,0,1,1,0,1,100,0 -10,7,737,16442,3000,1,0,0,1,1,0,1,100,0 -10,7,738,16443,3000,1,0,0,1,1,0,1,100,0 -10,7,739,15027,3000,1,0,0,1,1,0,1,100,0 -10,7,740,15028,3000,1,0,0,1,1,0,1,100,0 -10,7,741,13453,3000,1,0,0,1,1,0,1,100,0 -10,7,742,14193,3000,1,0,0,1,1,0,1,100,0 -10,7,743,13178,3000,1,0,0,1,1,0,1,100,0 -10,7,744,14194,3000,1,0,0,1,1,0,1,100,0 -10,7,745,16454,3000,1,0,0,1,1,0,1,100,0 -10,7,746,16455,3000,1,0,0,1,1,0,1,100,0 -10,7,747,15030,3000,1,0,0,1,1,0,1,100,0 -10,7,748,15031,3000,1,0,0,1,1,0,1,100,0 -10,7,749,13790,3000,1,0,0,1,1,0,1,100,0 -10,7,750,14005,3000,1,0,0,1,1,0,1,100,0 -10,7,751,14406,3000,1,0,0,1,1,0,1,100,0 -10,7,752,14413,3000,1,0,0,1,1,0,1,100,0 -10,7,753,16448,3000,1,0,0,1,1,0,1,100,0 -10,7,754,16449,3000,1,0,0,1,1,0,1,100,0 -10,7,755,12872,3000,1,0,0,1,1,0,1,100,0 -10,7,756,14187,3000,1,0,0,1,1,0,1,100,0 -10,7,757,14125,3000,1,0,0,1,1,0,1,100,0 -10,7,758,14500,3000,1,0,0,1,1,0,1,100,0 -10,7,759,14505,3000,1,0,0,1,1,0,1,100,0 -10,7,760,15118,3000,1,0,0,1,1,0,1,100,0 -10,7,761,15119,3000,1,0,0,1,1,0,1,100,0 -10,7,762,14662,3000,1,0,0,1,1,0,1,100,0 -10,7,763,14663,3000,1,0,0,1,1,0,1,100,0 -10,7,764,15771,3000,1,0,0,1,1,0,1,100,0 -10,7,765,9700,3000,1,0,0,1,1,0,1,100,0 -10,7,766,14498,3000,1,0,0,1,1,0,1,100,0 -10,7,767,14913,3000,1,0,0,1,1,0,1,100,0 -10,7,768,14914,3000,1,0,0,1,1,0,1,100,0 -10,7,769,13508,3000,1,0,0,1,1,0,1,100,0 -10,7,770,15115,3000,1,0,0,1,1,0,1,100,0 -10,7,771,15116,3000,1,0,0,1,1,0,1,100,0 -10,7,772,15113,3000,1,0,0,1,1,0,1,100,0 -10,7,773,15114,3000,1,0,0,1,1,0,1,100,0 -10,7,774,15222,3000,1,0,0,1,1,0,1,100,0 -10,7,775,15223,3000,1,0,0,1,1,0,1,100,0 -10,7,776,10750,3000,1,0,0,1,1,0,1,100,0 -10,7,777,14705,3000,1,0,0,1,1,0,1,100,0 -10,7,778,15027,3000,1,0,0,1,1,0,1,100,0 -10,7,779,15028,3000,1,0,0,1,1,0,1,100,0 -10,7,780,10380,3000,1,0,0,1,1,0,1,100,0 -10,7,781,15060,3000,1,0,0,1,1,0,1,100,0 -10,7,782,13963,3000,1,0,0,1,1,0,1,100,0 -10,7,783,14026,3000,1,0,0,1,1,0,1,100,0 -10,7,784,13964,3000,1,0,0,1,1,0,1,100,0 -10,7,785,14027,3000,1,0,0,1,1,0,1,100,0 -10,7,786,15064,3000,1,0,0,1,1,0,1,100,0 -10,7,787,15065,3000,1,0,0,1,1,0,1,100,0 -10,7,788,15524,3000,1,0,0,1,1,0,1,100,0 -10,7,789,15525,3000,1,0,0,1,1,0,1,100,0 -10,7,790,16450,3000,1,0,0,1,1,0,1,100,0 -10,7,791,16451,3000,1,0,0,1,1,0,1,100,0 -10,7,792,16344,3000,1,0,0,1,1,0,1,100,0 -10,7,793,16345,3000,1,0,0,1,1,0,1,100,0 -10,7,794,16342,3000,1,0,0,1,1,0,1,100,0 -10,7,795,16343,3000,1,0,0,1,1,0,1,100,0 -10,7,796,15220,3000,1,0,0,1,1,0,1,100,0 -10,7,797,15221,3000,1,0,0,1,1,0,1,100,0 -10,7,798,15066,3000,1,0,0,1,1,0,1,100,0 -10,7,799,15067,3000,1,0,0,1,1,0,1,100,0 -10,7,800,14089,3000,1,0,0,1,1,0,1,100,0 -10,7,801,14090,3000,1,0,0,1,1,0,1,100,0 -10,7,802,14195,3000,1,0,0,1,1,0,1,100,0 -10,7,803,14196,3000,1,0,0,1,1,0,1,100,0 -10,7,804,13965,3000,1,0,0,1,1,0,1,100,0 -10,7,805,14028,3000,1,0,0,1,1,0,1,100,0 -10,7,806,13508,3000,1,0,0,1,1,0,1,100,0 -10,7,807,13962,3000,1,0,0,1,1,0,1,100,0 -10,7,808,14314,3000,1,0,0,1,1,0,1,100,0 -10,7,809,13404,3000,1,0,0,1,1,0,1,100,0 -10,7,810,14188,3000,1,0,0,1,1,0,1,100,0 -10,7,811,14032,3000,1,0,0,1,1,0,1,100,0 -10,7,812,13960,3000,1,0,0,1,1,0,1,100,0 -10,7,813,15819,3000,1,0,0,1,1,0,1,100,0 -10,7,814,15820,3000,1,0,0,1,1,0,1,100,0 -10,7,815,10750,3000,1,0,0,1,1,0,1,100,0 -10,7,816,14705,3000,1,0,0,1,1,0,1,100,0 -10,7,817,14407,3000,1,0,0,1,1,0,1,100,0 -10,7,818,14414,3000,1,0,0,1,1,0,1,100,0 -10,7,819,16352,3000,1,0,0,1,1,0,1,100,0 -10,7,820,16353,3000,1,0,0,1,1,0,1,100,0 -10,7,821,14502,3000,1,0,0,1,1,0,1,100,0 -10,7,822,14507,3000,1,0,0,1,1,0,1,100,0 -10,7,823,10811,3000,1,0,0,1,1,0,1,100,0 -10,7,824,15061,3000,1,0,0,1,1,0,1,100,0 -10,7,825,15823,3000,1,0,0,1,1,0,1,100,0 -10,7,826,15824,3000,1,0,0,1,1,0,1,100,0 -10,7,827,15224,3000,1,0,0,1,1,0,1,100,0 -10,7,828,15225,3000,1,0,0,1,1,0,1,100,0 -10,7,829,14503,3000,1,0,0,1,1,0,1,100,0 -10,7,830,14510,3000,1,0,0,1,1,0,1,100,0 -10,7,831,15776,3000,1,0,0,1,1,0,1,100,0 -10,7,832,15777,3000,1,0,0,1,1,0,1,100,0 -10,7,833,15821,3000,1,0,0,1,1,0,1,100,0 -10,7,834,15822,3000,1,0,0,1,1,0,1,100,0 -10,7,835,14198,3000,1,0,0,1,1,0,1,100,0 -10,7,836,14197,3000,1,0,0,1,1,0,1,100,0 -10,7,837,16446,3000,1,0,0,1,1,0,1,100,0 -10,7,838,16447,3000,1,0,0,1,1,0,1,100,0 -10,7,839,14905,3000,1,0,0,1,1,0,1,100,0 -10,7,840,14907,3000,1,0,0,1,1,0,1,100,0 -10,7,841,14904,3000,1,0,0,1,1,0,1,100,0 -10,7,842,14906,3000,1,0,0,1,1,0,1,100,0 -10,7,843,14659,3000,1,0,0,1,1,0,1,100,0 -10,7,844,14660,3000,1,0,0,1,1,0,1,100,0 -10,7,845,13326,3000,1,0,0,1,1,0,1,100,0 -10,7,846,14416,3000,1,0,0,1,1,0,1,100,0 -10,7,847,13450,3000,1,0,0,1,1,0,1,100,0 -10,7,848,14031,3000,1,0,0,1,1,0,1,100,0 -10,7,849,16492,3000,1,0,0,1,1,0,1,100,0 -10,7,850,16493,3000,1,0,0,1,1,0,1,100,0 -10,8,851,1520,1,1,0,0,1,1,0,1,0,0 -10,8,852,7011,1,1,0,0,1,1,0,1,0,0 -10,7,853,14299,500,1,0,0,1,1,0,1,20,0 -10,7,854,14389,500,1,0,0,1,1,0,1,20,0 -10,7,855,15177,500,1,0,0,1,1,0,1,20,0 -10,7,856,14537,500,1,0,0,1,1,0,1,20,0 -10,7,857,14758,500,1,0,0,1,1,0,1,20,0 -10,7,858,14854,500,1,0,0,1,1,0,1,20,0 -10,7,859,13974,500,1,0,0,1,1,0,1,20,0 -10,7,860,15021,500,1,0,0,1,1,0,1,20,0 -10,7,861,15111,500,1,0,0,1,1,0,1,20,0 -10,7,862,15226,500,1,0,0,1,1,0,1,20,0 -10,7,863,15773,500,1,0,0,1,1,0,1,20,0 -10,7,864,15825,500,1,0,0,1,1,0,1,20,0 -10,7,865,15827,500,1,0,0,1,1,0,1,20,0 -10,7,866,16340,500,1,0,0,1,1,0,1,20,0 -10,7,867,16341,500,1,0,0,1,1,0,1,20,0 -10,7,868,16457,500,1,0,0,1,1,0,1,20,0 -10,7,869,16458,500,1,0,0,1,1,0,1,20,0 -10,7,870,11698,250,1,0,0,1,1,0,1,50,0 -10,7,871,11700,250,1,0,0,1,1,0,1,50,0 -10,8,872,4358,10,1,0,0,1,1,0,1,0,0 -10,8,873,7981,1,1,0,0,1,1,0,1,0,0 -10,8,874,7267,20,1,0,0,1,1,0,1,0,0 -10,8,875,9958,20,1,0,0,1,1,0,1,0,999 -10,8,876,1548,20,1,0,0,1,1,0,1,0,0 -10,8,877,1613,20,1,0,0,1,1,0,1,0,0 -10,8,878,1026,1,1,0,0,1,1,0,1,0,0 -10,8,879,5380,1,1,0,0,1,1,0,1,0,0 -10,8,880,11284,15,1,0,0,1,1,0,1,0,0 -10,8,881,11285,15,1,0,0,1,1,0,1,0,0 -10,8,882,11286,15,1,0,0,1,1,0,1,0,0 -10,8,883,10356,500,1,0,0,1,1,0,1,0,0 -10,8,884,12511,500,1,0,0,1,1,0,1,0,0 -10,8,885,13238,500,1,0,0,1,1,0,1,0,0 -10,8,886,1691,1,1,0,0,1,1,0,1,0,0 -10,8,887,9708,1,1,0,0,1,1,0,1,0,0 -10,8,888,11383,10,1,0,0,1,1,0,1,0,0 -10,8,889,11382,10,1,0,0,1,1,0,1,0,0 -10,8,890,11381,10,1,0,0,1,1,0,1,0,0 -10,7,891,16348,3000,1,0,0,1,1,0,1,100,0 -10,8,892,11386,10,1,0,0,1,1,0,1,0,0 -10,8,893,5767,1,10000,0,0,1,1,0,1,0,0 -10,8,894,5765,1,10000,0,0,1,1,0,1,0,0 -10,8,895,5768,1,10000,0,0,1,1,0,1,0,0 -10,8,896,14444,10,1,0,0,1,1,0,1,0,0 -10,8,897,14443,10,1,0,0,1,1,0,1,0,0 -10,8,898,14445,10,1,0,0,1,1,0,1,0,0 -10,8,899,15068,500,1,0,0,1,1,0,1,20,0 -10,7,900,16532,1000,1,0,0,1,1,0,1,0,0 -10,8,901,100,1,10000,0,0,1,1,0,1,0,0 -10,8,902,11243,1,1,0,0,1,1,0,1,0,0 -10,8,903,101,1,10000,0,0,1,1,0,1,0,0 -10,7,904,14368,3000,1,0,0,1,1,0,1,50,0 -10,8,905,8943,1,20,0,0,1,1,0,1,0,0 -10,7,906,1622,3000,1,0,0,1,1,0,1,0,0 -10,8,907,8953,1,20,0,0,1,1,0,1,0,0 -10,8,908,13693,1,20,0,0,1,1,0,1,0,0 -10,8,909,8949,1,20,0,0,1,1,0,1,0,0 -10,8,910,8955,1,20,0,0,1,1,0,1,0,0 -10,7,911,16456,500,1,0,0,1,1,0,1,0,0 \ No newline at end of file diff --git a/bundled-schema/RoadShopItems.sql b/bundled-schema/RoadShopItems.sql new file mode 100644 index 000000000..593a3a3cf --- /dev/null +++ b/bundled-schema/RoadShopItems.sql @@ -0,0 +1,918 @@ +BEGIN; + +INSERT INTO public.normal_shop_items +(shoptype, shopid, itemhash, itemid, points, tradequantity, rankreqlow, rankreqhigh, rankreqg, storelevelreq, maximumquantity, boughtquantity, roadfloorsrequired, weeklyfataliskills) +VALUES + (10,6,1,2146,25,1,0,0,1,1,0,1,0,0), + (10,6,2,2147,25,1,0,0,1,1,0,1,0,0), + (10,6,3,2148,25,1,0,0,1,1,0,1,0,0), + (10,6,4,2149,25,1,0,0,1,1,0,1,0,0), + (10,6,5,2150,25,1,0,0,1,1,0,1,0,0), + (10,6,6,2151,25,1,0,0,1,1,0,1,0,0), + (10,6,7,2152,25,1,0,0,1,1,0,1,0,0), + (10,6,8,2153,25,1,0,0,1,1,0,1,0,0), + (10,6,9,2154,25,1,0,0,1,1,0,1,0,0), + (10,6,10,2155,25,1,0,0,1,1,0,1,0,0), + (10,6,11,4398,25,1,0,0,1,1,0,1,0,0), + (10,6,12,12460,25,1,0,0,1,1,0,1,0,0), + (10,6,13,12461,25,1,0,0,1,1,0,1,0,0), + (10,6,14,12462,25,1,0,0,1,1,0,1,0,0), + (10,6,15,12463,25,1,0,0,1,1,0,1,0,0), + (10,6,16,12464,25,1,0,0,1,1,0,1,0,0), + (10,6,17,12465,25,1,0,0,1,1,0,1,0,0), + (10,6,18,12466,25,1,0,0,1,1,0,1,0,0), + (10,6,19,12467,25,1,0,0,1,1,0,1,0,0), + (10,6,20,12468,25,1,0,0,1,1,0,1,0,0), + (10,6,21,12469,25,1,0,0,1,1,0,1,0,0), + (10,6,22,15109,1000,1,0,0,1,1,0,1,0,0), + (10,6,23,15110,1000,1,0,0,1,1,0,1,0,0), + (10,6,24,2158,200,100,0,0,1,1,0,1,0,0), + (10,6,25,12306,2,1,0,0,1,1,0,1,80,0), + (10,6,26,12306,20000,10000,0,0,1,1,0,1,80,0), + (10,4,27,11664,20000,1,0,0,1,1,0,1,0,0), + (10,4,28,11665,20000,1,0,0,1,1,0,1,0,0), + (10,4,29,11666,20000,1,0,0,1,1,0,1,0,0), + (10,4,30,11667,20000,1,0,0,1,1,0,1,0,0), + (10,4,31,11668,20000,1,0,0,1,1,0,1,0,0), + (10,4,32,11669,20000,1,0,0,1,1,0,1,0,0), + (10,4,33,11670,20000,1,0,0,1,1,0,1,0,0), + (10,4,34,11671,20000,1,0,0,1,1,0,1,0,0), + (10,4,35,11672,20000,1,0,0,1,1,0,1,0,0), + (10,4,36,11673,20000,1,0,0,1,1,0,1,0,0), + (10,4,37,11674,20000,1,0,0,1,1,0,1,0,0), + (10,4,38,11675,20000,1,0,0,1,1,0,1,0,0), + (10,4,39,11676,20000,1,0,0,1,1,0,1,0,0), + (10,4,40,11677,20000,1,0,0,1,1,0,1,0,0), + (10,4,41,11678,20000,1,0,0,1,1,0,1,0,0), + (10,4,42,11679,20000,1,0,0,1,1,0,1,0,0), + (10,4,43,11680,20000,1,0,0,1,1,0,1,0,0), + (10,4,44,11681,20000,1,0,0,1,1,0,1,0,0), + (10,4,45,11682,20000,1,0,0,1,1,0,1,0,0), + (10,4,46,11683,20000,1,0,0,1,1,0,1,0,0), + (10,4,47,11684,20000,1,0,0,1,1,0,1,0,0), + (10,4,48,11685,20000,1,0,0,1,1,0,1,0,0), + (10,4,49,11686,20000,1,0,0,1,1,0,1,0,0), + (10,4,50,11687,20000,1,0,0,1,1,0,1,0,0), + (10,4,51,11688,20000,1,0,0,1,1,0,1,0,0), + (10,4,52,11689,20000,1,0,0,1,1,0,1,0,0), + (10,4,53,11690,20000,1,0,0,1,1,0,1,0,0), + (10,4,54,11691,20000,1,0,0,1,1,0,1,0,0), + (10,4,55,11692,20000,1,0,0,1,1,0,1,0,0), + (10,4,56,11693,20000,1,0,0,1,1,0,1,0,0), + (10,4,57,11694,20000,1,0,0,1,1,0,1,0,0), + (10,4,58,11695,20000,1,0,0,1,1,0,1,0,0), + (10,4,59,11696,20000,1,0,0,1,1,0,1,0,0), + (10,4,60,11697,20000,1,0,0,1,1,0,1,0,0), + (10,4,61,12893,20000,1,0,0,1,1,0,1,0,0), + (10,4,62,12894,20000,1,0,0,1,1,0,1,0,0), + (10,4,63,12895,20000,1,0,0,1,1,0,1,0,0), + (10,4,64,12896,20000,1,0,0,1,1,0,1,0,0), + (10,4,65,12897,20000,1,0,0,1,1,0,1,0,0), + (10,4,66,12898,20000,1,0,0,1,1,0,1,0,0), + (10,4,67,12899,20000,1,0,0,1,1,0,1,0,0), + (10,4,68,14337,20000,1,0,0,1,1,0,1,0,0), + (10,4,69,14338,20000,1,0,0,1,1,0,1,0,0), + (10,4,70,14339,20000,1,0,0,1,1,0,1,0,0), + (10,4,71,14340,20000,1,0,0,1,1,0,1,0,0), + (10,4,72,14341,20000,1,0,0,1,1,0,1,0,0), + (10,4,73,14342,20000,1,0,0,1,1,0,1,0,0), + (10,4,74,14343,20000,1,0,0,1,1,0,1,0,0), + (10,4,75,14344,20000,1,0,0,1,1,0,1,0,0), + (10,4,76,14345,20000,1,0,0,1,1,0,1,0,0), + (10,4,77,9254,10000,1,0,0,1,1,0,1,0,0), + (10,4,78,9255,10000,1,0,0,1,1,0,1,0,0), + (10,4,79,9256,10000,1,0,0,1,1,0,1,0,0), + (10,4,80,9257,10000,1,0,0,1,1,0,1,0,0), + (10,4,81,9258,10000,1,0,0,1,1,0,1,0,0), + (10,4,82,9259,10000,1,0,0,1,1,0,1,0,0), + (10,4,83,9260,10000,1,0,0,1,1,0,1,0,0), + (10,4,84,9261,10000,1,0,0,1,1,0,1,0,0), + (10,4,85,9262,10000,1,0,0,1,1,0,1,0,0), + (10,4,86,9263,10000,1,0,0,1,1,0,1,0,0), + (10,4,87,9264,10000,1,0,0,1,1,0,1,0,0), + (10,4,88,9265,10000,1,0,0,1,1,0,1,0,0), + (10,4,89,9266,10000,1,0,0,1,1,0,1,0,0), + (10,4,90,9267,10000,1,0,0,1,1,0,1,0,0), + (10,4,91,9268,10000,1,0,0,1,1,0,1,0,0), + (10,4,92,9269,10000,1,0,0,1,1,0,1,0,0), + (10,4,93,9270,10000,1,0,0,1,1,0,1,0,0), + (10,4,94,9271,10000,1,0,0,1,1,0,1,0,0), + (10,4,95,9272,10000,1,0,0,1,1,0,1,0,0), + (10,4,96,9273,10000,1,0,0,1,1,0,1,0,0), + (10,4,97,9274,10000,1,0,0,1,1,0,1,0,0), + (10,4,98,9275,10000,1,0,0,1,1,0,1,0,0), + (10,4,99,9276,10000,1,0,0,1,1,0,1,0,0), + (10,4,100,9277,10000,1,0,0,1,1,0,1,0,0), + (10,4,101,9278,10000,1,0,0,1,1,0,1,0,0), + (10,4,102,9279,10000,1,0,0,1,1,0,1,0,0), + (10,4,103,9280,10000,1,0,0,1,1,0,1,0,0), + (10,4,104,9281,10000,1,0,0,1,1,0,1,0,0), + (10,4,105,9282,10000,1,0,0,1,1,0,1,0,0), + (10,4,106,9283,10000,1,0,0,1,1,0,1,0,0), + (10,4,107,9284,10000,1,0,0,1,1,0,1,0,0), + (10,4,108,9285,10000,1,0,0,1,1,0,1,0,0), + (10,4,109,9286,10000,1,0,0,1,1,0,1,0,0), + (10,4,110,9287,10000,1,0,0,1,1,0,1,0,0), + (10,4,111,9288,10000,1,0,0,1,1,0,1,0,0), + (10,4,112,9289,10000,1,0,0,1,1,0,1,0,0), + (10,4,113,9290,10000,1,0,0,1,1,0,1,0,0), + (10,4,114,9291,10000,1,0,0,1,1,0,1,0,0), + (10,4,115,9292,10000,1,0,0,1,1,0,1,0,0), + (10,4,116,9293,10000,1,0,0,1,1,0,1,0,0), + (10,4,117,9294,10000,1,0,0,1,1,0,1,0,0), + (10,4,118,9295,10000,1,0,0,1,1,0,1,0,0), + (10,4,119,9296,10000,1,0,0,1,1,0,1,0,0), + (10,4,120,9297,10000,1,0,0,1,1,0,1,0,0), + (10,4,121,9298,10000,1,0,0,1,1,0,1,0,0), + (10,4,122,9299,10000,1,0,0,1,1,0,1,0,0), + (10,4,123,9300,10000,1,0,0,1,1,0,1,0,0), + (10,4,124,9301,10000,1,0,0,1,1,0,1,0,0), + (10,4,125,13196,10000,1,0,0,1,1,0,1,0,0), + (10,4,126,13197,10000,1,0,0,1,1,0,1,0,0), + (10,4,127,13198,10000,1,0,0,1,1,0,1,0,0), + (10,4,128,13199,10000,1,0,0,1,1,0,1,0,0), + (10,4,129,15542,10000,1,0,0,1,1,0,1,0,0), + (10,4,130,15543,10000,1,0,0,1,1,0,1,0,0), + (10,4,131,15544,10000,1,0,0,1,1,0,1,0,0), + (10,4,132,15545,10000,1,0,0,1,1,0,1,0,0), + (10,4,133,13640,20000,1,0,0,1,1,0,1,0,0), + (10,4,134,13641,20000,1,0,0,1,1,0,1,0,0), + (10,4,135,13642,20000,1,0,0,1,1,0,1,0,0), + (10,4,136,13643,20000,1,0,0,1,1,0,1,0,0), + (10,4,137,13644,20000,1,0,0,1,1,0,1,0,0), + (10,4,138,13645,20000,1,0,0,1,1,0,1,0,0), + (10,4,139,13646,20000,1,0,0,1,1,0,1,0,0), + (10,4,140,13647,20000,1,0,0,1,1,0,1,0,0), + (10,4,141,13648,20000,1,0,0,1,1,0,1,0,0), + (10,4,142,13649,20000,1,0,0,1,1,0,1,0,0), + (10,4,143,13650,20000,1,0,0,1,1,0,1,0,0), + (10,4,144,13651,20000,1,0,0,1,1,0,1,0,0), + (10,4,145,13652,20000,1,0,0,1,1,0,1,0,0), + (10,4,146,13653,20000,1,0,0,1,1,0,1,0,0), + (10,4,147,13654,20000,1,0,0,1,1,0,1,0,0), + (10,4,148,13655,20000,1,0,0,1,1,0,1,0,0), + (10,4,149,13656,20000,1,0,0,1,1,0,1,0,0), + (10,4,150,13657,20000,1,0,0,1,1,0,1,0,0), + (10,4,151,13658,20000,1,0,0,1,1,0,1,0,0), + (10,4,152,13659,20000,1,0,0,1,1,0,1,0,0), + (10,4,153,13660,20000,1,0,0,1,1,0,1,0,0), + (10,4,154,13661,20000,1,0,0,1,1,0,1,0,0), + (10,4,155,13662,20000,1,0,0,1,1,0,1,0,0), + (10,4,156,13663,20000,1,0,0,1,1,0,1,0,0), + (10,4,157,13664,20000,1,0,0,1,1,0,1,0,0), + (10,4,158,13665,20000,1,0,0,1,1,0,1,0,0), + (10,4,159,13666,20000,1,0,0,1,1,0,1,0,0), + (10,4,160,13667,20000,1,0,0,1,1,0,1,0,0), + (10,4,161,13668,20000,1,0,0,1,1,0,1,0,0), + (10,4,162,13669,20000,1,0,0,1,1,0,1,0,0), + (10,4,163,13670,20000,1,0,0,1,1,0,1,0,0), + (10,4,164,13671,20000,1,0,0,1,1,0,1,0,0), + (10,4,165,13672,20000,1,0,0,1,1,0,1,0,0), + (10,4,166,13673,20000,1,0,0,1,1,0,1,0,0), + (10,4,167,13674,20000,1,0,0,1,1,0,1,0,0), + (10,4,168,13675,20000,1,0,0,1,1,0,1,0,0), + (10,4,169,13676,20000,1,0,0,1,1,0,1,0,0), + (10,4,170,13677,20000,1,0,0,1,1,0,1,0,0), + (10,4,171,13678,20000,1,0,0,1,1,0,1,0,0), + (10,4,172,13679,20000,1,0,0,1,1,0,1,0,0), + (10,4,173,13680,20000,1,0,0,1,1,0,1,0,0), + (10,4,174,13681,20000,1,0,0,1,1,0,1,0,0), + (10,4,175,13682,20000,1,0,0,1,1,0,1,0,0), + (10,4,176,13683,20000,1,0,0,1,1,0,1,0,0), + (10,4,177,13684,20000,1,0,0,1,1,0,1,0,0), + (10,4,178,13685,20000,1,0,0,1,1,0,1,0,0), + (10,4,179,13686,20000,1,0,0,1,1,0,1,0,0), + (10,4,180,13687,20000,1,0,0,1,1,0,1,0,0), + (10,4,181,13688,20000,1,0,0,1,1,0,1,0,0), + (10,4,182,13689,20000,1,0,0,1,1,0,1,0,0), + (10,4,183,13690,20000,1,0,0,1,1,0,1,0,0), + (10,4,184,13691,20000,1,0,0,1,1,0,1,0,0), + (10,4,185,15546,20000,1,0,0,1,1,0,1,0,0), + (10,4,186,15547,20000,1,0,0,1,1,0,1,0,0), + (10,4,187,15548,20000,1,0,0,1,1,0,1,0,0), + (10,4,188,15549,20000,1,0,0,1,1,0,1,0,0), + (10,4,189,16162,35000,1,0,0,1,1,0,1,0,0), + (10,4,190,16163,35000,1,0,0,1,1,0,1,0,0), + (10,4,191,16164,35000,1,0,0,1,1,0,1,0,0), + (10,4,192,16165,35000,1,0,0,1,1,0,1,0,0), + (10,4,193,16166,35000,1,0,0,1,1,0,1,0,0), + (10,4,194,16167,35000,1,0,0,1,1,0,1,0,0), + (10,4,195,16168,35000,1,0,0,1,1,0,1,0,0), + (10,4,196,16169,35000,1,0,0,1,1,0,1,0,0), + (10,4,197,16172,35000,1,0,0,1,1,0,1,0,0), + (10,4,198,16173,35000,1,0,0,1,1,0,1,0,0), + (10,4,199,16174,35000,1,0,0,1,1,0,1,0,0), + (10,4,200,16175,35000,1,0,0,1,1,0,1,0,0), + (10,4,201,16176,35000,1,0,0,1,1,0,1,0,0), + (10,4,202,16177,35000,1,0,0,1,1,0,1,0,0), + (10,4,203,16178,35000,1,0,0,1,1,0,1,0,0), + (10,4,204,16179,35000,1,0,0,1,1,0,1,0,0), + (10,4,205,16182,35000,1,0,0,1,1,0,1,0,0), + (10,4,206,16183,35000,1,0,0,1,1,0,1,0,0), + (10,4,207,16184,35000,1,0,0,1,1,0,1,0,0), + (10,4,208,16185,35000,1,0,0,1,1,0,1,0,0), + (10,4,209,16186,35000,1,0,0,1,1,0,1,0,0), + (10,4,210,16187,35000,1,0,0,1,1,0,1,0,0), + (10,4,211,16188,35000,1,0,0,1,1,0,1,0,0), + (10,4,212,16189,35000,1,0,0,1,1,0,1,0,0), + (10,4,213,16192,35000,1,0,0,1,1,0,1,0,0), + (10,4,214,16193,35000,1,0,0,1,1,0,1,0,0), + (10,4,215,16194,35000,1,0,0,1,1,0,1,0,0), + (10,4,216,16195,35000,1,0,0,1,1,0,1,0,0), + (10,4,217,16196,35000,1,0,0,1,1,0,1,0,0), + (10,4,218,16197,35000,1,0,0,1,1,0,1,0,0), + (10,4,219,16198,35000,1,0,0,1,1,0,1,0,0), + (10,4,220,16199,35000,1,0,0,1,1,0,1,0,0), + (10,4,221,16202,35000,1,0,0,1,1,0,1,0,0), + (10,4,222,16203,35000,1,0,0,1,1,0,1,0,0), + (10,4,223,16204,35000,1,0,0,1,1,0,1,0,0), + (10,4,224,16205,35000,1,0,0,1,1,0,1,0,0), + (10,4,225,16206,35000,1,0,0,1,1,0,1,0,0), + (10,4,226,16207,35000,1,0,0,1,1,0,1,0,0), + (10,4,227,16208,35000,1,0,0,1,1,0,1,0,0), + (10,4,228,16209,35000,1,0,0,1,1,0,1,0,0), + (10,4,229,16212,35000,1,0,0,1,1,0,1,0,0), + (10,4,230,16213,35000,1,0,0,1,1,0,1,0,0), + (10,4,231,16214,35000,1,0,0,1,1,0,1,0,0), + (10,4,232,16215,35000,1,0,0,1,1,0,1,0,0), + (10,4,233,16216,35000,1,0,0,1,1,0,1,0,0), + (10,4,234,16217,35000,1,0,0,1,1,0,1,0,0), + (10,4,235,16218,35000,1,0,0,1,1,0,1,0,0), + (10,4,236,16219,35000,1,0,0,1,1,0,1,0,0), + (10,4,237,16222,35000,1,0,0,1,1,0,1,0,0), + (10,4,238,16223,35000,1,0,0,1,1,0,1,0,0), + (10,4,239,16224,35000,1,0,0,1,1,0,1,0,0), + (10,4,240,16225,35000,1,0,0,1,1,0,1,0,0), + (10,4,241,16226,35000,1,0,0,1,1,0,1,0,0), + (10,4,242,16227,35000,1,0,0,1,1,0,1,0,0), + (10,4,243,16228,35000,1,0,0,1,1,0,1,0,0), + (10,4,244,16229,35000,1,0,0,1,1,0,1,0,0), + (10,4,245,16232,35000,1,0,0,1,1,0,1,0,0), + (10,4,246,16233,35000,1,0,0,1,1,0,1,0,0), + (10,4,247,16234,35000,1,0,0,1,1,0,1,0,0), + (10,4,248,16235,35000,1,0,0,1,1,0,1,0,0), + (10,4,249,16236,35000,1,0,0,1,1,0,1,0,0), + (10,4,250,16237,35000,1,0,0,1,1,0,1,0,0), + (10,4,251,16238,35000,1,0,0,1,1,0,1,0,0), + (10,4,252,16239,35000,1,0,0,1,1,0,1,0,0), + (10,4,253,16242,35000,1,0,0,1,1,0,1,0,0), + (10,4,254,16243,35000,1,0,0,1,1,0,1,0,0), + (10,4,255,16244,35000,1,0,0,1,1,0,1,0,0), + (10,4,256,16245,35000,1,0,0,1,1,0,1,0,0), + (10,4,257,16246,35000,1,0,0,1,1,0,1,0,0), + (10,4,258,16247,35000,1,0,0,1,1,0,1,0,0), + (10,4,259,16248,35000,1,0,0,1,1,0,1,0,0), + (10,4,260,16249,35000,1,0,0,1,1,0,1,0,0), + (10,4,261,16252,35000,1,0,0,1,1,0,1,0,0), + (10,4,262,16253,35000,1,0,0,1,1,0,1,0,0), + (10,4,263,16254,35000,1,0,0,1,1,0,1,0,0), + (10,4,264,16255,35000,1,0,0,1,1,0,1,0,0), + (10,4,265,16256,35000,1,0,0,1,1,0,1,0,0), + (10,4,266,16257,35000,1,0,0,1,1,0,1,0,0), + (10,4,267,16258,35000,1,0,0,1,1,0,1,0,0), + (10,4,268,16259,35000,1,0,0,1,1,0,1,0,0), + (10,4,269,16262,35000,1,0,0,1,1,0,1,0,0), + (10,4,270,16263,35000,1,0,0,1,1,0,1,0,0), + (10,4,271,16264,35000,1,0,0,1,1,0,1,0,0), + (10,4,272,16265,35000,1,0,0,1,1,0,1,0,0), + (10,4,273,16266,35000,1,0,0,1,1,0,1,0,0), + (10,4,274,16267,35000,1,0,0,1,1,0,1,0,0), + (10,4,275,16268,35000,1,0,0,1,1,0,1,0,0), + (10,4,276,16269,35000,1,0,0,1,1,0,1,0,0), + (10,4,277,16272,35000,1,0,0,1,1,0,1,0,0), + (10,4,278,16273,35000,1,0,0,1,1,0,1,0,0), + (10,4,279,16274,35000,1,0,0,1,1,0,1,0,0), + (10,4,280,16275,35000,1,0,0,1,1,0,1,0,0), + (10,4,281,16276,35000,1,0,0,1,1,0,1,0,0), + (10,4,282,16277,35000,1,0,0,1,1,0,1,0,0), + (10,4,283,16278,35000,1,0,0,1,1,0,1,0,0), + (10,4,284,16279,35000,1,0,0,1,1,0,1,0,0), + (10,4,285,16282,35000,1,0,0,1,1,0,1,0,0), + (10,4,286,16283,35000,1,0,0,1,1,0,1,0,0), + (10,4,287,16284,35000,1,0,0,1,1,0,1,0,0), + (10,4,288,16285,35000,1,0,0,1,1,0,1,0,0), + (10,4,289,16286,35000,1,0,0,1,1,0,1,0,0), + (10,4,290,16287,35000,1,0,0,1,1,0,1,0,0), + (10,4,291,16288,35000,1,0,0,1,1,0,1,0,0), + (10,4,292,16289,35000,1,0,0,1,1,0,1,0,0), + (10,4,293,16292,35000,1,0,0,1,1,0,1,0,0), + (10,4,294,16293,35000,1,0,0,1,1,0,1,0,0), + (10,4,295,16294,35000,1,0,0,1,1,0,1,0,0), + (10,4,296,16295,35000,1,0,0,1,1,0,1,0,0), + (10,4,297,16296,35000,1,0,0,1,1,0,1,0,0), + (10,4,298,16297,35000,1,0,0,1,1,0,1,0,0), + (10,4,299,16298,35000,1,0,0,1,1,0,1,0,0), + (10,4,300,16299,35000,1,0,0,1,1,0,1,0,0), + (10,8,301,14136,15000,1,0,0,1,1,0,1,0,0), + (10,8,302,14137,15000,1,0,0,1,1,0,1,0,0), + (10,8,303,14138,15000,1,0,0,1,1,0,1,0,0), + (10,8,304,14139,15000,1,0,0,1,1,0,1,0,0), + (10,8,305,14140,15000,1,0,0,1,1,0,1,0,0), + (10,8,306,14141,15000,1,0,0,1,1,0,1,0,0), + (10,8,307,14142,15000,1,0,0,1,1,0,1,0,0), + (10,8,308,14143,15000,1,0,0,1,1,0,1,0,0), + (10,8,309,14144,15000,1,0,0,1,1,0,1,0,0), + (10,8,310,14145,15000,1,0,0,1,1,0,1,0,0), + (10,8,311,14454,30000,1,0,0,1,1,0,1,0,0), + (10,8,312,14455,30000,1,0,0,1,1,0,1,0,0), + (10,8,313,14456,30000,1,0,0,1,1,0,1,0,0), + (10,8,314,14457,30000,1,0,0,1,1,0,1,0,0), + (10,8,315,14458,30000,1,0,0,1,1,0,1,0,0), + (10,8,316,14459,30000,1,0,0,1,1,0,1,0,0), + (10,8,317,14460,30000,1,0,0,1,1,0,1,0,0), + (10,8,318,14461,30000,1,0,0,1,1,0,1,0,0), + (10,8,319,14462,30000,1,0,0,1,1,0,1,0,0), + (10,8,320,14463,30000,1,0,0,1,1,0,1,0,0), + (10,8,321,12724,50000,1,0,0,1,1,0,1,0,0), + (10,8,322,12725,50000,1,0,0,1,1,0,1,0,0), + (10,8,323,12726,50000,1,0,0,1,1,0,1,0,0), + (10,8,324,12727,50000,1,0,0,1,1,0,1,0,0), + (10,8,325,12728,50000,1,0,0,1,1,0,1,0,0), + (10,8,326,12729,50000,1,0,0,1,1,0,1,0,0), + (10,8,327,12730,50000,1,0,0,1,1,0,1,0,0), + (10,8,328,12731,50000,1,0,0,1,1,0,1,0,0), + (10,8,329,12732,50000,1,0,0,1,1,0,1,0,0), + (10,8,330,12733,50000,1,0,0,1,1,0,1,0,0), + (10,8,331,12734,50000,1,0,0,1,1,0,1,0,0), + (10,8,332,12735,50000,1,0,0,1,1,0,1,0,0), + (10,8,333,12736,50000,1,0,0,1,1,0,1,0,0), + (10,8,334,12737,50000,1,0,0,1,1,0,1,0,0), + (10,8,335,12738,50000,1,0,0,1,1,0,1,0,0), + (10,8,336,12739,50000,1,0,0,1,1,0,1,0,0), + (10,8,337,12740,50000,1,0,0,1,1,0,1,0,0), + (10,8,338,12741,50000,1,0,0,1,1,0,1,0,0), + (10,8,339,12742,50000,1,0,0,1,1,0,1,0,0), + (10,8,340,12743,50000,1,0,0,1,1,0,1,0,0), + (10,8,341,12744,50000,1,0,0,1,1,0,1,0,0), + (10,8,342,12745,50000,1,0,0,1,1,0,1,0,0), + (10,8,343,12746,50000,1,0,0,1,1,0,1,0,0), + (10,8,344,12747,50000,1,0,0,1,1,0,1,0,0), + (10,8,345,12748,50000,1,0,0,1,1,0,1,0,0), + (10,8,346,12749,50000,1,0,0,1,1,0,1,0,0), + (10,8,347,12750,50000,1,0,0,1,1,0,1,0,0), + (10,8,348,12751,50000,1,0,0,1,1,0,1,0,0), + (10,8,349,12752,50000,1,0,0,1,1,0,1,0,0), + (10,8,350,12753,50000,1,0,0,1,1,0,1,0,0), + (10,8,351,15070,50000,1,0,0,1,1,0,1,0,0), + (10,8,352,15071,50000,1,0,0,1,1,0,1,0,0), + (10,8,353,15072,50000,1,0,0,1,1,0,1,0,0), + (10,8,354,15073,50000,1,0,0,1,1,0,1,0,0), + (10,8,355,15074,50000,1,0,0,1,1,0,1,0,0), + (10,8,356,15075,50000,1,0,0,1,1,0,1,0,0), + (10,8,357,15076,50000,1,0,0,1,1,0,1,0,0), + (10,8,358,15077,50000,1,0,0,1,1,0,1,0,0), + (10,8,359,15078,50000,1,0,0,1,1,0,1,0,0), + (10,8,360,15079,50000,1,0,0,1,1,0,1,0,0), + (10,8,361,15567,20000,1,0,0,1,1,0,1,0,0), + (10,8,362,15568,20000,1,0,0,1,1,0,1,0,0), + (10,8,363,15569,20000,1,0,0,1,1,0,1,0,0), + (10,8,364,15570,20000,1,0,0,1,1,0,1,0,0), + (10,8,365,15571,20000,1,0,0,1,1,0,1,0,0), + (10,8,366,15572,20000,1,0,0,1,1,0,1,0,0), + (10,8,367,15573,20000,1,0,0,1,1,0,1,0,0), + (10,8,368,15574,20000,1,0,0,1,1,0,1,0,0), + (10,8,369,15575,20000,1,0,0,1,1,0,1,0,0), + (10,8,370,15576,20000,1,0,0,1,1,0,1,0,0), + (10,8,371,15577,20000,1,0,0,1,1,0,1,0,0), + (10,8,372,15578,20000,1,0,0,1,1,0,1,0,0), + (10,8,373,15579,20000,1,0,0,1,1,0,1,0,0), + (10,8,374,15580,20000,1,0,0,1,1,0,1,0,0), + (10,8,375,15581,20000,1,0,0,1,1,0,1,0,0), + (10,8,376,15582,20000,1,0,0,1,1,0,1,0,0), + (10,8,377,15583,20000,1,0,0,1,1,0,1,0,0), + (10,8,378,15584,20000,1,0,0,1,1,0,1,0,0), + (10,8,379,15585,20000,1,0,0,1,1,0,1,0,0), + (10,8,380,15586,20000,1,0,0,1,1,0,1,0,0), + (10,8,381,15587,20000,1,0,0,1,1,0,1,0,0), + (10,8,382,15588,20000,1,0,0,1,1,0,1,0,0), + (10,8,383,15589,20000,1,0,0,1,1,0,1,0,0), + (10,8,384,15590,20000,1,0,0,1,1,0,1,0,0), + (10,8,385,15591,20000,1,0,0,1,1,0,1,0,0), + (10,8,386,15592,20000,1,0,0,1,1,0,1,0,0), + (10,8,387,15593,20000,1,0,0,1,1,0,1,0,0), + (10,8,388,15594,20000,1,0,0,1,1,0,1,0,0), + (10,8,389,15595,20000,1,0,0,1,1,0,1,0,0), + (10,8,390,15596,20000,1,0,0,1,1,0,1,0,0), + (10,8,391,15597,20000,1,0,0,1,1,0,1,0,0), + (10,8,392,15598,20000,1,0,0,1,1,0,1,0,0), + (10,8,393,15599,20000,1,0,0,1,1,0,1,0,0), + (10,8,394,15600,20000,1,0,0,1,1,0,1,0,0), + (10,8,395,15601,20000,1,0,0,1,1,0,1,0,0), + (10,8,396,15602,20000,1,0,0,1,1,0,1,0,0), + (10,8,397,15603,20000,1,0,0,1,1,0,1,0,0), + (10,8,398,15604,20000,1,0,0,1,1,0,1,0,0), + (10,8,399,15605,20000,1,0,0,1,1,0,1,0,0), + (10,8,400,15606,20000,1,0,0,1,1,0,1,0,0), + (10,8,401,15607,20000,1,0,0,1,1,0,1,0,0), + (10,8,402,15608,20000,1,0,0,1,1,0,1,0,0), + (10,8,403,15609,20000,1,0,0,1,1,0,1,0,0), + (10,8,404,15610,20000,1,0,0,1,1,0,1,0,0), + (10,8,405,15611,20000,1,0,0,1,1,0,1,0,0), + (10,8,406,15612,20000,1,0,0,1,1,0,1,0,0), + (10,8,407,15613,20000,1,0,0,1,1,0,1,0,0), + (10,8,408,15614,20000,1,0,0,1,1,0,1,0,0), + (10,8,409,15615,20000,1,0,0,1,1,0,1,0,0), + (10,8,410,15616,20000,1,0,0,1,1,0,1,0,0), + (10,8,411,15617,20000,1,0,0,1,1,0,1,0,0), + (10,8,412,15618,20000,1,0,0,1,1,0,1,0,0), + (10,8,413,15619,20000,1,0,0,1,1,0,1,0,0), + (10,8,414,15620,20000,1,0,0,1,1,0,1,0,0), + (10,8,415,15621,20000,1,0,0,1,1,0,1,0,0), + (10,8,416,15622,20000,1,0,0,1,1,0,1,0,0), + (10,8,417,15623,20000,1,0,0,1,1,0,1,0,0), + (10,8,418,15624,20000,1,0,0,1,1,0,1,0,0), + (10,8,419,15625,20000,1,0,0,1,1,0,1,0,0), + (10,8,420,15626,20000,1,0,0,1,1,0,1,0,0), + (10,8,421,15627,20000,1,0,0,1,1,0,1,0,0), + (10,8,422,15628,20000,1,0,0,1,1,0,1,0,0), + (10,8,423,15629,20000,1,0,0,1,1,0,1,0,0), + (10,8,424,15630,20000,1,0,0,1,1,0,1,0,0), + (10,8,425,15631,20000,1,0,0,1,1,0,1,0,0), + (10,8,426,15632,20000,1,0,0,1,1,0,1,0,0), + (10,8,427,15633,20000,1,0,0,1,1,0,1,0,0), + (10,8,428,15634,20000,1,0,0,1,1,0,1,0,0), + (10,8,429,15635,20000,1,0,0,1,1,0,1,0,0), + (10,8,430,15636,20000,1,0,0,1,1,0,1,0,0), + (10,8,431,15637,20000,1,0,0,1,1,0,1,0,0), + (10,8,432,15638,20000,1,0,0,1,1,0,1,0,0), + (10,8,433,15639,20000,1,0,0,1,1,0,1,0,0), + (10,8,434,15640,20000,1,0,0,1,1,0,1,0,0), + (10,8,435,15641,20000,1,0,0,1,1,0,1,0,0), + (10,8,436,15642,20000,1,0,0,1,1,0,1,0,0), + (10,8,437,15643,20000,1,0,0,1,1,0,1,0,0), + (10,8,438,15644,20000,1,0,0,1,1,0,1,0,0), + (10,8,439,15645,20000,1,0,0,1,1,0,1,0,0), + (10,8,440,15646,20000,1,0,0,1,1,0,1,0,0), + (10,8,441,15647,20000,1,0,0,1,1,0,1,0,0), + (10,8,442,15648,20000,1,0,0,1,1,0,1,0,0), + (10,8,443,15649,20000,1,0,0,1,1,0,1,0,0), + (10,8,444,15650,20000,1,0,0,1,1,0,1,0,0), + (10,8,445,15651,20000,1,0,0,1,1,0,1,0,0), + (10,8,446,15652,20000,1,0,0,1,1,0,1,0,0), + (10,8,447,15653,20000,1,0,0,1,1,0,1,0,0), + (10,8,448,15654,20000,1,0,0,1,1,0,1,0,0), + (10,8,449,15655,20000,1,0,0,1,1,0,1,0,0), + (10,8,450,15656,20000,1,0,0,1,1,0,1,0,0), + (10,8,451,15657,20000,1,0,0,1,1,0,1,0,0), + (10,8,452,15658,20000,1,0,0,1,1,0,1,0,0), + (10,8,453,15659,20000,1,0,0,1,1,0,1,0,0), + (10,8,454,15660,20000,1,0,0,1,1,0,1,0,0), + (10,8,455,15661,20000,1,0,0,1,1,0,1,0,0), + (10,8,456,15662,20000,1,0,0,1,1,0,1,0,0), + (10,8,457,15663,20000,1,0,0,1,1,0,1,0,0), + (10,8,458,15664,20000,1,0,0,1,1,0,1,0,0), + (10,8,459,15665,20000,1,0,0,1,1,0,1,0,0), + (10,8,460,15666,20000,1,0,0,1,1,0,1,0,0), + (10,8,461,15667,20000,1,0,0,1,1,0,1,0,0), + (10,8,462,15668,20000,1,0,0,1,1,0,1,0,0), + (10,8,463,15669,20000,1,0,0,1,1,0,1,0,0), + (10,8,464,15670,20000,1,0,0,1,1,0,1,0,0), + (10,8,465,15671,20000,1,0,0,1,1,0,1,0,0), + (10,8,466,15672,20000,1,0,0,1,1,0,1,0,0), + (10,8,467,15673,20000,1,0,0,1,1,0,1,0,0), + (10,8,468,15674,20000,1,0,0,1,1,0,1,0,0), + (10,8,469,15675,20000,1,0,0,1,1,0,1,0,0), + (10,8,470,15676,20000,1,0,0,1,1,0,1,0,0), + (10,8,471,15677,20000,1,0,0,1,1,0,1,0,0), + (10,8,472,15678,20000,1,0,0,1,1,0,1,0,0), + (10,8,473,15679,20000,1,0,0,1,1,0,1,0,0), + (10,8,474,15680,20000,1,0,0,1,1,0,1,0,0), + (10,8,475,15681,20000,1,0,0,1,1,0,1,0,0), + (10,8,476,15682,20000,1,0,0,1,1,0,1,0,0), + (10,8,477,15683,20000,1,0,0,1,1,0,1,0,0), + (10,8,478,15684,20000,1,0,0,1,1,0,1,0,0), + (10,8,479,15685,20000,1,0,0,1,1,0,1,0,0), + (10,8,480,15686,20000,1,0,0,1,1,0,1,0,0), + (10,8,481,15687,20000,1,0,0,1,1,0,1,0,0), + (10,8,482,15688,20000,1,0,0,1,1,0,1,0,0), + (10,8,483,15689,20000,1,0,0,1,1,0,1,0,0), + (10,8,484,15690,20000,1,0,0,1,1,0,1,0,0), + (10,8,485,15691,20000,1,0,0,1,1,0,1,0,0), + (10,8,486,15692,20000,1,0,0,1,1,0,1,0,0), + (10,8,487,15693,20000,1,0,0,1,1,0,1,0,0), + (10,8,488,15694,20000,1,0,0,1,1,0,1,0,0), + (10,8,489,15695,20000,1,0,0,1,1,0,1,0,0), + (10,8,490,15696,20000,1,0,0,1,1,0,1,0,0), + (10,8,491,15697,20000,1,0,0,1,1,0,1,0,0), + (10,8,492,15698,20000,1,0,0,1,1,0,1,0,0), + (10,8,493,15699,20000,1,0,0,1,1,0,1,0,0), + (10,8,494,15700,20000,1,0,0,1,1,0,1,0,0), + (10,8,495,15701,20000,1,0,0,1,1,0,1,0,0), + (10,8,496,15702,20000,1,0,0,1,1,0,1,0,0), + (10,8,497,15703,20000,1,0,0,1,1,0,1,0,0), + (10,8,498,15704,20000,1,0,0,1,1,0,1,0,0), + (10,8,499,15705,20000,1,0,0,1,1,0,1,0,0), + (10,8,500,15706,20000,1,0,0,1,1,0,1,0,0), + (10,8,501,15707,20000,1,0,0,1,1,0,1,0,0), + (10,8,502,15708,20000,1,0,0,1,1,0,1,0,0), + (10,8,503,15709,20000,1,0,0,1,1,0,1,0,0), + (10,8,504,15710,20000,1,0,0,1,1,0,1,0,0), + (10,8,505,15711,20000,1,0,0,1,1,0,1,0,0), + (10,8,506,15712,20000,1,0,0,1,1,0,1,0,0), + (10,8,507,15713,20000,1,0,0,1,1,0,1,0,0), + (10,8,508,15714,20000,1,0,0,1,1,0,1,0,0), + (10,8,509,15715,20000,1,0,0,1,1,0,1,0,0), + (10,8,510,15716,20000,1,0,0,1,1,0,1,0,0), + (10,8,511,15717,20000,1,0,0,1,1,0,1,0,0), + (10,8,512,15718,20000,1,0,0,1,1,0,1,0,0), + (10,8,513,15719,20000,1,0,0,1,1,0,1,0,0), + (10,8,514,15720,20000,1,0,0,1,1,0,1,0,0), + (10,8,515,15721,20000,1,0,0,1,1,0,1,0,0), + (10,8,516,15722,20000,1,0,0,1,1,0,1,0,0), + (10,8,517,15723,20000,1,0,0,1,1,0,1,0,0), + (10,8,518,15724,20000,1,0,0,1,1,0,1,0,0), + (10,8,519,15725,20000,1,0,0,1,1,0,1,0,0), + (10,8,520,15726,20000,1,0,0,1,1,0,1,0,0), + (10,8,521,15727,20000,1,0,0,1,1,0,1,0,0), + (10,8,522,15728,20000,1,0,0,1,1,0,1,0,0), + (10,8,523,15729,20000,1,0,0,1,1,0,1,0,0), + (10,8,524,15730,20000,1,0,0,1,1,0,1,0,0), + (10,8,525,15731,20000,1,0,0,1,1,0,1,0,0), + (10,8,526,15732,20000,1,0,0,1,1,0,1,0,0), + (10,8,527,15733,20000,1,0,0,1,1,0,1,0,0), + (10,8,528,15734,20000,1,0,0,1,1,0,1,0,0), + (10,8,529,15735,20000,1,0,0,1,1,0,1,0,0), + (10,8,530,15736,20000,1,0,0,1,1,0,1,0,0), + (10,8,531,15737,20000,1,0,0,1,1,0,1,0,0), + (10,8,532,15738,20000,1,0,0,1,1,0,1,0,0), + (10,8,533,15739,20000,1,0,0,1,1,0,1,0,0), + (10,8,534,15740,20000,1,0,0,1,1,0,1,0,0), + (10,8,535,15741,20000,1,0,0,1,1,0,1,0,0), + (10,8,536,15742,20000,1,0,0,1,1,0,1,0,0), + (10,8,537,15743,20000,1,0,0,1,1,0,1,0,0), + (10,8,538,15744,20000,1,0,0,1,1,0,1,0,0), + (10,8,539,15745,20000,1,0,0,1,1,0,1,0,0), + (10,8,540,15746,20000,1,0,0,1,1,0,1,0,0), + (10,8,541,15747,20000,1,0,0,1,1,0,1,0,0), + (10,8,542,15748,20000,1,0,0,1,1,0,1,0,0), + (10,8,543,15749,20000,1,0,0,1,1,0,1,0,0), + (10,8,544,15750,20000,1,0,0,1,1,0,1,0,0), + (10,8,545,15751,20000,1,0,0,1,1,0,1,0,0), + (10,8,546,15752,20000,1,0,0,1,1,0,1,0,0), + (10,8,547,15753,20000,1,0,0,1,1,0,1,0,0), + (10,8,548,15754,20000,1,0,0,1,1,0,1,0,0), + (10,8,549,15755,20000,1,0,0,1,1,0,1,0,0), + (10,8,550,15756,20000,1,0,0,1,1,0,1,0,0), + (10,8,551,15757,20000,1,0,0,1,1,0,1,0,0), + (10,8,552,15758,20000,1,0,0,1,1,0,1,0,0), + (10,8,553,15759,20000,1,0,0,1,1,0,1,0,0), + (10,8,554,15760,20000,1,0,0,1,1,0,1,0,0), + (10,8,555,15761,20000,1,0,0,1,1,0,1,0,0), + (10,8,556,15762,20000,1,0,0,1,1,0,1,0,0), + (10,8,557,15763,20000,1,0,0,1,1,0,1,0,0), + (10,8,558,15764,20000,1,0,0,1,1,0,1,0,0), + (10,8,559,15765,20000,1,0,0,1,1,0,1,0,0), + (10,8,560,15766,20000,1,0,0,1,1,0,1,0,0), + (10,8,561,15919,20000,1,0,0,1,1,0,1,0,0), + (10,8,562,15920,20000,1,0,0,1,1,0,1,0,0), + (10,8,563,15921,20000,1,0,0,1,1,0,1,0,0), + (10,8,564,15922,20000,1,0,0,1,1,0,1,0,0), + (10,8,565,15923,20000,1,0,0,1,1,0,1,0,0), + (10,8,566,15924,20000,1,0,0,1,1,0,1,0,0), + (10,8,567,15925,20000,1,0,0,1,1,0,1,0,0), + (10,8,568,15926,20000,1,0,0,1,1,0,1,0,0), + (10,8,569,15927,20000,1,0,0,1,1,0,1,0,0), + (10,8,570,15928,20000,1,0,0,1,1,0,1,0,0), + (10,8,571,15929,20000,1,0,0,1,1,0,1,0,0), + (10,8,572,15930,20000,1,0,0,1,1,0,1,0,0), + (10,8,573,15931,20000,1,0,0,1,1,0,1,0,0), + (10,8,574,15932,20000,1,0,0,1,1,0,1,0,0), + (10,8,575,15933,20000,1,0,0,1,1,0,1,0,0), + (10,8,576,15934,20000,1,0,0,1,1,0,1,0,0), + (10,8,577,15935,20000,1,0,0,1,1,0,1,0,0), + (10,8,578,15936,20000,1,0,0,1,1,0,1,0,0), + (10,8,579,15937,20000,1,0,0,1,1,0,1,0,0), + (10,8,580,15938,20000,1,0,0,1,1,0,1,0,0), + (10,8,581,15939,20000,1,0,0,1,1,0,1,0,0), + (10,8,582,15940,20000,1,0,0,1,1,0,1,0,0), + (10,8,583,15941,20000,1,0,0,1,1,0,1,0,0), + (10,8,584,15942,20000,1,0,0,1,1,0,1,0,0), + (10,8,585,15943,20000,1,0,0,1,1,0,1,0,0), + (10,8,586,15944,20000,1,0,0,1,1,0,1,0,0), + (10,8,587,15945,20000,1,0,0,1,1,0,1,0,0), + (10,8,588,15946,20000,1,0,0,1,1,0,1,0,0), + (10,8,589,15947,20000,1,0,0,1,1,0,1,0,0), + (10,8,590,15948,20000,1,0,0,1,1,0,1,0,0), + (10,8,591,15949,20000,1,0,0,1,1,0,1,0,0), + (10,8,592,15950,20000,1,0,0,1,1,0,1,0,0), + (10,8,593,15951,20000,1,0,0,1,1,0,1,0,0), + (10,8,594,15952,20000,1,0,0,1,1,0,1,0,0), + (10,8,595,15953,20000,1,0,0,1,1,0,1,0,0), + (10,8,596,15954,20000,1,0,0,1,1,0,1,0,0), + (10,8,597,15955,20000,1,0,0,1,1,0,1,0,0), + (10,8,598,15956,20000,1,0,0,1,1,0,1,0,0), + (10,8,599,15957,20000,1,0,0,1,1,0,1,0,0), + (10,8,600,15958,20000,1,0,0,1,1,0,1,0,0), + (10,8,601,15959,20000,1,0,0,1,1,0,1,0,0), + (10,8,602,15960,20000,1,0,0,1,1,0,1,0,0), + (10,8,603,15961,20000,1,0,0,1,1,0,1,0,0), + (10,8,604,15962,20000,1,0,0,1,1,0,1,0,0), + (10,8,605,15963,20000,1,0,0,1,1,0,1,0,0), + (10,8,606,15964,20000,1,0,0,1,1,0,1,0,0), + (10,8,607,15965,20000,1,0,0,1,1,0,1,0,0), + (10,8,608,15966,20000,1,0,0,1,1,0,1,0,0), + (10,8,609,15967,20000,1,0,0,1,1,0,1,0,0), + (10,8,610,15968,20000,1,0,0,1,1,0,1,0,0), + (10,7,611,13506,250,1,0,0,1,1,0,1,50,0), + (10,7,612,15011,250,1,0,0,1,1,0,1,50,0), + (10,7,613,13636,250,1,0,0,1,1,0,1,50,0), + (10,7,614,1227,250,1,0,0,1,1,0,1,50,0), + (10,7,615,15022,250,1,0,0,1,1,0,1,50,0), + (10,8,616,4407,1000,1,0,0,1,1,0,1,0,0), + (10,8,617,4408,1000,1,0,0,1,1,0,1,0,0), + (10,8,618,4409,1000,1,0,0,1,1,0,1,0,0), + (10,8,619,4410,1000,1,0,0,1,1,0,1,0,0), + (10,8,620,4411,1000,1,0,0,1,1,0,1,0,0), + (10,8,621,4412,1000,1,0,0,1,1,0,1,0,0), + (10,8,622,4413,1000,1,0,0,1,1,0,1,0,0), + (10,8,623,4414,1000,1,0,0,1,1,0,1,0,0), + (10,8,624,4823,1000,1,0,0,1,1,0,1,0,0), + (10,8,625,4824,1000,1,0,0,1,1,0,1,0,0), + (10,8,626,4825,1000,1,0,0,1,1,0,1,0,0), + (10,8,627,4826,1000,1,0,0,1,1,0,1,0,0), + (10,8,628,4827,1000,1,0,0,1,1,0,1,0,0), + (10,8,629,4828,1000,1,0,0,1,1,0,1,0,0), + (10,8,630,4829,1000,1,0,0,1,1,0,1,0,0), + (10,8,631,4830,1000,1,0,0,1,1,0,1,0,0), + (10,8,632,5194,1000,1,0,0,1,1,0,1,0,0), + (10,8,633,5195,1000,1,0,0,1,1,0,1,0,0), + (10,8,634,5196,1000,1,0,0,1,1,0,1,0,0), + (10,8,635,5197,1000,1,0,0,1,1,0,1,0,0), + (10,8,636,5198,1000,1,0,0,1,1,0,1,0,0), + (10,8,637,5199,1000,1,0,0,1,1,0,1,0,0), + (10,8,638,5200,1000,1,0,0,1,1,0,1,0,0), + (10,8,639,5201,1000,1,0,0,1,1,0,1,0,0), + (10,8,640,13630,1000,1,0,0,1,1,0,1,0,0), + (10,8,641,13631,1000,1,0,0,1,1,0,1,0,0), + (10,8,642,13632,1000,1,0,0,1,1,0,1,0,0), + (10,8,643,13633,1000,1,0,0,1,1,0,1,0,0), + (10,8,644,13634,1000,1,0,0,1,1,0,1,0,0), + (10,8,645,13635,1000,1,0,0,1,1,0,1,0,0), + (10,8,646,15103,1000,1,0,0,1,1,0,1,0,0), + (10,8,647,15104,1000,1,0,0,1,1,0,1,0,0), + (10,8,648,15105,1000,1,0,0,1,1,0,1,0,0), + (10,8,649,15106,1000,1,0,0,1,1,0,1,0,0), + (10,8,650,15107,1000,1,0,0,1,1,0,1,0,0), + (10,8,651,15108,1000,1,0,0,1,1,0,1,0,0), + (10,8,652,16459,1000,1,0,0,1,1,0,1,0,0), + (10,8,653,16460,1000,1,0,0,1,1,0,1,0,0), + (10,8,654,16461,1000,1,0,0,1,1,0,1,0,0), + (10,8,655,16462,1000,1,0,0,1,1,0,1,0,0), + (10,8,656,16463,1000,1,0,0,1,1,0,1,0,0), + (10,8,657,16464,1000,1,0,0,1,1,0,1,0,0), + (10,8,658,16465,1000,1,0,0,1,1,0,1,0,0), + (10,8,659,16466,1000,1,0,0,1,1,0,1,0,0), + (10,8,660,16467,1000,1,0,0,1,1,0,1,0,0), + (10,8,661,16468,1000,1,0,0,1,1,0,1,0,0), + (10,8,662,16469,1000,1,0,0,1,1,0,1,0,0), + (10,8,663,16470,1000,1,0,0,1,1,0,1,0,0), + (10,8,664,16471,1000,1,0,0,1,1,0,1,0,0), + (10,8,665,16472,1000,1,0,0,1,1,0,1,0,0), + (10,8,666,13416,1000,1,0,0,1,1,0,1,0,0), + (10,8,667,13417,1000,1,0,0,1,1,0,1,0,0), + (10,8,668,13418,1000,1,0,0,1,1,0,1,0,0), + (10,8,669,13419,1000,1,0,0,1,1,0,1,0,0), + (10,8,670,13420,1000,1,0,0,1,1,0,1,0,0), + (10,8,671,14283,1000,1,0,0,1,1,0,1,0,0), + (10,8,672,14284,1000,1,0,0,1,1,0,1,0,0), + (10,8,673,14285,1000,1,0,0,1,1,0,1,0,0), + (10,8,674,14286,1000,1,0,0,1,1,0,1,0,0), + (10,8,675,13182,1000,1,0,0,1,1,0,1,0,0), + (10,8,676,13507,1000,1,0,0,1,1,0,1,0,0), + (10,8,677,13981,1000,1,0,0,1,1,0,1,0,0), + (10,8,678,14744,1000,1,0,0,1,1,0,1,0,0), + (10,8,679,14893,1000,1,0,0,1,1,0,1,0,0), + (10,8,680,15785,1000,1,0,0,1,1,0,1,0,0), + (10,8,681,16419,1000,1,0,0,1,1,0,1,0,0), + (10,8,682,11470,1000,1,0,0,1,1,0,1,0,0), + (10,8,683,12512,1000,1,0,0,1,1,0,1,0,0), + (10,8,684,12884,1000,1,0,0,1,1,0,1,0,0), + (10,8,685,12513,1000,1,0,0,1,1,0,1,0,0), + (10,8,686,12514,1000,1,0,0,1,1,0,1,0,0), + (10,8,687,12515,1000,1,0,0,1,1,0,1,0,0), + (10,8,688,12516,1000,1,0,0,1,1,0,1,0,0), + (10,8,689,12517,1000,1,0,0,1,1,0,1,0,0), + (10,8,690,12518,1000,1,0,0,1,1,0,1,0,0), + (10,8,691,12519,1000,1,0,0,1,1,0,1,0,0), + (10,8,692,12520,1000,1,0,0,1,1,0,1,0,0), + (10,8,693,12521,1000,1,0,0,1,1,0,1,0,0), + (10,8,694,8179,1000,1,0,0,1,1,0,1,0,0), + (10,8,695,9704,1000,1,0,0,1,1,0,1,0,0), + (10,8,696,15448,1000,1,0,0,1,1,0,1,0,0), + (10,8,697,11162,1000,1,0,0,1,1,0,1,0,0), + (10,8,698,11163,1000,1,0,0,1,1,0,1,0,0), + (10,8,699,11164,1000,1,0,0,1,1,0,1,0,0), + (10,8,700,11165,1000,1,0,0,1,1,0,1,0,0), + (10,8,701,11661,1000,1,0,0,1,1,0,1,0,0), + (10,8,702,11662,1000,1,0,0,1,1,0,1,0,0), + (10,8,703,14639,1000,1,0,0,1,1,0,1,0,0), + (10,8,704,13607,10,1,0,0,1,1,0,1,0,0), + (10,7,705,15774,3000,1,0,0,1,1,0,1,100,0), + (10,7,706,15775,3000,1,0,0,1,1,0,1,100,0), + (10,7,707,11420,3000,1,0,0,1,1,0,1,100,0), + (10,7,708,14704,3000,1,0,0,1,1,0,1,100,0), + (10,7,709,13177,3000,1,0,0,1,1,0,1,100,0), + (10,7,710,14191,3000,1,0,0,1,1,0,1,100,0), + (10,7,711,13449,3000,1,0,0,1,1,0,1,100,0), + (10,7,712,14192,3000,1,0,0,1,1,0,1,100,0), + (10,7,713,15772,3000,1,0,0,1,1,0,1,100,0), + (10,7,714,13791,3000,1,0,0,1,1,0,1,100,0), + (10,7,715,14006,3000,1,0,0,1,1,0,1,100,0), + (10,7,716,15768,3000,1,0,0,1,1,0,1,100,0), + (10,7,717,14069,3000,1,0,0,1,1,0,1,100,0), + (10,7,718,14124,3000,1,0,0,1,1,0,1,100,0), + (10,7,719,15507,3000,1,0,0,1,1,0,1,100,0), + (10,7,720,15508,3000,1,0,0,1,1,0,1,100,0), + (10,7,721,14855,3000,1,0,0,1,1,0,1,100,0), + (10,7,722,14894,3000,1,0,0,1,1,0,1,100,0), + (10,7,723,16444,3000,1,0,0,1,1,0,1,100,0), + (10,7,724,16445,3000,1,0,0,1,1,0,1,100,0), + (10,7,725,12509,3000,1,0,0,1,1,0,1,100,0), + (10,7,726,14126,3000,1,0,0,1,1,0,1,100,0), + (10,7,727,15062,3000,1,0,0,1,1,0,1,100,0), + (10,7,728,15063,3000,1,0,0,1,1,0,1,100,0), + (10,7,729,14891,3000,1,0,0,1,1,0,1,100,0), + (10,7,730,14895,3000,1,0,0,1,1,0,1,100,0), + (10,7,731,14091,3000,1,0,0,1,1,0,1,100,0), + (10,7,732,14092,3000,1,0,0,1,1,0,1,100,0), + (10,7,733,14501,3000,1,0,0,1,1,0,1,100,0), + (10,7,734,14506,3000,1,0,0,1,1,0,1,100,0), + (10,7,735,15285,3000,1,0,0,1,1,0,1,100,0), + (10,7,736,15286,3000,1,0,0,1,1,0,1,100,0), + (10,7,737,16442,3000,1,0,0,1,1,0,1,100,0), + (10,7,738,16443,3000,1,0,0,1,1,0,1,100,0), + (10,7,739,15027,3000,1,0,0,1,1,0,1,100,0), + (10,7,740,15028,3000,1,0,0,1,1,0,1,100,0), + (10,7,741,13453,3000,1,0,0,1,1,0,1,100,0), + (10,7,742,14193,3000,1,0,0,1,1,0,1,100,0), + (10,7,743,13178,3000,1,0,0,1,1,0,1,100,0), + (10,7,744,14194,3000,1,0,0,1,1,0,1,100,0), + (10,7,745,16454,3000,1,0,0,1,1,0,1,100,0), + (10,7,746,16455,3000,1,0,0,1,1,0,1,100,0), + (10,7,747,15030,3000,1,0,0,1,1,0,1,100,0), + (10,7,748,15031,3000,1,0,0,1,1,0,1,100,0), + (10,7,749,13790,3000,1,0,0,1,1,0,1,100,0), + (10,7,750,14005,3000,1,0,0,1,1,0,1,100,0), + (10,7,751,14406,3000,1,0,0,1,1,0,1,100,0), + (10,7,752,14413,3000,1,0,0,1,1,0,1,100,0), + (10,7,753,16448,3000,1,0,0,1,1,0,1,100,0), + (10,7,754,16449,3000,1,0,0,1,1,0,1,100,0), + (10,7,755,12872,3000,1,0,0,1,1,0,1,100,0), + (10,7,756,14187,3000,1,0,0,1,1,0,1,100,0), + (10,7,757,14125,3000,1,0,0,1,1,0,1,100,0), + (10,7,758,14500,3000,1,0,0,1,1,0,1,100,0), + (10,7,759,14505,3000,1,0,0,1,1,0,1,100,0), + (10,7,760,15118,3000,1,0,0,1,1,0,1,100,0), + (10,7,761,15119,3000,1,0,0,1,1,0,1,100,0), + (10,7,762,14662,3000,1,0,0,1,1,0,1,100,0), + (10,7,763,14663,3000,1,0,0,1,1,0,1,100,0), + (10,7,764,15771,3000,1,0,0,1,1,0,1,100,0), + (10,7,765,9700,3000,1,0,0,1,1,0,1,100,0), + (10,7,766,14498,3000,1,0,0,1,1,0,1,100,0), + (10,7,767,14913,3000,1,0,0,1,1,0,1,100,0), + (10,7,768,14914,3000,1,0,0,1,1,0,1,100,0), + (10,7,769,13508,3000,1,0,0,1,1,0,1,100,0), + (10,7,770,15115,3000,1,0,0,1,1,0,1,100,0), + (10,7,771,15116,3000,1,0,0,1,1,0,1,100,0), + (10,7,772,15113,3000,1,0,0,1,1,0,1,100,0), + (10,7,773,15114,3000,1,0,0,1,1,0,1,100,0), + (10,7,774,15222,3000,1,0,0,1,1,0,1,100,0), + (10,7,775,15223,3000,1,0,0,1,1,0,1,100,0), + (10,7,776,10750,3000,1,0,0,1,1,0,1,100,0), + (10,7,777,14705,3000,1,0,0,1,1,0,1,100,0), + (10,7,778,15027,3000,1,0,0,1,1,0,1,100,0), + (10,7,779,15028,3000,1,0,0,1,1,0,1,100,0), + (10,7,780,10380,3000,1,0,0,1,1,0,1,100,0), + (10,7,781,15060,3000,1,0,0,1,1,0,1,100,0), + (10,7,782,13963,3000,1,0,0,1,1,0,1,100,0), + (10,7,783,14026,3000,1,0,0,1,1,0,1,100,0), + (10,7,784,13964,3000,1,0,0,1,1,0,1,100,0), + (10,7,785,14027,3000,1,0,0,1,1,0,1,100,0), + (10,7,786,15064,3000,1,0,0,1,1,0,1,100,0), + (10,7,787,15065,3000,1,0,0,1,1,0,1,100,0), + (10,7,788,15524,3000,1,0,0,1,1,0,1,100,0), + (10,7,789,15525,3000,1,0,0,1,1,0,1,100,0), + (10,7,790,16450,3000,1,0,0,1,1,0,1,100,0), + (10,7,791,16451,3000,1,0,0,1,1,0,1,100,0), + (10,7,792,16344,3000,1,0,0,1,1,0,1,100,0), + (10,7,793,16345,3000,1,0,0,1,1,0,1,100,0), + (10,7,794,16342,3000,1,0,0,1,1,0,1,100,0), + (10,7,795,16343,3000,1,0,0,1,1,0,1,100,0), + (10,7,796,15220,3000,1,0,0,1,1,0,1,100,0), + (10,7,797,15221,3000,1,0,0,1,1,0,1,100,0), + (10,7,798,15066,3000,1,0,0,1,1,0,1,100,0), + (10,7,799,15067,3000,1,0,0,1,1,0,1,100,0), + (10,7,800,14089,3000,1,0,0,1,1,0,1,100,0), + (10,7,801,14090,3000,1,0,0,1,1,0,1,100,0), + (10,7,802,14195,3000,1,0,0,1,1,0,1,100,0), + (10,7,803,14196,3000,1,0,0,1,1,0,1,100,0), + (10,7,804,13965,3000,1,0,0,1,1,0,1,100,0), + (10,7,805,14028,3000,1,0,0,1,1,0,1,100,0), + (10,7,806,13508,3000,1,0,0,1,1,0,1,100,0), + (10,7,807,13962,3000,1,0,0,1,1,0,1,100,0), + (10,7,808,14314,3000,1,0,0,1,1,0,1,100,0), + (10,7,809,13404,3000,1,0,0,1,1,0,1,100,0), + (10,7,810,14188,3000,1,0,0,1,1,0,1,100,0), + (10,7,811,14032,3000,1,0,0,1,1,0,1,100,0), + (10,7,812,13960,3000,1,0,0,1,1,0,1,100,0), + (10,7,813,15819,3000,1,0,0,1,1,0,1,100,0), + (10,7,814,15820,3000,1,0,0,1,1,0,1,100,0), + (10,7,815,10750,3000,1,0,0,1,1,0,1,100,0), + (10,7,816,14705,3000,1,0,0,1,1,0,1,100,0), + (10,7,817,14407,3000,1,0,0,1,1,0,1,100,0), + (10,7,818,14414,3000,1,0,0,1,1,0,1,100,0), + (10,7,819,16352,3000,1,0,0,1,1,0,1,100,0), + (10,7,820,16353,3000,1,0,0,1,1,0,1,100,0), + (10,7,821,14502,3000,1,0,0,1,1,0,1,100,0), + (10,7,822,14507,3000,1,0,0,1,1,0,1,100,0), + (10,7,823,10811,3000,1,0,0,1,1,0,1,100,0), + (10,7,824,15061,3000,1,0,0,1,1,0,1,100,0), + (10,7,825,15823,3000,1,0,0,1,1,0,1,100,0), + (10,7,826,15824,3000,1,0,0,1,1,0,1,100,0), + (10,7,827,15224,3000,1,0,0,1,1,0,1,100,0), + (10,7,828,15225,3000,1,0,0,1,1,0,1,100,0), + (10,7,829,14503,3000,1,0,0,1,1,0,1,100,0), + (10,7,830,14510,3000,1,0,0,1,1,0,1,100,0), + (10,7,831,15776,3000,1,0,0,1,1,0,1,100,0), + (10,7,832,15777,3000,1,0,0,1,1,0,1,100,0), + (10,7,833,15821,3000,1,0,0,1,1,0,1,100,0), + (10,7,834,15822,3000,1,0,0,1,1,0,1,100,0), + (10,7,835,14198,3000,1,0,0,1,1,0,1,100,0), + (10,7,836,14197,3000,1,0,0,1,1,0,1,100,0), + (10,7,837,16446,3000,1,0,0,1,1,0,1,100,0), + (10,7,838,16447,3000,1,0,0,1,1,0,1,100,0), + (10,7,839,14905,3000,1,0,0,1,1,0,1,100,0), + (10,7,840,14907,3000,1,0,0,1,1,0,1,100,0), + (10,7,841,14904,3000,1,0,0,1,1,0,1,100,0), + (10,7,842,14906,3000,1,0,0,1,1,0,1,100,0), + (10,7,843,14659,3000,1,0,0,1,1,0,1,100,0), + (10,7,844,14660,3000,1,0,0,1,1,0,1,100,0), + (10,7,845,13326,3000,1,0,0,1,1,0,1,100,0), + (10,7,846,14416,3000,1,0,0,1,1,0,1,100,0), + (10,7,847,13450,3000,1,0,0,1,1,0,1,100,0), + (10,7,848,14031,3000,1,0,0,1,1,0,1,100,0), + (10,7,849,16492,3000,1,0,0,1,1,0,1,100,0), + (10,7,850,16493,3000,1,0,0,1,1,0,1,100,0), + (10,8,851,1520,1,1,0,0,1,1,0,1,0,0), + (10,8,852,7011,1,1,0,0,1,1,0,1,0,0), + (10,7,853,14299,500,1,0,0,1,1,0,1,20,0), + (10,7,854,14389,500,1,0,0,1,1,0,1,20,0), + (10,7,855,15177,500,1,0,0,1,1,0,1,20,0), + (10,7,856,14537,500,1,0,0,1,1,0,1,20,0), + (10,7,857,14758,500,1,0,0,1,1,0,1,20,0), + (10,7,858,14854,500,1,0,0,1,1,0,1,20,0), + (10,7,859,13974,500,1,0,0,1,1,0,1,20,0), + (10,7,860,15021,500,1,0,0,1,1,0,1,20,0), + (10,7,861,15111,500,1,0,0,1,1,0,1,20,0), + (10,7,862,15226,500,1,0,0,1,1,0,1,20,0), + (10,7,863,15773,500,1,0,0,1,1,0,1,20,0), + (10,7,864,15825,500,1,0,0,1,1,0,1,20,0), + (10,7,865,15827,500,1,0,0,1,1,0,1,20,0), + (10,7,866,16340,500,1,0,0,1,1,0,1,20,0), + (10,7,867,16341,500,1,0,0,1,1,0,1,20,0), + (10,7,868,16457,500,1,0,0,1,1,0,1,20,0), + (10,7,869,16458,500,1,0,0,1,1,0,1,20,0), + (10,7,870,11698,250,1,0,0,1,1,0,1,50,0), + (10,7,871,11700,250,1,0,0,1,1,0,1,50,0), + (10,8,872,4358,10,1,0,0,1,1,0,1,0,0), + (10,8,873,7981,1,1,0,0,1,1,0,1,0,0), + (10,8,874,7267,20,1,0,0,1,1,0,1,0,0), + (10,8,875,9958,20,1,0,0,1,1,0,1,0,999), + (10,8,876,1548,20,1,0,0,1,1,0,1,0,0), + (10,8,877,1613,20,1,0,0,1,1,0,1,0,0), + (10,8,878,1026,1,1,0,0,1,1,0,1,0,0), + (10,8,879,5380,1,1,0,0,1,1,0,1,0,0), + (10,8,880,11284,15,1,0,0,1,1,0,1,0,0), + (10,8,881,11285,15,1,0,0,1,1,0,1,0,0), + (10,8,882,11286,15,1,0,0,1,1,0,1,0,0), + (10,8,883,10356,500,1,0,0,1,1,0,1,0,0), + (10,8,884,12511,500,1,0,0,1,1,0,1,0,0), + (10,8,885,13238,500,1,0,0,1,1,0,1,0,0), + (10,8,886,1691,1,1,0,0,1,1,0,1,0,0), + (10,8,887,9708,1,1,0,0,1,1,0,1,0,0), + (10,8,888,11383,10,1,0,0,1,1,0,1,0,0), + (10,8,889,11382,10,1,0,0,1,1,0,1,0,0), + (10,8,890,11381,10,1,0,0,1,1,0,1,0,0), + (10,7,891,16348,3000,1,0,0,1,1,0,1,100,0), + (10,8,892,11386,10,1,0,0,1,1,0,1,0,0), + (10,8,893,5767,1,10000,0,0,1,1,0,1,0,0), + (10,8,894,5765,1,10000,0,0,1,1,0,1,0,0), + (10,8,895,5768,1,10000,0,0,1,1,0,1,0,0), + (10,8,896,14444,10,1,0,0,1,1,0,1,0,0), + (10,8,897,14443,10,1,0,0,1,1,0,1,0,0), + (10,8,898,14445,10,1,0,0,1,1,0,1,0,0), + (10,8,899,15068,500,1,0,0,1,1,0,1,20,0), + (10,7,900,16532,1000,1,0,0,1,1,0,1,0,0), + (10,8,901,100,1,10000,0,0,1,1,0,1,0,0), + (10,8,902,11243,1,1,0,0,1,1,0,1,0,0), + (10,8,903,101,1,10000,0,0,1,1,0,1,0,0), + (10,7,904,14368,3000,1,0,0,1,1,0,1,50,0), + (10,8,905,8943,1,20,0,0,1,1,0,1,0,0), + (10,7,906,1622,3000,1,0,0,1,1,0,1,0,0), + (10,8,907,8953,1,20,0,0,1,1,0,1,0,0), + (10,8,908,13693,1,20,0,0,1,1,0,1,0,0), + (10,8,909,8949,1,20,0,0,1,1,0,1,0,0), + (10,8,910,8955,1,20,0,0,1,1,0,1,0,0), + (10,7,911,16456,500,1,0,0,1,1,0,1,0,0); + +END; \ No newline at end of file From f2e697f3e7f53e09e52826cab75c13256f4a031a Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 9 Oct 2022 06:46:19 +1100 Subject: [PATCH 47/95] disable Teleport command by default --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 98ea1c0ef..ba9af8b77 100644 --- a/config.json +++ b/config.json @@ -40,7 +40,7 @@ "prefix": "!ravi" }, { "name": "Teleport", - "enabled": true, + "enabled": false, "prefix": "!tele" }, { "name": "Reload", From 0bbb90a927047e5722bc0ed0f174d430654c9abf Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 12 Oct 2022 01:41:29 +1100 Subject: [PATCH 48/95] address packet queueing issues --- server/channelserver/handlers.go | 18 ++++-- server/channelserver/sys_session.go | 90 ++++++++++++++++------------- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index bda3eb352..b0c4d8d7d 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -182,11 +182,19 @@ func handleMsgSysLogout(s *Session, p mhfpacket.MHFPacket) { } func logoutPlayer(s *Session) { + s.server.Lock() if _, exists := s.server.sessions[s.rawConn]; exists { delete(s.server.sessions, s.rawConn) - s.rawConn.Close() - } else { - return // Prevent re-running logout logic on real logouts + } + s.rawConn.Close() + s.server.Unlock() + + for _, stage := range s.server.stages { + for session := range stage.clients { + if session.charID == s.charID { + delete(stage.clients, session) + } + } } _, err := s.server.db.Exec("UPDATE sign_sessions SET server_id=NULL, char_id=NULL WHERE token=$1", s.token) @@ -1794,9 +1802,7 @@ func handleMsgMhfGetLobbyCrowd(s *Session, p mhfpacket.MHFPacket) { // It can be worried about later if we ever get to the point where there are // full servers to actually need to migrate people from and empty ones to pkt := p.(*mhfpacket.MsgMhfGetLobbyCrowd) - blankData := make([]byte, 0x320) - doAckBufSucceed(s, pkt.AckHandle, blankData) - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 0x320)) } func handleMsgMhfGetTrendWeapon(s *Session, p mhfpacket.MHFPacket) { diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index ec122a521..90430f4da 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -1,11 +1,13 @@ package channelserver import ( + "encoding/binary" "encoding/hex" "fmt" "io" "net" "sync" + "time" "erupe-ce/common/byteframe" "erupe-ce/common/stringstack" @@ -17,6 +19,11 @@ import ( "golang.org/x/text/encoding/japanese" ) +type packet struct { + data []byte + nonBlocking bool +} + // Session holds state for the channel server connection. type Session struct { sync.Mutex @@ -24,11 +31,10 @@ type Session struct { server *Server rawConn net.Conn cryptConn *network.CryptConn - sendPackets chan []byte + sendPackets chan packet clientContext *clientctx.ClientContext userEnteredStage bool // If the user has entered a stage before - myseries MySeries stageID string stage *Stage reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet. @@ -55,18 +61,8 @@ type Session struct { mailList []int // For Debuging - Name string -} - -type MySeries struct { - houseTier []byte - houseData []byte - bookshelfData []byte - galleryData []byte - toreData []byte - gardenData []byte - state uint8 - password string + Name string + closed bool } // NewSession creates a new Session type. @@ -76,15 +72,14 @@ func NewSession(server *Server, conn net.Conn) *Session { server: server, rawConn: conn, cryptConn: network.NewCryptConn(conn), - sendPackets: make(chan []byte, 20), + sendPackets: make(chan packet, 20), clientContext: &clientctx.ClientContext{ StrConv: &stringsupport.StringConverter{ Encoding: japanese.ShiftJIS, }, }, - userEnteredStage: false, - sessionStart: Time_Current_Adjusted().Unix(), - stageMoveStack: stringstack.New(), + sessionStart: Time_Current_Adjusted().Unix(), + stageMoveStack: stringstack.New(), } return s } @@ -102,19 +97,34 @@ func (s *Session) Start() { // QueueSend queues a packet (raw []byte) to be sent. func (s *Session) QueueSend(data []byte) { - bf := byteframe.NewByteFrameFromBytes(data[:2]) - s.logMessage(bf.ReadUint16(), data, "Server", s.Name) - s.sendPackets <- data + 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} + } } // QueueSendNonBlocking queues a packet (raw []byte) to be sent, dropping the packet entirely if the queue is full. func (s *Session) QueueSendNonBlocking(data []byte) { select { - case s.sendPackets <- data: - // Enqueued properly. + case s.sendPackets <- packet{data, true}: + // Enqueued data default: - // Couldn't enqueue, likely something wrong with the connection. - s.logger.Warn("Dropped packet for session because of full send buffer, something is probably wrong") + s.logger.Warn("Packet queue too full, dropping!") + // Queue too full } } @@ -142,29 +152,25 @@ func (s *Session) QueueAck(ackHandle uint32, data []byte) { func (s *Session) sendLoop() { for { - // TODO(Andoryuuta): Test making this into a buffered channel and grouping the packet together before sending. - rawPacket := <-s.sendPackets - - if rawPacket == nil { - s.logger.Debug("Got nil from s.SendPackets, exiting send loop") + if s.closed { return } - - // Make a copy of the data. - terminatedPacket := make([]byte, len(rawPacket)) - copy(terminatedPacket, rawPacket) - - // Append the MSG_SYS_END tailing opcode. - terminatedPacket = append(terminatedPacket, []byte{0x00, 0x10}...) - - s.cryptConn.SendPacket(terminatedPacket) + pkt := <-s.sendPackets + err := s.cryptConn.SendPacket(append(pkt.data, []byte{0x00, 0x10}...)) + if err != nil { + s.logger.Warn("Failed to send packet") + } + time.Sleep(10 * time.Millisecond) } } func (s *Session) recvLoop() { for { + if s.closed { + logoutPlayer(s) + return + } pkt, err := s.cryptConn.ReadPacket() - if err == io.EOF { s.logger.Info(fmt.Sprintf("[%s] Disconnected", s.Name)) logoutPlayer(s) @@ -176,6 +182,7 @@ func (s *Session) recvLoop() { return } s.handlePacketGroup(pkt) + time.Sleep(10 * time.Millisecond) } } @@ -195,7 +202,8 @@ func (s *Session) handlePacketGroup(pktGroup []byte) { s.logMessage(opcodeUint16, pktGroup, s.Name, "Server") if opcode == network.MSG_SYS_LOGOUT { - s.rawConn.Close() + s.closed = true + return } // Get the packet parser and handler for this opcode. mhfPkt := mhfpacket.FromOpcode(opcode) From 1f95033e28a05b0a9cecc1ada2d14e3cbc6efb7b Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 12 Oct 2022 05:06:22 +1100 Subject: [PATCH 49/95] prevent fatal crash on missing savedata --- server/channelserver/handlers_plate.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/channelserver/handlers_plate.go b/server/channelserver/handlers_plate.go index b1bfea5d2..172a5f134 100644 --- a/server/channelserver/handlers_plate.go +++ b/server/channelserver/handlers_plate.go @@ -12,13 +12,13 @@ func handleMsgMhfLoadPlateData(s *Session, p mhfpacket.MHFPacket) { var data []byte err := s.server.db.QueryRow("SELECT platedata FROM characters WHERE id = $1", s.charID).Scan(&data) if err != nil { - s.logger.Fatal("Failed to get plate data savedata from db", zap.Error(err)) + s.logger.Error("Failed to get plate data savedata from db", zap.Error(err)) } if len(data) > 0 { doAckBufSucceed(s, pkt.AckHandle, data) } else { - doAckBufSucceed(s, pkt.AckHandle, []byte{}) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } } @@ -77,13 +77,13 @@ func handleMsgMhfLoadPlateBox(s *Session, p mhfpacket.MHFPacket) { var data []byte err := s.server.db.QueryRow("SELECT platebox FROM characters WHERE id = $1", s.charID).Scan(&data) if err != nil { - s.logger.Fatal("Failed to get sigil box savedata from db", zap.Error(err)) + s.logger.Error("Failed to get sigil box savedata from db", zap.Error(err)) } if len(data) > 0 { doAckBufSucceed(s, pkt.AckHandle, data) } else { - doAckBufSucceed(s, pkt.AckHandle, []byte{}) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } } From f9e9aaa3038c6b280602912cc577c62ca2e40c13 Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 12 Oct 2022 05:15:40 +1100 Subject: [PATCH 50/95] use default season integer on fail --- server/entranceserver/make_resp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/entranceserver/make_resp.go b/server/entranceserver/make_resp.go index c0358faef..7dc2065d0 100644 --- a/server/entranceserver/make_resp.go +++ b/server/entranceserver/make_resp.go @@ -25,7 +25,7 @@ func encodeServerInfo(config *config.Config, s *Server) []byte { sid := (4096 + serverIdx*256) + 16 err := s.db.QueryRow("SELECT season FROM servers WHERE server_id=$1", sid).Scan(&season) if err != nil { - panic(err) + season = 0 } if si.IP == "" { si.IP = config.Host From 7d3aa8c5b9fe2d3a5b340d4c3f64088befa5e377 Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 12 Oct 2022 05:19:48 +1100 Subject: [PATCH 51/95] use default currentplayers integer on fail --- server/entranceserver/make_resp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/entranceserver/make_resp.go b/server/entranceserver/make_resp.go index 7dc2065d0..0df241260 100644 --- a/server/entranceserver/make_resp.go +++ b/server/entranceserver/make_resp.go @@ -50,7 +50,7 @@ func encodeServerInfo(config *config.Config, s *Server) []byte { bf.WriteUint16(ci.MaxPlayers) err := s.db.QueryRow("SELECT current_players FROM servers WHERE server_id=$1", sid).Scan(¤tplayers) if err != nil { - panic(err) + currentplayers = 0 } bf.WriteUint16(currentplayers) bf.WriteUint32(0) From f346c181d3649df1d933d69e00a28759c47a0efb Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 12 Oct 2022 19:27:35 +1100 Subject: [PATCH 52/95] add versioning print --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 60b64dac1..3964ff315 100644 --- a/main.go +++ b/main.go @@ -35,7 +35,7 @@ func main() { defer zapLogger.Sync() logger := zapLogger.Named("main") - logger.Info("Starting Erupe") + logger.Info("Starting Erupe (9.1b)") if config.ErupeConfig.Database.Password == "" { preventClose("Database password is blank") From 45b736db2d645c7044c5f5bd2d7e0a5c488a3084 Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 12 Oct 2022 22:44:08 +1100 Subject: [PATCH 53/95] fix guild enumeration overflow --- server/channelserver/handlers_guild.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index a45dfd4a4..e7c7d33d6 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1260,9 +1260,16 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { bf = byteframe.NewByteFrame() if pkt.Type > 8 { - bf.WriteUint16(uint16(len(alliances))) + if len(guilds) > 10 { + bf.WriteUint16(10) + } else { + bf.WriteUint16(uint16(len(alliances))) + } bf.WriteUint8(0x00) // Unk - for _, alliance := range alliances { + for i, alliance := range alliances { + if i == 10 { + break + } bf.WriteUint32(alliance.ID) bf.WriteUint32(alliance.ParentGuild.LeaderCharID) bf.WriteUint16(alliance.TotalMembers) @@ -1281,9 +1288,16 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteBool(true) // TODO: Enable GuildAlliance applications } } else { - bf.WriteUint16(uint16(len(guilds))) + if len(guilds) > 10 { + bf.WriteUint16(10) + } else { + bf.WriteUint16(uint16(len(guilds))) + } bf.WriteUint8(0x01) // Unk - for _, guild := range guilds { + for i, guild := range guilds { + if i == 10 { + break + } bf.WriteUint32(guild.ID) bf.WriteUint32(guild.LeaderCharID) bf.WriteUint16(guild.MemberCount) From 07c00cc2e34527559505ded95415169cf6ed90bc Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 13 Oct 2022 04:21:07 +1100 Subject: [PATCH 54/95] stub guild hunt box --- network/mhfpacket/msg_mhf_guild_huntdata.go | 20 ++++++++++++-------- server/channelserver/handlers_guild.go | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/network/mhfpacket/msg_mhf_guild_huntdata.go b/network/mhfpacket/msg_mhf_guild_huntdata.go index b744cce23..9e114c968 100644 --- a/network/mhfpacket/msg_mhf_guild_huntdata.go +++ b/network/mhfpacket/msg_mhf_guild_huntdata.go @@ -1,17 +1,18 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfGuildHuntdata represents the MSG_MHF_GUILD_HUNTDATA -type MsgMhfGuildHuntdata struct{ - AckHandle uint32 - Unk0 uint8 +type MsgMhfGuildHuntdata struct { + AckHandle uint32 + Operation uint8 + GuildID uint32 } // Opcode returns the ID associated with this packet type. @@ -22,7 +23,10 @@ func (m *MsgMhfGuildHuntdata) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGuildHuntdata) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() + m.Operation = bf.ReadUint8() + if m.Operation == 1 { + m.GuildID = bf.ReadUint32() + } return nil } diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index e7c7d33d6..5c60bd009 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1806,7 +1806,20 @@ func handleMsgMhfGetGuildWeeklyBonusActiveCount(s *Session, p mhfpacket.MHFPacke func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGuildHuntdata) - doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + bf := byteframe.NewByteFrame() + switch pkt.Operation { + case 0: // Unk + doAckBufSucceed(s, pkt.AckHandle, []byte{}) + case 1: // Get Huntdata + bf.WriteUint8(0) // Entries + /* Entry format + uint32 UnkID + uint32 MonID + */ + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) + case 2: // Unk, controls glow + doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00}) + } } type MessageBoardPost struct { From 25491834df1c82282e7797f9d3ed3159942ff116 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 13 Oct 2022 04:21:47 +1100 Subject: [PATCH 55/95] fix ud shop coin response --- server/channelserver/handlers.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index b0c4d8d7d..a198933ad 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -1767,8 +1767,9 @@ func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdShopCoin(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetUdShopCoin) - data, _ := hex.DecodeString("0000000000000001") - doAckBufSucceed(s, pkt.AckHandle, data) + bf := byteframe.NewByteFrame() + bf.WriteUint32(0) + doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfUseUdShopCoin(s *Session, p mhfpacket.MHFPacket) {} From ef5afa38998be523c3023a8298297e4817d4e3c3 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 17 Oct 2022 12:38:27 +1100 Subject: [PATCH 56/95] add quest coordinate print option --- config.json | 1 + config/config.go | 33 ++++++++++---------- server/channelserver/handlers_cast_binary.go | 12 +++++++ 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/config.json b/config.json index ba9af8b77..6543a0617 100644 --- a/config.json +++ b/config.json @@ -19,6 +19,7 @@ "MezFesAlt": false, "DisableMailItems": true, "DisableTokenCheck": false, + "PrintQuestCoordinates": false, "SaveDumps": { "Enabled": true, "OutputDir": "savedata" diff --git a/config/config.go b/config/config.go index c90550f53..0d6ac7063 100644 --- a/config/config.go +++ b/config/config.go @@ -29,22 +29,23 @@ type Config struct { // DevModeOptions holds various debug/temporary options for use while developing Erupe. type DevModeOptions struct { - EnableLauncherServer bool // Enables the launcher server to be served on port 80 - HideLoginNotice bool // Hide the Erupe notice on login - LoginNotice string // MHFML string of the login notice displayed - CleanDB bool // Automatically wipes the DB on server reset. - MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds. - LogInboundMessages bool // Log all messages sent to the server - LogOutboundMessages bool // Log all messages sent to the clients - MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled - DivaEvent int // Diva Defense event status - FestaEvent int // Hunter's Festa event status - TournamentEvent int // VS Tournament event status - MezFesEvent bool // MezFes status - MezFesAlt bool // Swaps out Volpakkun for Tokotoko - DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!) - DisableMailItems bool // Hack to prevent english versions of MHF from crashing - SaveDumps SaveDumpOptions + EnableLauncherServer bool // Enables the launcher server to be served on port 80 + HideLoginNotice bool // Hide the Erupe notice on login + LoginNotice string // MHFML string of the login notice displayed + CleanDB bool // Automatically wipes the DB on server reset. + MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds. + LogInboundMessages bool // Log all messages sent to the server + LogOutboundMessages bool // Log all messages sent to the clients + MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled + DivaEvent int // Diva Defense event status + FestaEvent int // Hunter's Festa event status + TournamentEvent int // VS Tournament event status + MezFesEvent bool // MezFes status + MezFesAlt bool // Swaps out Volpakkun for Tokotoko + DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!) + DisableMailItems bool // Hack to prevent english versions of MHF from crashing + PrintQuestCoordinates bool // Prints quest coordinates to console + SaveDumps SaveDumpOptions } type SaveDumpOptions struct { diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 3791ea241..867437344 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -19,6 +19,7 @@ import ( const ( BinaryMessageTypeState = 0 BinaryMessageTypeChat = 1 + BinaryMessageTypeQuest = 2 BinaryMessageTypeData = 3 BinaryMessageTypeMailNotify = 4 BinaryMessageTypeEmote = 6 @@ -89,6 +90,17 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { } } + if s.server.erupeConfig.DevModeOptions.PrintQuestCoordinates == true && s.server.erupeConfig.DevMode { + if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x02 && len(pkt.RawDataPayload) > 32 { + tmp.ReadBytes(20) + tmp.SetLE() + x := tmp.ReadFloat32() + y := tmp.ReadFloat32() + z := tmp.ReadFloat32() + s.logger.Debug("Coord", zap.Float32s("XYZ", []float32{x, y, z})) + } + } + // Parse out the real casted binary payload var msgBinTargeted *binpacket.MsgBinTargeted var authorLen, msgLen uint16 From c6c247b56bdf0e08c13fa2eba5b9b2aac7d9d8b3 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 17 Oct 2022 13:41:30 +1100 Subject: [PATCH 57/95] better festa responses --- server/channelserver/handlers_festa.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/server/channelserver/handlers_festa.go b/server/channelserver/handlers_festa.go index 6e5080ac3..ffe953943 100644 --- a/server/channelserver/handlers_festa.go +++ b/server/channelserver/handlers_festa.go @@ -253,11 +253,19 @@ func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return } - var souls uint32 + var souls, exists uint32 s.server.db.QueryRow("SELECT souls FROM guild_characters WHERE character_id=$1", s.charID).Scan(&souls) + err = s.server.db.QueryRow("SELECT prize_id FROM festa_prizes_accepted WHERE prize_id=0 AND character_id=$1", s.charID).Scan(&exists) bf := byteframe.NewByteFrame() bf.WriteUint32(souls) - bf.WriteUint32(0) // unk + if err != nil { + bf.WriteBool(true) + bf.WriteBool(false) + } else { + bf.WriteBool(false) + bf.WriteBool(true) + } + bf.WriteUint16(0) // Unk doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } @@ -280,10 +288,10 @@ func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) { return } resp.WriteUint32(guild.Souls) - resp.WriteUint32(0) // unk - resp.WriteUint32(0) // unk, rank? - resp.WriteUint32(0) // unk - resp.WriteUint32(0) // unk + resp.WriteUint32(1) // unk + resp.WriteUint32(1) // unk + resp.WriteUint32(1) // unk, rank? + resp.WriteUint32(1) // unk doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } @@ -342,6 +350,7 @@ func handleMsgMhfChargeFesta(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireFesta(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfAcquireFesta) + s.server.db.Exec("INSERT INTO public.festa_prizes_accepted VALUES (0, $1)", s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } From 5e42402a3d696a9f97358da4a58b78ab0f747863 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 18 Oct 2022 11:42:12 +1100 Subject: [PATCH 58/95] signserver cleanup --- server/signserver/dbutils.go | 2 +- server/signserver/session.go | 34 +++++++++++--------------------- server/signserver/sign_server.go | 19 +++++------------- 3 files changed, 17 insertions(+), 38 deletions(-) diff --git a/server/signserver/dbutils.go b/server/signserver/dbutils.go index 5e99d4c85..213a74a14 100644 --- a/server/signserver/dbutils.go +++ b/server/signserver/dbutils.go @@ -148,7 +148,7 @@ func (s *Server) getFriendsForCharacters(chars []character) []members { if err != nil { continue } - for i, _ := range charFriends { + for i := range charFriends { charFriends[i].CID = char.ID } friends = append(friends, charFriends...) diff --git a/server/signserver/session.go b/server/signserver/session.go index aef6508b1..f52ebb401 100644 --- a/server/signserver/session.go +++ b/server/signserver/session.go @@ -16,32 +16,19 @@ import ( type Session struct { sync.Mutex logger *zap.Logger - sid int server *Server - rawConn *net.Conn + rawConn net.Conn cryptConn *network.CryptConn } -func (s *Session) fail() { - s.server.Lock() - delete(s.server.sessions, s.sid) - s.server.Unlock() - -} - func (s *Session) work() { - for { - pkt, err := s.cryptConn.ReadPacket() - if err != nil { - s.fail() - return - } - - err = s.handlePacket(pkt) - if err != nil { - s.fail() - return - } + pkt, err := s.cryptConn.ReadPacket() + if err != nil { + return + } + err = s.handlePacket(pkt) + if err != nil { + return } } @@ -61,6 +48,7 @@ func (s *Session) handlePacket(pkt []byte) error { case "DELETE:100": loginTokenString := string(bf.ReadNullTerminatedBytes()) characterID := int(bf.ReadUint32()) + _ = int(bf.ReadUint32()) // login_token_number s.server.deleteCharacter(characterID, loginTokenString) sugar.Infof("Deleted character ID: %v\n", characterID) err := s.cryptConn.SendPacket([]byte{0x01}) // DEL_SUCCESS @@ -78,13 +66,13 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error { reqUsername := string(bf.ReadNullTerminatedBytes()) reqPassword := string(bf.ReadNullTerminatedBytes()) - reqUnk := string(bf.ReadNullTerminatedBytes()) + reqSkey := string(bf.ReadNullTerminatedBytes()) s.server.logger.Info( "Got sign in request", zap.String("reqUsername", reqUsername), zap.String("reqPassword", reqPassword), - zap.String("reqUnk", reqUnk), + zap.String("reqSkey", reqSkey), ) newCharaReq := false diff --git a/server/signserver/sign_server.go b/server/signserver/sign_server.go index 02bafb10d..6d567e126 100644 --- a/server/signserver/sign_server.go +++ b/server/signserver/sign_server.go @@ -24,7 +24,6 @@ type Server struct { sync.Mutex logger *zap.Logger erupeConfig *config.Config - sid int sessions map[int]*Session db *sqlx.DB listener net.Listener @@ -36,8 +35,6 @@ func NewServer(config *Config) *Server { s := &Server{ logger: config.Logger, erupeConfig: config.ErupeConfig, - sid: 0, - sessions: make(map[int]*Session), db: config.DB, } return s @@ -84,20 +81,19 @@ func (s *Server) acceptClients() { } } - go s.handleConnection(s.sid, conn) - s.sid++ + go s.handleConnection(conn) } } -func (s *Server) handleConnection(sid int, conn net.Conn) { +func (s *Server) handleConnection(conn net.Conn) { s.logger.Info("Got connection to sign server", zap.String("remoteaddr", conn.RemoteAddr().String())) + defer conn.Close() // Client initalizes the connection with a one-time buffer of 8 NULL bytes. nullInit := make([]byte, 8) _, err := io.ReadFull(conn, nullInit) if err != nil { - fmt.Println(err) - conn.Close() + s.logger.Error("Error initialising sign server connection", zap.Error(err)) return } @@ -105,15 +101,10 @@ func (s *Server) handleConnection(sid int, conn net.Conn) { session := &Session{ logger: s.logger, server: s, - rawConn: &conn, + rawConn: conn, cryptConn: network.NewCryptConn(conn), } - // Add the session to the server's sessions map. - s.Lock() - s.sessions[sid] = session - s.Unlock() - // Do the session's work. session.work() } From 9fc26405bb0af6ef67c76417e887484d8791a874 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 18 Oct 2022 12:03:12 +1100 Subject: [PATCH 59/95] defer closing entranceserver connections --- server/entranceserver/entrance_server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/entranceserver/entrance_server.go b/server/entranceserver/entrance_server.go index 56f300c27..706aac8b3 100644 --- a/server/entranceserver/entrance_server.go +++ b/server/entranceserver/entrance_server.go @@ -90,6 +90,7 @@ func (s *Server) acceptClients() { } func (s *Server) handleEntranceServerConnection(conn net.Conn) { + defer conn.Close() // Client initalizes the connection with a one-time buffer of 8 NULL bytes. nullInit := make([]byte, 8) n, err := io.ReadFull(conn, nullInit) @@ -118,5 +119,4 @@ func (s *Server) handleEntranceServerConnection(conn net.Conn) { cc.SendPacket(data) // Close because we only need to send the response once. // Any further requests from the client will come from a new connection. - conn.Close() } From 6413be532011147d155ad059850c5900fabdd49c Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 19 Oct 2022 23:09:43 +1100 Subject: [PATCH 60/95] enhance quest debugging tools --- config.json | 2 +- config/config.go | 34 ++++++++++---------- server/channelserver/handlers_cast_binary.go | 3 +- server/channelserver/handlers_quest.go | 18 +++++++++-- 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/config.json b/config.json index 6543a0617..9d8f99dd5 100644 --- a/config.json +++ b/config.json @@ -19,7 +19,7 @@ "MezFesAlt": false, "DisableMailItems": true, "DisableTokenCheck": false, - "PrintQuestCoordinates": false, + "QuestDebugTools": false, "SaveDumps": { "Enabled": true, "OutputDir": "savedata" diff --git a/config/config.go b/config/config.go index 0d6ac7063..6b8bb743f 100644 --- a/config/config.go +++ b/config/config.go @@ -29,23 +29,23 @@ type Config struct { // DevModeOptions holds various debug/temporary options for use while developing Erupe. type DevModeOptions struct { - EnableLauncherServer bool // Enables the launcher server to be served on port 80 - HideLoginNotice bool // Hide the Erupe notice on login - LoginNotice string // MHFML string of the login notice displayed - CleanDB bool // Automatically wipes the DB on server reset. - MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds. - LogInboundMessages bool // Log all messages sent to the server - LogOutboundMessages bool // Log all messages sent to the clients - MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled - DivaEvent int // Diva Defense event status - FestaEvent int // Hunter's Festa event status - TournamentEvent int // VS Tournament event status - MezFesEvent bool // MezFes status - MezFesAlt bool // Swaps out Volpakkun for Tokotoko - DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!) - DisableMailItems bool // Hack to prevent english versions of MHF from crashing - PrintQuestCoordinates bool // Prints quest coordinates to console - SaveDumps SaveDumpOptions + EnableLauncherServer bool // Enables the launcher server to be served on port 80 + HideLoginNotice bool // Hide the Erupe notice on login + LoginNotice string // MHFML string of the login notice displayed + CleanDB bool // Automatically wipes the DB on server reset. + MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds. + LogInboundMessages bool // Log all messages sent to the server + LogOutboundMessages bool // Log all messages sent to the clients + MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled + DivaEvent int // Diva Defense event status + FestaEvent int // Hunter's Festa event status + TournamentEvent int // VS Tournament event status + MezFesEvent bool // MezFes status + MezFesAlt bool // Swaps out Volpakkun for Tokotoko + DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!) + DisableMailItems bool // Hack to prevent english versions of MHF from crashing + QuestDebugTools bool // Enable various quest debug logs + SaveDumps SaveDumpOptions } type SaveDumpOptions struct { diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 867437344..fb0d0331f 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -90,8 +90,9 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { } } - if s.server.erupeConfig.DevModeOptions.PrintQuestCoordinates == true && s.server.erupeConfig.DevMode { + if s.server.erupeConfig.DevModeOptions.QuestDebugTools == true && s.server.erupeConfig.DevMode { if pkt.BroadcastType == 0x03 && pkt.MessageType == 0x02 && len(pkt.RawDataPayload) > 32 { + // This is only correct most of the time tmp.ReadBytes(20) tmp.SetLE() x := tmp.ReadFloat32() diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 7ee552232..5d662b06c 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -2,6 +2,7 @@ package channelserver import ( "fmt" + "go.uber.org/zap" "io/ioutil" "os" "path/filepath" @@ -13,9 +14,16 @@ import ( func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysGetFile) - // Debug print the request. if pkt.IsScenario { - fmt.Printf("%+v\n", pkt.ScenarioIdentifer) + if s.server.erupeConfig.DevModeOptions.QuestDebugTools && s.server.erupeConfig.DevMode { + s.logger.Debug( + "Scenario", + zap.Uint8("CategoryID", pkt.ScenarioIdentifer.CategoryID), + zap.Uint32("MainID", pkt.ScenarioIdentifer.MainID), + zap.Uint8("ChapterID", pkt.ScenarioIdentifer.ChapterID), + zap.Uint8("Flags", pkt.ScenarioIdentifer.Flags), + ) + } filename := fmt.Sprintf("%d_0_0_0_S%d_T%d_C%d", pkt.ScenarioIdentifer.CategoryID, pkt.ScenarioIdentifer.MainID, pkt.ScenarioIdentifer.Flags, pkt.ScenarioIdentifer.ChapterID) // Read the scenario file. data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("scenarios/%s.bin", filename))) @@ -31,6 +39,12 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { } doAckBufSucceed(s, pkt.AckHandle, data) } else { + if s.server.erupeConfig.DevModeOptions.QuestDebugTools && s.server.erupeConfig.DevMode { + s.logger.Debug( + "Quest", + zap.String("Filename", pkt.Filename), + ) + } // Get quest file. data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))) if err != nil { From e5e375004586dad93003bb005e7cfd707869d8bf Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 22 Oct 2022 05:54:53 +1100 Subject: [PATCH 61/95] auto-unregister from host-less quests --- server/channelserver/handlers.go | 12 ++++++++++++ server/channelserver/handlers_stage.go | 2 ++ server/channelserver/sys_stage.go | 1 + 3 files changed, 15 insertions(+) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index a198933ad..cc5f57d9b 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -190,6 +190,18 @@ func logoutPlayer(s *Session) { s.server.Unlock() for _, stage := range s.server.stages { + // Tell sessions registered to disconnecting players quest to unregister + if stage.hostCharID == s.charID { + if s.stage.id == "sl1Ns200p0a0u0" { + for _, sess := range s.server.sessions { + for rSlot := range stage.reservedClientSlots { + if sess.charID == rSlot { + sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) + } + } + } + } + } for session := range stage.clients { if session.charID == s.charID { delete(stage.clients, session) diff --git a/server/channelserver/handlers_stage.go b/server/channelserver/handlers_stage.go index 906480be7..cc98417c6 100644 --- a/server/channelserver/handlers_stage.go +++ b/server/channelserver/handlers_stage.go @@ -19,6 +19,7 @@ func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) { doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } else { stage := NewStage(pkt.StageID) + stage.hostCharID = s.charID stage.maxPlayers = uint16(pkt.PlayerCount) s.server.stages[stage.id] = stage doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) @@ -42,6 +43,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { stage = s.server.stages[stageID] s.server.Unlock() stage.Lock() + stage.hostCharID = s.charID stage.clients[s] = s.charID stage.Unlock() } diff --git a/server/channelserver/sys_stage.go b/server/channelserver/sys_stage.go index 827b2d6be..49e454749 100644 --- a/server/channelserver/sys_stage.go +++ b/server/channelserver/sys_stage.go @@ -46,6 +46,7 @@ type Stage struct { // other clients expect the server to echo them back in the exact same format. rawBinaryData map[stageBinaryKey][]byte + hostCharID uint32 maxPlayers uint16 password string createdAt string From 7691b842597d9c5ddbbb6e68a913780822328664 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 23 Oct 2022 12:45:10 +1100 Subject: [PATCH 62/95] add persistent featured weapons --- config.json | 1 + config/config.go | 1 + patch-schema/active-feature.sql | 9 +++++ server/channelserver/handlers_event.go | 54 +++++++++++++++----------- 4 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 patch-schema/active-feature.sql diff --git a/config.json b/config.json index 9d8f99dd5..9f8eed32f 100644 --- a/config.json +++ b/config.json @@ -2,6 +2,7 @@ "Host": "127.0.0.1", "BinPath": "bin", "DisableSoftCrash": false, + "FeaturedWeapons": 2, "devmode": true, "devmodeoptions": { "EnableLauncherServer": false, diff --git a/config/config.go b/config/config.go index 6b8bb743f..ca67b1f9c 100644 --- a/config/config.go +++ b/config/config.go @@ -15,6 +15,7 @@ type Config struct { Host string `mapstructure:"Host"` BinPath string `mapstructure:"BinPath"` DisableSoftCrash bool // Disables the 'Press Return to exit' dialog allowing scripts to reboot the server automatically + FeaturedWeapons int // Number of Active Feature weapons to generate daily DevMode bool DevModeOptions DevModeOptions diff --git a/patch-schema/active-feature.sql b/patch-schema/active-feature.sql new file mode 100644 index 000000000..f8b835100 --- /dev/null +++ b/patch-schema/active-feature.sql @@ -0,0 +1,9 @@ +BEGIN; + +CREATE TABLE IF NOT EXISTS public.feature_weapon +( + start_time timestamp without time zone NOT NULL, + featured integer NOT NULL +); + +END; \ No newline at end of file diff --git a/server/channelserver/handlers_event.go b/server/channelserver/handlers_event.go index b6765f998..95227709f 100644 --- a/server/channelserver/handlers_event.go +++ b/server/channelserver/handlers_event.go @@ -53,38 +53,46 @@ func handleMsgMhfEnumerateEvent(s *Session, p mhfpacket.MHFPacket) { } type activeFeature struct { - StartTime time.Time - ActiveFeatures uint32 - Unk1 uint16 + StartTime time.Time `db:"start_time"` + ActiveFeatures uint32 `db:"featured"` } func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule) - persistentEventSchedule := make([]activeFeature, 8) // generate day after weekly restart - for x := -1; x < 7; x++ { - feat := generateActiveWeapons(14) // number of active weapons - // TODO: only generate this once per restart (server should be restarted weekly) - // then load data from db instead of regenerating - persistentEventSchedule[x+1] = activeFeature{ - StartTime: Time_Current_Midnight().Add(time.Duration(24*x) * time.Hour), - ActiveFeatures: uint32(feat), - Unk1: 0, + + var features []activeFeature + rows, _ := s.server.db.Queryx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1 OR start_time=$2`, Time_Current_Midnight().Add(-24*time.Hour), Time_Current_Midnight()) + for rows.Next() { + var feature activeFeature + rows.StructScan(&feature) + features = append(features, feature) + } + + if len(features) < 2 { + if len(features) == 0 { + feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons) + feature.StartTime = Time_Current_Midnight().Add(-24 * time.Hour) + features = append(features, feature) + s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures) } + feature := generateFeatureWeapons(s.server.erupeConfig.FeaturedWeapons) + feature.StartTime = Time_Current_Midnight() + features = append(features, feature) + s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, feature.StartTime, feature.ActiveFeatures) } - resp := byteframe.NewByteFrame() - resp.WriteUint8(uint8(len(persistentEventSchedule))) // Entry count, client only parses the first 7 or 8. - resp.WriteUint32(uint32(Time_Current_Adjusted().Add(-5 * time.Minute).Unix())) // 5 minutes ago server time - - for _, es := range persistentEventSchedule { - resp.WriteUint32(uint32(es.StartTime.Unix())) - resp.WriteUint32(es.ActiveFeatures) - resp.WriteUint16(es.Unk1) + bf := byteframe.NewByteFrame() + bf.WriteUint8(2) + bf.WriteUint32(uint32(Time_Current_Adjusted().Add(-5 * time.Minute).Unix())) + for _, feature := range features { + bf.WriteUint32(uint32(feature.StartTime.Unix())) + bf.WriteUint32(feature.ActiveFeatures) + bf.WriteUint16(0) } - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } -func generateActiveWeapons(count int) int { +func generateFeatureWeapons(count int) activeFeature { nums := make([]int, 0) var result int r := rand.New(rand.NewSource(time.Now().UnixNano())) @@ -104,7 +112,7 @@ func generateActiveWeapons(count int) int { for _, num := range nums { result += int(math.Pow(2, float64(num))) } - return result + return activeFeature{ActiveFeatures: uint32(result)} } type loginBoost struct { From b69305a8a9e8a30366a6321220a87a181eccd9f7 Mon Sep 17 00:00:00 2001 From: rockisch Date: Sun, 23 Oct 2022 01:17:03 -0300 Subject: [PATCH 63/95] read static byte in 'Parse' call --- network/mhfpacket/msg_mhf_enumerate_guild.go | 3 +++ server/channelserver/handlers_guild.go | 26 +++++++------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/network/mhfpacket/msg_mhf_enumerate_guild.go b/network/mhfpacket/msg_mhf_enumerate_guild.go index 65edbc555..a976cb34b 100644 --- a/network/mhfpacket/msg_mhf_enumerate_guild.go +++ b/network/mhfpacket/msg_mhf_enumerate_guild.go @@ -32,6 +32,7 @@ type MsgMhfEnumerateGuild struct { AckHandle uint32 Type EnumerateGuildType Page uint8 + Sorting bool RawDataPayload []byte } @@ -45,6 +46,8 @@ func (m *MsgMhfEnumerateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli m.AckHandle = bf.ReadUint32() m.Type = EnumerateGuildType(bf.ReadUint8()) m.Page = bf.ReadUint8() + m.Sorting = bf.ReadBool() + bf.ReadUint8() m.RawDataPayload = bf.DataFromCurrent() bf.Seek(-2, io.SeekEnd) return nil diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 5c60bd009..8cc0d48b7 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1101,7 +1101,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { switch pkt.Type { case mhfpacket.ENUMERATE_GUILD_TYPE_GUILD_NAME: - bf.ReadBytes(10) + bf.ReadBytes(8) searchTerm := fmt.Sprintf(`%%%s%%`, stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())) rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE g.name ILIKE $1 OFFSET $2`, guildInfoSelectQuery), searchTerm, pkt.Page*10) if err == nil { @@ -1111,7 +1111,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } } case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_NAME: - bf.ReadBytes(10) + bf.ReadBytes(8) searchTerm := fmt.Sprintf(`%%%s%%`, stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())) rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE lc.name ILIKE $1 OFFSET $2`, guildInfoSelectQuery), searchTerm, pkt.Page*10) if err == nil { @@ -1121,7 +1121,6 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } } case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_ID: - bf.ReadBytes(2) ID := bf.ReadUint32() rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE leader_id = $1`, guildInfoSelectQuery), ID) if err == nil { @@ -1131,8 +1130,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } } case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_MEMBERS: - sorting := bf.ReadUint8() - if sorting == 1 { + if pkt.Sorting { rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) } else { rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) @@ -1144,8 +1142,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } } case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_REGISTRATION: - sorting := bf.ReadUint8() - if sorting == 1 { + if pkt.Sorting { rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) } else { rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) @@ -1157,8 +1154,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } } case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_RANK: - sorting := bf.ReadUint8() - if sorting == 1 { + if pkt.Sorting { rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) } else { rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) @@ -1170,7 +1166,6 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } } case mhfpacket.ENUMERATE_GUILD_TYPE_MOTTO: - bf.ReadBytes(2) mainMotto := bf.ReadUint16() subMotto := bf.ReadUint16() rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE main_motto = $1 AND sub_motto = $2 OFFSET $3`, guildInfoSelectQuery), mainMotto, subMotto, pkt.Page*10) @@ -1202,7 +1197,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } switch pkt.Type { case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME: - bf.ReadBytes(10) + bf.ReadBytes(8) searchTerm := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) for _, alliance := range tempAlliances { if strings.Contains(alliance.Name, searchTerm) { @@ -1210,7 +1205,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } } case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_NAME: - bf.ReadBytes(10) + bf.ReadBytes(8) searchTerm := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) for _, alliance := range tempAlliances { if strings.Contains(alliance.ParentGuild.LeaderName, searchTerm) { @@ -1218,7 +1213,6 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } } case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_ID: - bf.ReadBytes(2) ID := bf.ReadUint32() for _, alliance := range tempAlliances { if alliance.ParentGuild.LeaderCharID == ID { @@ -1226,8 +1220,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } } case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_MEMBERS: - sorting := bf.ReadBool() - if sorting { + if pkt.Sorting { sort.Slice(tempAlliances, func(i, j int) bool { return tempAlliances[i].TotalMembers > tempAlliances[j].TotalMembers }) @@ -1238,8 +1231,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } alliances = tempAlliances case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ORDER_REGISTRATION: - sorting := bf.ReadBool() - if sorting { + if pkt.Sorting { sort.Slice(tempAlliances, func(i, j int) bool { return tempAlliances[i].CreatedAt.Unix() > tempAlliances[j].CreatedAt.Unix() }) From a9a7573687c787868e146b7e30da2632e4a044e6 Mon Sep 17 00:00:00 2001 From: rockisch Date: Sun, 23 Oct 2022 01:19:26 -0300 Subject: [PATCH 64/95] handle pagination in guild enumeration --- server/channelserver/handlers_guild.go | 50 ++++++++++++-------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 8cc0d48b7..4f7594eb0 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1103,7 +1103,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { case mhfpacket.ENUMERATE_GUILD_TYPE_GUILD_NAME: bf.ReadBytes(8) searchTerm := fmt.Sprintf(`%%%s%%`, stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())) - rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE g.name ILIKE $1 OFFSET $2`, guildInfoSelectQuery), searchTerm, pkt.Page*10) + rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE g.name ILIKE $1 OFFSET $2 LIMIT 11`, guildInfoSelectQuery), searchTerm, pkt.Page*10) if err == nil { for rows.Next() { guild, _ := buildGuildObjectFromDbResult(rows, err, s) @@ -1113,7 +1113,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_NAME: bf.ReadBytes(8) searchTerm := fmt.Sprintf(`%%%s%%`, stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())) - rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE lc.name ILIKE $1 OFFSET $2`, guildInfoSelectQuery), searchTerm, pkt.Page*10) + rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE lc.name ILIKE $1 OFFSET $2 LIMIT 11`, guildInfoSelectQuery), searchTerm, pkt.Page*10) if err == nil { for rows.Next() { guild, _ := buildGuildObjectFromDbResult(rows, err, s) @@ -1131,9 +1131,9 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_MEMBERS: if pkt.Sorting { - rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) + rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10) } else { - rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) + rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY member_count ASC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10) } if err == nil { for rows.Next() { @@ -1143,9 +1143,9 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_REGISTRATION: if pkt.Sorting { - rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) + rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id ASC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10) } else { - rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) + rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY id DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10) } if err == nil { for rows.Next() { @@ -1155,9 +1155,9 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } case mhfpacket.ENUMERATE_GUILD_TYPE_ORDER_RANK: if pkt.Sorting { - rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) + rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10) } else { - rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp ASC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) + rows, err = s.server.db.Queryx(fmt.Sprintf(`%s ORDER BY rank_rp ASC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10) } if err == nil { for rows.Next() { @@ -1168,7 +1168,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { case mhfpacket.ENUMERATE_GUILD_TYPE_MOTTO: mainMotto := bf.ReadUint16() subMotto := bf.ReadUint16() - rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE main_motto = $1 AND sub_motto = $2 OFFSET $3`, guildInfoSelectQuery), mainMotto, subMotto, pkt.Page*10) + rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE main_motto = $1 AND sub_motto = $2 OFFSET $3 LIMIT 11`, guildInfoSelectQuery), mainMotto, subMotto, pkt.Page*10) if err == nil { for rows.Next() { guild, _ := buildGuildObjectFromDbResult(rows, err, s) @@ -1177,7 +1177,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } case mhfpacket.ENUMERATE_GUILD_TYPE_RECRUITING: // Assume the player wants the newest guilds with open recruitment - rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE recruiting=true ORDER BY id DESC OFFSET $1`, guildInfoSelectQuery), pkt.Page*10) + rows, err = s.server.db.Queryx(fmt.Sprintf(`%s WHERE recruiting=true ORDER BY id DESC OFFSET $1 LIMIT 11`, guildInfoSelectQuery), pkt.Page*10) if err == nil { for rows.Next() { guild, _ := buildGuildObjectFromDbResult(rows, err, s) @@ -1252,16 +1252,14 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { bf = byteframe.NewByteFrame() if pkt.Type > 8 { - if len(guilds) > 10 { - bf.WriteUint16(10) - } else { - bf.WriteUint16(uint16(len(alliances))) + hasNextPage := false + if len(alliances) > 10 { + hasNextPage = true + alliances = alliances[:10] } - bf.WriteUint8(0x00) // Unk - for i, alliance := range alliances { - if i == 10 { - break - } + bf.WriteUint16(uint16(len(alliances))) + bf.WriteBool(hasNextPage) // Unk + for _, alliance := range alliances { bf.WriteUint32(alliance.ID) bf.WriteUint32(alliance.ParentGuild.LeaderCharID) bf.WriteUint16(alliance.TotalMembers) @@ -1280,16 +1278,14 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteBool(true) // TODO: Enable GuildAlliance applications } } else { + hasNextPage := false if len(guilds) > 10 { - bf.WriteUint16(10) - } else { - bf.WriteUint16(uint16(len(guilds))) + hasNextPage = true + guilds = guilds[:10] } - bf.WriteUint8(0x01) // Unk - for i, guild := range guilds { - if i == 10 { - break - } + bf.WriteUint16(uint16(len(guilds))) + bf.WriteBool(hasNextPage) + for _, guild := range guilds { bf.WriteUint32(guild.ID) bf.WriteUint32(guild.LeaderCharID) bf.WriteUint16(guild.MemberCount) From 33685fe36a61c70128374c5cd6ae20aeba5f23e0 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 23 Oct 2022 16:30:52 +1100 Subject: [PATCH 65/95] fix road leaderboard overflow --- server/channelserver/handlers_rengoku.go | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/server/channelserver/handlers_rengoku.go b/server/channelserver/handlers_rengoku.go index d9f58df57..1a581e80c 100644 --- a/server/channelserver/handlers_rengoku.go +++ b/server/channelserver/handlers_rengoku.go @@ -136,6 +136,10 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, s.Name, true) ps.Uint8(bf, "", false) } + if i > 100 { + i++ + continue + } scoreData.WriteUint32(i) scoreData.WriteUint32(score.MaxStagesMP) ps.Uint8(scoreData, score.Name, true) @@ -152,6 +156,10 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, s.Name, true) ps.Uint8(bf, "", false) } + if i > 100 { + i++ + continue + } scoreData.WriteUint32(i) scoreData.WriteUint32(score.MaxPointsMP) ps.Uint8(scoreData, score.Name, true) @@ -169,6 +177,10 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, s.Name, true) ps.Uint8(bf, "", false) } + if i > 100 { + i++ + continue + } scoreData.WriteUint32(i) scoreData.WriteUint32(score.MaxStagesMP) ps.Uint8(scoreData, score.Name, true) @@ -189,6 +201,10 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, s.Name, true) ps.Uint8(bf, "", false) } + if i > 100 { + i++ + continue + } scoreData.WriteUint32(i) scoreData.WriteUint32(score.MaxPointsMP) ps.Uint8(scoreData, score.Name, true) @@ -208,6 +224,10 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, s.Name, true) ps.Uint8(bf, "", false) } + if i > 100 { + i++ + continue + } scoreData.WriteUint32(i) scoreData.WriteUint32(score.MaxStagesSP) ps.Uint8(scoreData, score.Name, true) @@ -224,6 +244,10 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, s.Name, true) ps.Uint8(bf, "", false) } + if i > 100 { + i++ + continue + } scoreData.WriteUint32(i) scoreData.WriteUint32(score.MaxPointsSP) ps.Uint8(scoreData, score.Name, true) @@ -241,6 +265,10 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, s.Name, true) ps.Uint8(bf, "", false) } + if i > 100 { + i++ + continue + } scoreData.WriteUint32(i) scoreData.WriteUint32(score.MaxStagesSP) ps.Uint8(scoreData, score.Name, true) @@ -261,6 +289,10 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, s.Name, true) ps.Uint8(bf, "", false) } + if i > 100 { + i++ + continue + } scoreData.WriteUint32(i) scoreData.WriteUint32(score.MaxPointsSP) ps.Uint8(scoreData, score.Name, true) From 1e3095781c95ae8a76db16af7cfd865a5d3b3e65 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 23 Oct 2022 17:31:14 +1100 Subject: [PATCH 66/95] optimise road leaderboard code --- server/channelserver/handlers_rengoku.go | 252 +++++------------------ 1 file changed, 52 insertions(+), 200 deletions(-) diff --git a/server/channelserver/handlers_rengoku.go b/server/channelserver/handlers_rengoku.go index 1a581e80c..f8b4b7c66 100644 --- a/server/channelserver/handlers_rengoku.go +++ b/server/channelserver/handlers_rengoku.go @@ -3,6 +3,7 @@ package channelserver import ( ps "erupe-ce/common/pascalstring" "fmt" + "github.com/jmoiron/sqlx" "io/ioutil" "path/filepath" @@ -96,20 +97,13 @@ func handleMsgMhfGetRengokuBinary(s *Session, p mhfpacket.MHFPacket) { doAckBufSucceed(s, pkt.AckHandle, data) } -const rengokuScoreQuery = ` -SELECT max_stages_mp, max_points_mp, max_stages_sp, max_points_sp, c.name, gc.guild_id -FROM rengoku_score rs +const rengokuScoreQuery = `, c.name FROM rengoku_score rs LEFT JOIN characters c ON c.id = rs.character_id -LEFT JOIN guild_characters gc ON gc.character_id = rs.character_id -` +LEFT JOIN guild_characters gc ON gc.character_id = rs.character_id ` type RengokuScore struct { - Name string `db:"name"` - GuildID int `db:"guild_id"` - MaxStagesMP uint32 `db:"max_stages_mp"` - MaxPointsMP uint32 `db:"max_points_mp"` - MaxStagesSP uint32 `db:"max_stages_sp"` - MaxPointsSP uint32 `db:"max_points_sp"` + Name string `db:"name"` + Score uint32 `db:"score"` } func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { @@ -121,202 +115,60 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { guild = nil } + if pkt.Leaderboard == 2 || pkt.Leaderboard == 3 || pkt.Leaderboard == 6 || pkt.Leaderboard == 7 { + if guild == nil { + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 11)) + return + } + } + var score RengokuScore + var selfExist bool i := uint32(1) bf := byteframe.NewByteFrame() scoreData := byteframe.NewByteFrame() + + var rows *sqlx.Rows switch pkt.Leaderboard { - case 0: // Max stage overall MP - rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_stages_mp DESC", rengokuScoreQuery)) - for rows.Next() { - rows.StructScan(&score) - if score.Name == s.Name { - bf.WriteUint32(i) - bf.WriteUint32(score.MaxStagesMP) - ps.Uint8(bf, s.Name, true) - ps.Uint8(bf, "", false) - } - if i > 100 { - i++ - continue - } - scoreData.WriteUint32(i) - scoreData.WriteUint32(score.MaxStagesMP) - ps.Uint8(scoreData, score.Name, true) - ps.Uint8(scoreData, "", false) - i++ - } - case 1: // Max RdP overall MP - rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_points_mp DESC", rengokuScoreQuery)) - for rows.Next() { - rows.StructScan(&score) - if score.Name == s.Name { - bf.WriteUint32(i) - bf.WriteUint32(score.MaxPointsMP) - ps.Uint8(bf, s.Name, true) - ps.Uint8(bf, "", false) - } - if i > 100 { - i++ - continue - } - scoreData.WriteUint32(i) - scoreData.WriteUint32(score.MaxPointsMP) - ps.Uint8(scoreData, score.Name, true) - ps.Uint8(scoreData, "", false) - i++ - } - case 2: // Max stage guild MP - if guild != nil { - rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_stages_mp DESC", rengokuScoreQuery), guild.ID) - for rows.Next() { - rows.StructScan(&score) - if score.Name == s.Name { - bf.WriteUint32(i) - bf.WriteUint32(score.MaxStagesMP) - ps.Uint8(bf, s.Name, true) - ps.Uint8(bf, "", false) - } - if i > 100 { - i++ - continue - } - scoreData.WriteUint32(i) - scoreData.WriteUint32(score.MaxStagesMP) - ps.Uint8(scoreData, score.Name, true) - ps.Uint8(scoreData, "", false) - i++ - } - } else { - bf.WriteBytes(make([]byte, 11)) - } - case 3: // Max RdP guild MP - if guild != nil { - rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_points_mp DESC", rengokuScoreQuery), guild.ID) - for rows.Next() { - rows.StructScan(&score) - if score.Name == s.Name { - bf.WriteUint32(i) - bf.WriteUint32(score.MaxPointsMP) - ps.Uint8(bf, s.Name, true) - ps.Uint8(bf, "", false) - } - if i > 100 { - i++ - continue - } - scoreData.WriteUint32(i) - scoreData.WriteUint32(score.MaxPointsMP) - ps.Uint8(scoreData, score.Name, true) - ps.Uint8(scoreData, "", false) - i++ - } - } else { - bf.WriteBytes(make([]byte, 11)) - } - case 4: // Max stage overall SP - rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_stages_sp DESC", rengokuScoreQuery)) - for rows.Next() { - rows.StructScan(&score) - if score.Name == s.Name { - bf.WriteUint32(i) - bf.WriteUint32(score.MaxStagesSP) - ps.Uint8(bf, s.Name, true) - ps.Uint8(bf, "", false) - } - if i > 100 { - i++ - continue - } - scoreData.WriteUint32(i) - scoreData.WriteUint32(score.MaxStagesSP) - ps.Uint8(scoreData, score.Name, true) - ps.Uint8(scoreData, "", false) - i++ - } - case 5: // Max RdP overall SP - rows, _ := s.server.db.Queryx(fmt.Sprintf("%s ORDER BY max_points_sp DESC", rengokuScoreQuery)) - for rows.Next() { - rows.StructScan(&score) - if score.Name == s.Name { - bf.WriteUint32(i) - bf.WriteUint32(score.MaxPointsSP) - ps.Uint8(bf, s.Name, true) - ps.Uint8(bf, "", false) - } - if i > 100 { - i++ - continue - } - scoreData.WriteUint32(i) - scoreData.WriteUint32(score.MaxPointsSP) - ps.Uint8(scoreData, score.Name, true) - ps.Uint8(scoreData, "", false) - i++ - } - case 6: // Max stage guild SP - if guild != nil { - rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_stages_sp DESC", rengokuScoreQuery), guild.ID) - for rows.Next() { - rows.StructScan(&score) - if score.Name == s.Name { - bf.WriteUint32(i) - bf.WriteUint32(score.MaxStagesSP) - ps.Uint8(bf, s.Name, true) - ps.Uint8(bf, "", false) - } - if i > 100 { - i++ - continue - } - scoreData.WriteUint32(i) - scoreData.WriteUint32(score.MaxStagesSP) - ps.Uint8(scoreData, score.Name, true) - ps.Uint8(scoreData, "", false) - i++ - } - } else { - bf.WriteBytes(make([]byte, 11)) - } - case 7: // Max RdP guild SP - if guild != nil { - rows, _ := s.server.db.Queryx(fmt.Sprintf("%s WHERE guild_id=$1 ORDER BY max_points_sp DESC", rengokuScoreQuery), guild.ID) - for rows.Next() { - rows.StructScan(&score) - if score.Name == s.Name { - bf.WriteUint32(i) - bf.WriteUint32(score.MaxPointsSP) - ps.Uint8(bf, s.Name, true) - ps.Uint8(bf, "", false) - } - if i > 100 { - i++ - continue - } - scoreData.WriteUint32(i) - scoreData.WriteUint32(score.MaxPointsSP) - ps.Uint8(scoreData, score.Name, true) - ps.Uint8(scoreData, "", false) - i++ - } - } else { - bf.WriteBytes(make([]byte, 11)) - } + case 0: + rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_mp AS score %s ORDER BY max_stages_mp DESC", rengokuScoreQuery)) + case 1: + rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_mp AS score %s ORDER BY max_points_mp DESC", rengokuScoreQuery)) + case 2: + rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_mp AS score %s WHERE guild_id=$1 ORDER BY max_stages_mp DESC", rengokuScoreQuery), guild.ID) + case 3: + rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_mp AS score %s WHERE guild_id=$1 ORDER BY max_points_mp DESC", rengokuScoreQuery), guild.ID) + case 4: + rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_sp AS score %s ORDER BY max_stages_sp DESC", rengokuScoreQuery)) + case 5: + rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_sp AS score %s ORDER BY max_points_sp DESC", rengokuScoreQuery)) + case 6: + rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_stages_sp AS score %s WHERE guild_id=$1 ORDER BY max_stages_sp DESC", rengokuScoreQuery), guild.ID) + case 7: + rows, _ = s.server.db.Queryx(fmt.Sprintf("SELECT max_points_sp AS score %s WHERE guild_id=$1 ORDER BY max_points_sp DESC", rengokuScoreQuery), guild.ID) } - if i == 1 { - bf.WriteUint32(1) - bf.WriteUint32(0) - ps.Uint8(bf, s.Name, true) - ps.Uint8(bf, "", false) - bf.WriteUint8(1) - bf.WriteUint32(1) - bf.WriteUint32(0) - ps.Uint8(bf, s.Name, true) - ps.Uint8(bf, "", false) - } else { - bf.WriteUint8(uint8(i) - 1) - bf.WriteBytes(scoreData.Data()) + + for rows.Next() { + rows.StructScan(&score) + if score.Name == s.Name { + bf.WriteUint32(i) + bf.WriteUint32(score.Score) + ps.Uint8(bf, s.Name, true) + ps.Uint8(bf, "", false) + selfExist = true + } + scoreData.WriteUint32(i) + scoreData.WriteUint32(score.Score) + ps.Uint8(scoreData, score.Name, true) + ps.Uint8(scoreData, "", false) + i++ } + + if !selfExist { + bf.WriteBytes(make([]byte, 10)) + } + bf.WriteUint8(uint8(i) - 1) + bf.WriteBytes(scoreData.Data()) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } From 3cd756c35d22c6400f321a7d35ad3b23d476be94 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 23 Oct 2022 18:22:56 +1100 Subject: [PATCH 67/95] fix road leaderboard overflow --- server/channelserver/handlers_rengoku.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/channelserver/handlers_rengoku.go b/server/channelserver/handlers_rengoku.go index f8b4b7c66..c1e8d2dbd 100644 --- a/server/channelserver/handlers_rengoku.go +++ b/server/channelserver/handlers_rengoku.go @@ -157,6 +157,10 @@ func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) { ps.Uint8(bf, "", false) selfExist = true } + if i > 100 { + i++ + continue + } scoreData.WriteUint32(i) scoreData.WriteUint32(score.Score) ps.Uint8(scoreData, score.Name, true) From 470eb32763df3e22d653cf80b18754607486d919 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 23 Oct 2022 18:32:46 +1100 Subject: [PATCH 68/95] merge linting --- server/channelserver/handlers_guild.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 4f7594eb0..4561f69a7 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1257,7 +1257,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { hasNextPage = true alliances = alliances[:10] } - bf.WriteUint16(uint16(len(alliances))) + bf.WriteUint16(uint16(len(alliances))) bf.WriteBool(hasNextPage) // Unk for _, alliance := range alliances { bf.WriteUint32(alliance.ID) @@ -1283,7 +1283,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { hasNextPage = true guilds = guilds[:10] } - bf.WriteUint16(uint16(len(guilds))) + bf.WriteUint16(uint16(len(guilds))) bf.WriteBool(hasNextPage) for _, guild := range guilds { bf.WriteUint32(guild.ID) From 1ff7561d5cdb888bf666a13424a4f95a48c695bc Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 23 Oct 2022 18:34:58 +1100 Subject: [PATCH 69/95] merge linting --- network/mhfpacket/msg_mhf_enumerate_guild.go | 2 +- server/channelserver/handlers_guild.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/network/mhfpacket/msg_mhf_enumerate_guild.go b/network/mhfpacket/msg_mhf_enumerate_guild.go index a976cb34b..691f8241f 100644 --- a/network/mhfpacket/msg_mhf_enumerate_guild.go +++ b/network/mhfpacket/msg_mhf_enumerate_guild.go @@ -47,7 +47,7 @@ func (m *MsgMhfEnumerateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli m.Type = EnumerateGuildType(bf.ReadUint8()) m.Page = bf.ReadUint8() m.Sorting = bf.ReadBool() - bf.ReadUint8() + _ = bf.ReadUint8() m.RawDataPayload = bf.DataFromCurrent() bf.Seek(-2, io.SeekEnd) return nil diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 4561f69a7..6a3c03373 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1258,7 +1258,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { alliances = alliances[:10] } bf.WriteUint16(uint16(len(alliances))) - bf.WriteBool(hasNextPage) // Unk + bf.WriteBool(hasNextPage) for _, alliance := range alliances { bf.WriteUint32(alliance.ID) bf.WriteUint32(alliance.ParentGuild.LeaderCharID) From cfb2dff9c312e66d7b57976a36d418e2dbf39d44 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 23 Oct 2022 18:46:41 +1100 Subject: [PATCH 70/95] sort festa members by soul count --- server/channelserver/handlers_festa.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/channelserver/handlers_festa.go b/server/channelserver/handlers_festa.go index ffe953943..005575e58 100644 --- a/server/channelserver/handlers_festa.go +++ b/server/channelserver/handlers_festa.go @@ -6,6 +6,7 @@ import ( ps "erupe-ce/common/pascalstring" "erupe-ce/network/mhfpacket" "math/rand" + "sort" "time" ) @@ -310,6 +311,9 @@ func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() bf.WriteUint16(uint16(len(members))) bf.WriteUint16(0) // Unk + sort.Slice(members, func(i, j int) bool { + return members[i].Souls > members[j].Souls + }) for _, member := range members { bf.WriteUint32(member.CharID) bf.WriteUint32(member.Souls) From a71ad2aa3eac1e339a3f65fb07835537624b19ee Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 23 Oct 2022 18:50:48 +1100 Subject: [PATCH 71/95] fix festa prize enumeration --- server/channelserver/handlers_festa.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_festa.go b/server/channelserver/handlers_festa.go index 005575e58..9f925f3dc 100644 --- a/server/channelserver/handlers_festa.go +++ b/server/channelserver/handlers_festa.go @@ -381,7 +381,7 @@ type Prize struct { func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateFestaPersonalPrize) - rows, _ := s.server.db.Queryx("SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = 4) AS claimed FROM festa_prizes fp WHERE type='personal'") + rows, _ := s.server.db.Queryx(`SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = $1) AS claimed FROM festa_prizes fp WHERE type='personal'`, s.charID) var count uint32 prizeData := byteframe.NewByteFrame() for rows.Next() { @@ -407,7 +407,7 @@ func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) func handleMsgMhfEnumerateFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateFestaIntermediatePrize) - rows, _ := s.server.db.Queryx("SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = 4) AS claimed FROM festa_prizes fp WHERE type='guild'") + rows, _ := s.server.db.Queryx(`SELECT id, tier, souls_req, item_id, num_item, (SELECT count(*) FROM festa_prizes_accepted fpa WHERE fp.id = fpa.prize_id AND fpa.character_id = $1) AS claimed FROM festa_prizes fp WHERE type='guild'`, s.charID) var count uint32 prizeData := byteframe.NewByteFrame() for rows.Next() { From ae8741dbd21d557a58ec6912b54f1bea34cdbeed Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 05:04:28 +1100 Subject: [PATCH 72/95] prevent panic on nil stage --- server/channelserver/handlers.go | 12 +++++------- server/channelserver/handlers_stage.go | 4 ++-- server/channelserver/sys_stage.go | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index cc5f57d9b..a4d7e9e14 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -191,13 +191,11 @@ func logoutPlayer(s *Session) { for _, stage := range s.server.stages { // Tell sessions registered to disconnecting players quest to unregister - if stage.hostCharID == s.charID { - if s.stage.id == "sl1Ns200p0a0u0" { - for _, sess := range s.server.sessions { - for rSlot := range stage.reservedClientSlots { - if sess.charID == rSlot { - sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) - } + if stage.host.charID == s.charID { + for _, sess := range s.server.sessions { + for rSlot := range stage.reservedClientSlots { + if sess.charID == rSlot && sess.stage != nil && sess.stage.id == "sl1Ns200p0a0u0" { + sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) } } } diff --git a/server/channelserver/handlers_stage.go b/server/channelserver/handlers_stage.go index cc98417c6..90ecdec99 100644 --- a/server/channelserver/handlers_stage.go +++ b/server/channelserver/handlers_stage.go @@ -19,7 +19,7 @@ func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) { doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } else { stage := NewStage(pkt.StageID) - stage.hostCharID = s.charID + stage.host = s stage.maxPlayers = uint16(pkt.PlayerCount) s.server.stages[stage.id] = stage doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) @@ -43,7 +43,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { stage = s.server.stages[stageID] s.server.Unlock() stage.Lock() - stage.hostCharID = s.charID + stage.host = s stage.clients[s] = s.charID stage.Unlock() } diff --git a/server/channelserver/sys_stage.go b/server/channelserver/sys_stage.go index 49e454749..4cd96a7f8 100644 --- a/server/channelserver/sys_stage.go +++ b/server/channelserver/sys_stage.go @@ -46,7 +46,7 @@ type Stage struct { // other clients expect the server to echo them back in the exact same format. rawBinaryData map[stageBinaryKey][]byte - hostCharID uint32 + host *Session maxPlayers uint16 password string createdAt string From 4dfc6c11dcdaeaebc3dec3e9b9c55560da24d552 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 05:23:05 +1100 Subject: [PATCH 73/95] fix disconnect not applying to other stages --- server/channelserver/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index a4d7e9e14..34fa8a540 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -194,7 +194,7 @@ func logoutPlayer(s *Session) { if stage.host.charID == s.charID { for _, sess := range s.server.sessions { for rSlot := range stage.reservedClientSlots { - if sess.charID == rSlot && sess.stage != nil && sess.stage.id == "sl1Ns200p0a0u0" { + if sess.charID == rSlot && sess.stage != nil && sess.stage.id[3:5] != "Qs" { sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) } } From 2013f51233a2085dd582bb41fb801d1652c146aa Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 07:56:36 +1100 Subject: [PATCH 74/95] prevent panic on nil host --- server/channelserver/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 34fa8a540..be2d37794 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -191,7 +191,7 @@ func logoutPlayer(s *Session) { for _, stage := range s.server.stages { // Tell sessions registered to disconnecting players quest to unregister - if stage.host.charID == s.charID { + if stage.host != nil && stage.host.charID == s.charID { for _, sess := range s.server.sessions { for rSlot := range stage.reservedClientSlots { if sess.charID == rSlot && sess.stage != nil && sess.stage.id[3:5] != "Qs" { From 25a6527c938096ba44019d759dd1ae6067b6028b Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 09:14:57 +1100 Subject: [PATCH 75/95] automate netcafe reset --- bundled-schema/NetcafeDefaults.sql | 13 +++++++++++++ patch-schema/netcafe-2.sql | 6 ++++++ patch-schema/netcafe.sql | 10 ---------- server/channelserver/handlers_cafe.go | 12 ++++++++++-- 4 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 bundled-schema/NetcafeDefaults.sql create mode 100644 patch-schema/netcafe-2.sql diff --git a/bundled-schema/NetcafeDefaults.sql b/bundled-schema/NetcafeDefaults.sql new file mode 100644 index 000000000..458cfa7b9 --- /dev/null +++ b/bundled-schema/NetcafeDefaults.sql @@ -0,0 +1,13 @@ +BEGIN; + +INSERT INTO public.cafebonus (time_req, item_type, item_id, quantity) +VALUES + (1800, 17, 0, 250), + (3600, 17, 0, 500), + (7200, 17, 0, 1000), + (10800, 17, 0, 1500), + (18000, 17, 0, 1750), + (28800, 17, 0, 3000), + (43200, 17, 0, 4000); + +END; \ No newline at end of file diff --git a/patch-schema/netcafe-2.sql b/patch-schema/netcafe-2.sql new file mode 100644 index 000000000..d2a1f0763 --- /dev/null +++ b/patch-schema/netcafe-2.sql @@ -0,0 +1,6 @@ +BEGIN; + +ALTER TABLE IF EXISTS public.characters + ADD COLUMN cafe_reset timestamp without time zone; + +END; \ No newline at end of file diff --git a/patch-schema/netcafe.sql b/patch-schema/netcafe.sql index e284742ce..563e10fb0 100644 --- a/patch-schema/netcafe.sql +++ b/patch-schema/netcafe.sql @@ -27,14 +27,4 @@ CREATE TABLE IF NOT EXISTS public.cafe_accepted character_id integer NOT NULL ); -INSERT INTO public.cafebonus (time_req, item_type, item_id, quantity) -VALUES - (1800, 17, 0, 250), - (3600, 17, 0, 500), - (7200, 17, 0, 1000), - (10800, 17, 0, 1500), - (18000, 17, 0, 1750), - (28800, 17, 0, 3000), - (43200, 17, 0, 4000); - END; \ No newline at end of file diff --git a/server/channelserver/handlers_cafe.go b/server/channelserver/handlers_cafe.go index c7d826429..de634191b 100644 --- a/server/channelserver/handlers_cafe.go +++ b/server/channelserver/handlers_cafe.go @@ -4,6 +4,7 @@ import ( "erupe-ce/common/byteframe" ps "erupe-ce/common/pascalstring" "erupe-ce/network/mhfpacket" + "fmt" "go.uber.org/zap" "io" "time" @@ -71,15 +72,22 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetCafeDuration) bf := byteframe.NewByteFrame() + var cafeReset time.Time + err := s.server.db.QueryRow(`SELECT cafe_reset FROM characters WHERE id=$1`, s.charID).Scan(&cafeReset) + if Time_Current_Adjusted().After(cafeReset) { + cafeReset = TimeWeekNext() + s.server.db.Exec(`UPDATE characters SET cafe_time=0, cafe_reset=$1 WHERE id=$2`, cafeReset, s.charID) + } + var cafeTime uint32 - err := s.server.db.QueryRow("SELECT cafe_time FROM characters WHERE id = $1", s.charID).Scan(&cafeTime) + err = s.server.db.QueryRow("SELECT cafe_time FROM characters WHERE id = $1", s.charID).Scan(&cafeTime) if err != nil { panic(err) } cafeTime = uint32(Time_Current_Adjusted().Unix()) - uint32(s.sessionStart) + cafeTime bf.WriteUint32(cafeTime) // Total cafe time bf.WriteUint16(0) - ps.Uint16(bf, "Resets at next maintenance", true) + ps.Uint16(bf, fmt.Sprintf("Resets after %s %d", cafeReset.Month().String(), cafeReset.Day()), true) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } From 9560cdc7dfcc89d4d4b051e6e7f9f5416b19c12b Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 09:25:20 +1100 Subject: [PATCH 76/95] adjust wording --- server/channelserver/handlers_cafe.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers_cafe.go b/server/channelserver/handlers_cafe.go index de634191b..385701428 100644 --- a/server/channelserver/handlers_cafe.go +++ b/server/channelserver/handlers_cafe.go @@ -87,7 +87,7 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) { cafeTime = uint32(Time_Current_Adjusted().Unix()) - uint32(s.sessionStart) + cafeTime bf.WriteUint32(cafeTime) // Total cafe time bf.WriteUint16(0) - ps.Uint16(bf, fmt.Sprintf("Resets after %s %d", cafeReset.Month().String(), cafeReset.Day()), true) + ps.Uint16(bf, fmt.Sprintf("Resets on %s %d", cafeReset.Month().String(), cafeReset.Day()), true) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } From 77ed0564cea7231dc3a8ce82207cbd5976c82a86 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 16:00:58 +1100 Subject: [PATCH 77/95] normalise config --- config.json | 126 +++++++++++++++++++++++------------------------ config/config.go | 33 ++++++------- main.go | 4 +- 3 files changed, 81 insertions(+), 82 deletions(-) diff --git a/config.json b/config.json index 9f8eed32f..a7e18a70a 100644 --- a/config.json +++ b/config.json @@ -3,13 +3,13 @@ "BinPath": "bin", "DisableSoftCrash": false, "FeaturedWeapons": 2, - "devmode": true, - "devmodeoptions": { + "DevMode": true, + "DevModeOptions": { "EnableLauncherServer": false, - "hideLoginNotice": false, - "loginNotice": "
Welcome to Erupe SU9.1 Beta!
Erupe is experimental software, we are not liable for any
issues caused by installing the software!

■Report bugs on Discord!

■Test everything!

■Don't talk to softlocking NPCs!

■Fork the code on GitHub!

Thank you to all of the contributors,

this wouldn't exist without you.", - "cleandb": false, - "maxlauncherhr": false, + "HideLoginNotice": false, + "LoginNotice": "
Welcome to Erupe SU9.1 Beta!
Erupe is experimental software, we are not liable for any
issues caused by installing the software!

■Report bugs on Discord!

■Test everything!

■Don't talk to softlocking NPCs!

■Fork the code on GitHub!

Thank you to all of the contributors,

this wouldn't exist without you.", + "CleanDB": false, + "MaxLauncherHR": false, "LogInboundMessages": false, "LogOutboundMessages": false, "MaxHexdumpLength": 256, @@ -26,88 +26,88 @@ "OutputDir": "savedata" } }, - "discord": { - "enabled": false, - "bottoken": "", - "realtimeChannelID": "" + "Discord": { + "Enabled": false, + "BotToken": "", + "RealtimeChannelID": "" }, "Commands": [ { - "name": "Rights", - "enabled": true, - "prefix": "!rights" + "Name": "Rights", + "Enabled": true, + "Prefix": "!rights" }, { - "name": "Raviente", - "enabled": true, - "prefix": "!ravi" + "Name": "Raviente", + "Enabled": true, + "Prefix": "!ravi" }, { - "name": "Teleport", - "enabled": false, - "prefix": "!tele" + "Name": "Teleport", + "Enabled": false, + "Prefix": "!tele" }, { - "name": "Reload", - "enabled": true, - "prefix": "!reload" + "Name": "Reload", + "Enabled": true, + "Prefix": "!reload" }, { - "name": "KeyQuest", - "enabled": false, - "prefix": "!kqf" + "Name": "KeyQuest", + "Enabled": false, + "Prefix": "!kqf" } ], - "database": { - "host": "localhost", - "port": 5432, - "user": "postgres", - "password": "", - "database": "erupe" + "Database": { + "Host": "localhost", + "Port": 5432, + "User": "postgres", + "Password": "a", + "Database": "erupe" }, - "launcher": { - "enabled": true, - "port": 80, + "Launcher": { + "Enabled": false, + "Port": 80, "UseOriginalLauncherFiles": false }, - "sign": { - "enabled": true, - "port": 53312 + "Sign": { + "Enabled": true, + "Port": 53312 }, - "channel": { - "enabled": true + "Channel": { + "Enabled": true }, - "entrance": { - "enabled": true, - "port": 53310, - "entries": [ + "Entrance": { + "Enabled": true, + "Port": 53310, + "Entries": [ { - "name": "Newbie", "description": "", "ip": "", "type": 3, "recommended": 2, "allowedclientflags": 0, - "channels": [ - { "port": 54001, "MaxPlayers": 100 }, - { "port": 54002, "MaxPlayers": 100 } + "Name": "Newbie", "Description": "", "IP": "", "Type": 3, "Recommended": 2, "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54001, "MaxPlayers": 100 }, + { "Port": 54002, "MaxPlayers": 100 } ] }, { - "name": "Normal", "description": "", "ip": "", "type": 1, "recommended": 0, "allowedclientflags": 0, - "channels": [ - { "port": 54003, "MaxPlayers": 100 }, - { "port": 54004, "MaxPlayers": 100 } + "Name": "Normal", "Description": "", "IP": "", "Type": 1, "Recommended": 0, "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54003, "MaxPlayers": 100 }, + { "Port": 54004, "MaxPlayers": 100 } ] }, { - "name": "Cities", "description": "", "ip": "", "type": 2, "recommended": 0, "allowedclientflags": 0, - "channels": [ - { "port": 54005, "MaxPlayers": 100 } + "Name": "Cities", "Description": "", "IP": "", "Type": 2, "Recommended": 0, "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54005, "MaxPlayers": 100 } ] }, { - "name": "Tavern", "description": "", "ip": "", "type": 4, "recommended": 0, "allowedclientflags": 0, - "channels": [ - { "port": 54006, "MaxPlayers": 100 } + "Name": "Tavern", "Description": "", "IP": "", "Type": 4, "Recommended": 0, "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54006, "MaxPlayers": 100 } ] }, { - "name": "Return", "description": "", "ip": "", "type": 5, "recommended": 0, "allowedclientflags": 0, - "channels": [ - { "port": 54007, "MaxPlayers": 100 } + "Name": "Return", "Description": "", "IP": "", "Type": 5, "Recommended": 0, "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54007, "MaxPlayers": 100 } ] }, { - "name": "MezFes", "description": "", "ip": "", "type": 6, "recommended": 6, "allowedclientflags": 0, - "channels": [ - { "port": 54008, "MaxPlayers": 100 } + "Name": "MezFes", "Description": "", "IP": "", "Type": 6, "Recommended": 6, "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54008, "MaxPlayers": 100 } ] } ] diff --git a/config/config.go b/config/config.go index ca67b1f9c..e040c7808 100644 --- a/config/config.go +++ b/config/config.go @@ -30,23 +30,22 @@ type Config struct { // DevModeOptions holds various debug/temporary options for use while developing Erupe. type DevModeOptions struct { - EnableLauncherServer bool // Enables the launcher server to be served on port 80 - HideLoginNotice bool // Hide the Erupe notice on login - LoginNotice string // MHFML string of the login notice displayed - CleanDB bool // Automatically wipes the DB on server reset. - MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds. - LogInboundMessages bool // Log all messages sent to the server - LogOutboundMessages bool // Log all messages sent to the clients - MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled - DivaEvent int // Diva Defense event status - FestaEvent int // Hunter's Festa event status - TournamentEvent int // VS Tournament event status - MezFesEvent bool // MezFes status - MezFesAlt bool // Swaps out Volpakkun for Tokotoko - DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!) - DisableMailItems bool // Hack to prevent english versions of MHF from crashing - QuestDebugTools bool // Enable various quest debug logs - SaveDumps SaveDumpOptions + HideLoginNotice bool // Hide the Erupe notice on login + LoginNotice string // MHFML string of the login notice displayed + CleanDB bool // Automatically wipes the DB on server reset. + MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds. + LogInboundMessages bool // Log all messages sent to the server + LogOutboundMessages bool // Log all messages sent to the clients + MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled + DivaEvent int // Diva Defense event status + FestaEvent int // Hunter's Festa event status + TournamentEvent int // VS Tournament event status + MezFesEvent bool // MezFes status + MezFesAlt bool // Swaps out Volpakkun for Tokotoko + DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!) + DisableMailItems bool // Hack to prevent english versions of MHF from crashing + QuestDebugTools bool // Enable various quest debug logs + SaveDumps SaveDumpOptions } type SaveDumpOptions struct { diff --git a/main.go b/main.go index 3964ff315..ab1cea809 100644 --- a/main.go +++ b/main.go @@ -119,7 +119,7 @@ func main() { // Launcher HTTP server. var launcherServer *launcherserver.Server - if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.EnableLauncherServer { + if config.ErupeConfig.Launcher.Enabled { launcherServer = launcherserver.NewServer( &launcherserver.Config{ Logger: logger.Named("launcher"), @@ -235,7 +235,7 @@ func main() { entranceServer.Shutdown() } - if config.ErupeConfig.DevModeOptions.EnableLauncherServer { + if config.ErupeConfig.Launcher.Enabled { launcherServer.Shutdown() } From cad882e8995204e8f11ef11003eb320512430459 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 16:01:26 +1100 Subject: [PATCH 78/95] normalise config --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index a7e18a70a..680213df5 100644 --- a/config.json +++ b/config.json @@ -58,7 +58,7 @@ "Host": "localhost", "Port": 5432, "User": "postgres", - "Password": "a", + "Password": "", "Database": "erupe" }, "Launcher": { From 50c8d39d7f11782980f0f5049c2c4d4cf837aa28 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 16:09:43 +1100 Subject: [PATCH 79/95] hide application notification for non recruiters --- server/channelserver/handlers_guild.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 6a3c03373..3f0df48b3 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1034,7 +1034,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { } applicants, err := GetGuildMembers(s, guild.ID, true) - if err != nil { + if err != nil || (characterGuildData != nil && !characterGuildData.CanRecruit()) { bf.WriteUint16(0) } else { bf.WriteUint16(uint16(len(applicants))) From fda2e74442125c949a169c411410a311ecde48c0 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 16:51:56 +1100 Subject: [PATCH 80/95] persist cafe time --- main.go | 2 -- server/channelserver/handlers_cafe.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/main.go b/main.go index ab1cea809..dcb3a14b4 100644 --- a/main.go +++ b/main.go @@ -105,8 +105,6 @@ func main() { // Clear stale data _ = db.MustExec("DELETE FROM sign_sessions") _ = db.MustExec("DELETE FROM servers") - _ = db.MustExec("DELETE FROM cafe_accepted") - _ = db.MustExec("UPDATE characters SET cafe_time=0") // Clean the DB if the option is on. if config.ErupeConfig.DevMode && config.ErupeConfig.DevModeOptions.CleanDB { diff --git a/server/channelserver/handlers_cafe.go b/server/channelserver/handlers_cafe.go index 385701428..15b01f510 100644 --- a/server/channelserver/handlers_cafe.go +++ b/server/channelserver/handlers_cafe.go @@ -76,7 +76,7 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) { err := s.server.db.QueryRow(`SELECT cafe_reset FROM characters WHERE id=$1`, s.charID).Scan(&cafeReset) if Time_Current_Adjusted().After(cafeReset) { cafeReset = TimeWeekNext() - s.server.db.Exec(`UPDATE characters SET cafe_time=0, cafe_reset=$1 WHERE id=$2`, cafeReset, s.charID) + s.server.db.Exec(`UPDATE characters SET cafe_time=0, cafe_reset=$1 WHERE id=$2; DELETE FROM cafe_accepted WHERE character_id=$2`, cafeReset, s.charID) } var cafeTime uint32 From 55f1de11fe8467a5df743f904e806d5b7e47f0b3 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 17:48:57 +1100 Subject: [PATCH 81/95] add account creation toggle --- config.json | 1 + config/config.go | 1 + server/signserver/session.go | 15 +++++++++------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/config.json b/config.json index 680213df5..f0feb790e 100644 --- a/config.json +++ b/config.json @@ -5,6 +5,7 @@ "FeaturedWeapons": 2, "DevMode": true, "DevModeOptions": { + "AutoCreateAccount": true, "EnableLauncherServer": false, "HideLoginNotice": false, "LoginNotice": "
Welcome to Erupe SU9.1 Beta!
Erupe is experimental software, we are not liable for any
issues caused by installing the software!

■Report bugs on Discord!

■Test everything!

■Don't talk to softlocking NPCs!

■Fork the code on GitHub!

Thank you to all of the contributors,

this wouldn't exist without you.", diff --git a/config/config.go b/config/config.go index e040c7808..48da57344 100644 --- a/config/config.go +++ b/config/config.go @@ -30,6 +30,7 @@ type Config struct { // DevModeOptions holds various debug/temporary options for use while developing Erupe. type DevModeOptions struct { + AutoCreateAccount bool // Automatically create accounts if they don't exist HideLoginNotice bool // Hide the Erupe notice on login LoginNotice string // MHFML string of the login notice displayed CleanDB bool // Automatically wipes the DB on server reset. diff --git a/server/signserver/session.go b/server/signserver/session.go index f52ebb401..6b2e38b8c 100644 --- a/server/signserver/session.go +++ b/server/signserver/session.go @@ -93,12 +93,15 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error { s.logger.Info("Account not found", zap.String("reqUsername", reqUsername)) serverRespBytes = makeSignInFailureResp(SIGN_EAUTH) - // HACK(Andoryuuta): Create a new account if it doesn't exit. - s.logger.Info("Creating account", zap.String("reqUsername", reqUsername), zap.String("reqPassword", reqPassword)) - err = s.server.registerDBAccount(reqUsername, reqPassword) - if err != nil { - s.logger.Info("Error on creating new account", zap.Error(err)) - serverRespBytes = makeSignInFailureResp(SIGN_EABORT) + if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.AutoCreateAccount { + s.logger.Info("Creating account", zap.String("reqUsername", reqUsername), zap.String("reqPassword", reqPassword)) + err = s.server.registerDBAccount(reqUsername, reqPassword) + if err != nil { + s.logger.Info("Error on creating new account", zap.Error(err)) + serverRespBytes = makeSignInFailureResp(SIGN_EABORT) + break + } + } else { break } From 75bd425fbf424acd93c88ce7b6b82afae35f0e17 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 24 Oct 2022 18:33:55 +1100 Subject: [PATCH 82/95] remove migrations directory --- migrations/000001_initial_db.down.sql | 10 -- migrations/000001_initial_db.up.sql | 37 ------- migrations/000002_alter_characters.down.sql | 8 -- migrations/000002_alter_characters.up.sql | 8 -- migrations/000003_character_savedata.down.sql | 6 -- migrations/000003_character_savedata.up.sql | 6 -- .../000004_character_additional.down.sql | 13 --- migrations/000004_character_additional.up.sql | 14 --- migrations/000005_quests.down.sql | 5 - migrations/000005_quests.up.sql | 8 -- migrations/000006_mercenary.down.sql | 6 -- migrations/000006_mercenary.up.sql | 6 -- migrations/000007_guilds.down.sql | 6 -- migrations/000007_guilds.up.sql | 22 ---- migrations/000008_guild_additional.down.sql | 11 -- migrations/000008_guild_additional.up.sql | 11 -- migrations/000009_character_social.down.sql | 6 -- migrations/000009_character_social.up.sql | 6 -- ...0010_guild_comments_festival_hall.down.sql | 10 -- ...000010_guild_comments_festival_hall.up.sql | 11 -- .../000011_character_points_minidata.down.sql | 24 ----- .../000011_character_points_minidata.up.sql | 100 ------------------ migrations/000012_loginboost_etc.down.sql | 5 - migrations/000012_loginboost_etc.up.sql | 13 --- migrations/000013_shop_constraints.down.sql | 12 --- migrations/000013_shop_constraints.up.sql | 12 --- .../000014_guild_flags_applications.down.sql | 18 ---- .../000014_guild_flags_applications.up.sql | 30 ------ migrations/000015_mail.down.sql | 3 - migrations/000015_mail.up.sql | 19 ---- migrations/000016_server.down.sql | 3 - migrations/000016_server.up.sql | 21 ---- migrations/000017_account.down.sql | 6 -- migrations/000017_account.up.sql | 45 -------- migrations/000018_event_week.down.sql | 3 - migrations/000018_event_week.up.sql | 11 -- migrations/000019_gook.down.sql | 3 - migrations/000019_gook.up.sql | 20 ---- migrations/000020_history.down.sql | 3 - migrations/000020_history.up.sql | 13 --- 40 files changed, 574 deletions(-) delete mode 100644 migrations/000001_initial_db.down.sql delete mode 100644 migrations/000001_initial_db.up.sql delete mode 100644 migrations/000002_alter_characters.down.sql delete mode 100644 migrations/000002_alter_characters.up.sql delete mode 100644 migrations/000003_character_savedata.down.sql delete mode 100644 migrations/000003_character_savedata.up.sql delete mode 100644 migrations/000004_character_additional.down.sql delete mode 100644 migrations/000004_character_additional.up.sql delete mode 100644 migrations/000005_quests.down.sql delete mode 100644 migrations/000005_quests.up.sql delete mode 100644 migrations/000006_mercenary.down.sql delete mode 100644 migrations/000006_mercenary.up.sql delete mode 100644 migrations/000007_guilds.down.sql delete mode 100644 migrations/000007_guilds.up.sql delete mode 100644 migrations/000008_guild_additional.down.sql delete mode 100644 migrations/000008_guild_additional.up.sql delete mode 100644 migrations/000009_character_social.down.sql delete mode 100644 migrations/000009_character_social.up.sql delete mode 100644 migrations/000010_guild_comments_festival_hall.down.sql delete mode 100644 migrations/000010_guild_comments_festival_hall.up.sql delete mode 100644 migrations/000011_character_points_minidata.down.sql delete mode 100644 migrations/000011_character_points_minidata.up.sql delete mode 100644 migrations/000012_loginboost_etc.down.sql delete mode 100644 migrations/000012_loginboost_etc.up.sql delete mode 100644 migrations/000013_shop_constraints.down.sql delete mode 100644 migrations/000013_shop_constraints.up.sql delete mode 100644 migrations/000014_guild_flags_applications.down.sql delete mode 100644 migrations/000014_guild_flags_applications.up.sql delete mode 100644 migrations/000015_mail.down.sql delete mode 100644 migrations/000015_mail.up.sql delete mode 100644 migrations/000016_server.down.sql delete mode 100644 migrations/000016_server.up.sql delete mode 100644 migrations/000017_account.down.sql delete mode 100644 migrations/000017_account.up.sql delete mode 100644 migrations/000018_event_week.down.sql delete mode 100644 migrations/000018_event_week.up.sql delete mode 100644 migrations/000019_gook.down.sql delete mode 100644 migrations/000019_gook.up.sql delete mode 100644 migrations/000020_history.down.sql delete mode 100644 migrations/000020_history.up.sql diff --git a/migrations/000001_initial_db.down.sql b/migrations/000001_initial_db.down.sql deleted file mode 100644 index 04f7e46f8..000000000 --- a/migrations/000001_initial_db.down.sql +++ /dev/null @@ -1,10 +0,0 @@ -BEGIN; - -DROP TABLE IF EXISTS sign_sessions; -DROP TABLE IF EXISTS characters; -DROP TABLE IF EXISTS users; - -DROP DOMAIN IF EXISTS uint8; -DROP DOMAIN IF EXISTS uint16; - -END; \ No newline at end of file diff --git a/migrations/000001_initial_db.up.sql b/migrations/000001_initial_db.up.sql deleted file mode 100644 index eeac64a33..000000000 --- a/migrations/000001_initial_db.up.sql +++ /dev/null @@ -1,37 +0,0 @@ -BEGIN; - -CREATE DOMAIN uint8 AS smallint - CHECK(VALUE >= 0 AND VALUE <= 255); - -CREATE DOMAIN uint16 AS integer - CHECK(VALUE >= 0 AND VALUE <= 65536); - -CREATE TABLE users ( - id serial NOT NULL PRIMARY KEY, - username text UNIQUE NOT NULL, - password text NOT NULL, - item_box bytea -); - -CREATE TABLE characters ( - id serial NOT NULL PRIMARY KEY, - user_id bigint REFERENCES users(id), - is_female boolean, - is_new_character boolean, - small_gr_level uint8, - gr_override_mode boolean, - name varchar(15), - unk_desc_string varchar(31), - gr_override_level uint16, - gr_override_unk0 uint8, - gr_override_unk1 uint8 -); - -CREATE TABLE sign_sessions ( - id serial NOT NULL PRIMARY KEY, - user_id bigint REFERENCES users(id), - auth_token_num bigint, - auth_token_str text -); - -END; \ No newline at end of file diff --git a/migrations/000002_alter_characters.down.sql b/migrations/000002_alter_characters.down.sql deleted file mode 100644 index c5eeb425b..000000000 --- a/migrations/000002_alter_characters.down.sql +++ /dev/null @@ -1,8 +0,0 @@ -BEGIN; - -ALTER TABLE characters - DROP COLUMN exp, - DROP COLUMN weapon, - DROP COLUMN last_login; - -END; \ No newline at end of file diff --git a/migrations/000002_alter_characters.up.sql b/migrations/000002_alter_characters.up.sql deleted file mode 100644 index 8e92154dc..000000000 --- a/migrations/000002_alter_characters.up.sql +++ /dev/null @@ -1,8 +0,0 @@ -BEGIN; - -ALTER TABLE characters - ADD COLUMN exp uint16, - ADD COLUMN weapon uint16, - ADD COLUMN last_login integer; - -END; \ No newline at end of file diff --git a/migrations/000003_character_savedata.down.sql b/migrations/000003_character_savedata.down.sql deleted file mode 100644 index d8d1ca8c6..000000000 --- a/migrations/000003_character_savedata.down.sql +++ /dev/null @@ -1,6 +0,0 @@ -BEGIN; - -ALTER TABLE characters - DROP COLUMN savedata; - -END; \ No newline at end of file diff --git a/migrations/000003_character_savedata.up.sql b/migrations/000003_character_savedata.up.sql deleted file mode 100644 index d0f39a223..000000000 --- a/migrations/000003_character_savedata.up.sql +++ /dev/null @@ -1,6 +0,0 @@ -BEGIN; - -ALTER TABLE characters - ADD COLUMN savedata bytea; - -END; \ No newline at end of file diff --git a/migrations/000004_character_additional.down.sql b/migrations/000004_character_additional.down.sql deleted file mode 100644 index 5229381cb..000000000 --- a/migrations/000004_character_additional.down.sql +++ /dev/null @@ -1,13 +0,0 @@ -BEGIN; - -ALTER TABLE characters - DROP COLUMN decomyset, - DROP COLUMN hunternavi, - DROP COLUMN otomoairou, - DROP COLUMN partner, - DROP COLUMN platebox, - DROP COLUMN platedata, - DROP COLUMN platemyset, - DROP COLUMN rengokudata; - -END; \ No newline at end of file diff --git a/migrations/000004_character_additional.up.sql b/migrations/000004_character_additional.up.sql deleted file mode 100644 index 699351796..000000000 --- a/migrations/000004_character_additional.up.sql +++ /dev/null @@ -1,14 +0,0 @@ -BEGIN; - -ALTER TABLE characters - ADD COLUMN decomyset bytea, - ADD COLUMN hunternavi bytea, - ADD COLUMN otomoairou bytea, - ADD COLUMN partner bytea, - ADD COLUMN platebox bytea, - ADD COLUMN platedata bytea, - ADD COLUMN platemyset bytea, - ADD COLUMN trophy bytea, - ADD COLUMN rengokudata bytea; - -END; diff --git a/migrations/000005_quests.down.sql b/migrations/000005_quests.down.sql deleted file mode 100644 index 60eff8f22..000000000 --- a/migrations/000005_quests.down.sql +++ /dev/null @@ -1,5 +0,0 @@ -BEGIN; - -DROP TABLE IF EXISTS questlists; - -END; \ No newline at end of file diff --git a/migrations/000005_quests.up.sql b/migrations/000005_quests.up.sql deleted file mode 100644 index 26a02f8d1..000000000 --- a/migrations/000005_quests.up.sql +++ /dev/null @@ -1,8 +0,0 @@ -BEGIN; - -CREATE TABLE questlists ( - ind int NOT NULL PRIMARY KEY, - questlist bytea -); - -END; \ No newline at end of file diff --git a/migrations/000006_mercenary.down.sql b/migrations/000006_mercenary.down.sql deleted file mode 100644 index 54cbd957b..000000000 --- a/migrations/000006_mercenary.down.sql +++ /dev/null @@ -1,6 +0,0 @@ -BEGIN; - -ALTER TABLE characters - DROP COLUMN savemercenary; - -END; \ No newline at end of file diff --git a/migrations/000006_mercenary.up.sql b/migrations/000006_mercenary.up.sql deleted file mode 100644 index af025dff0..000000000 --- a/migrations/000006_mercenary.up.sql +++ /dev/null @@ -1,6 +0,0 @@ -BEGIN; - -ALTER TABLE characters - ADD COLUMN savemercenary bytea; - -END; \ No newline at end of file diff --git a/migrations/000007_guilds.down.sql b/migrations/000007_guilds.down.sql deleted file mode 100644 index 344ab854e..000000000 --- a/migrations/000007_guilds.down.sql +++ /dev/null @@ -1,6 +0,0 @@ -BEGIN; - -DROP TABLE guild_characters; -DROP TABLE guilds; - -END; \ No newline at end of file diff --git a/migrations/000007_guilds.up.sql b/migrations/000007_guilds.up.sql deleted file mode 100644 index e327c7db3..000000000 --- a/migrations/000007_guilds.up.sql +++ /dev/null @@ -1,22 +0,0 @@ -BEGIN; - -CREATE TABLE guilds -( - id serial NOT NULL PRIMARY KEY, - name varchar(24), - created_at timestamp DEFAULT NOW(), - leader_id int NOT NULL, - main_motto varchar(255) DEFAULT '' -); - -CREATE TABLE guild_characters -( - id serial NOT NULL PRIMARY KEY, - guild_id bigint REFERENCES guilds (id), - character_id bigint REFERENCES characters (id), - joined_at timestamp DEFAULT NOW() -); - -CREATE UNIQUE INDEX guild_character_unique_index ON guild_characters (character_id); - -END; \ No newline at end of file diff --git a/migrations/000008_guild_additional.down.sql b/migrations/000008_guild_additional.down.sql deleted file mode 100644 index 9252a98f2..000000000 --- a/migrations/000008_guild_additional.down.sql +++ /dev/null @@ -1,11 +0,0 @@ -BEGIN; - -ALTER TABLE guilds - DROP COLUMN rp; - -ALTER TABLE guild_characters - DROP COLUMN is_applicant, - DROP COLUMN is_sub_leader, - DROP COLUMN order_index; - -END; \ No newline at end of file diff --git a/migrations/000008_guild_additional.up.sql b/migrations/000008_guild_additional.up.sql deleted file mode 100644 index 7e16984d3..000000000 --- a/migrations/000008_guild_additional.up.sql +++ /dev/null @@ -1,11 +0,0 @@ -BEGIN; - -ALTER TABLE guild_characters - ADD COLUMN is_applicant bool NOT NULL DEFAULT false, - ADD COLUMN is_sub_leader bool NOT NULL DEFAULT false, - ADD COLUMN order_index int NOT NULL DEFAULT 1; - -ALTER TABLE guilds - ADD COLUMN rp uint16 NOT NULL DEFAULT 0; - -END; diff --git a/migrations/000009_character_social.down.sql b/migrations/000009_character_social.down.sql deleted file mode 100644 index 243ea6712..000000000 --- a/migrations/000009_character_social.down.sql +++ /dev/null @@ -1,6 +0,0 @@ -BEGIN; - -ALTER TABLE characters - DROP COLUMN restrict_guild_scout; - -END; \ No newline at end of file diff --git a/migrations/000009_character_social.up.sql b/migrations/000009_character_social.up.sql deleted file mode 100644 index f94ce2043..000000000 --- a/migrations/000009_character_social.up.sql +++ /dev/null @@ -1,6 +0,0 @@ -BEGIN; - -ALTER TABLE characters - ADD COLUMN restrict_guild_scout bool NOT NULL DEFAULT false; - -END; \ No newline at end of file diff --git a/migrations/000010_guild_comments_festival_hall.down.sql b/migrations/000010_guild_comments_festival_hall.down.sql deleted file mode 100644 index c86d1ee5e..000000000 --- a/migrations/000010_guild_comments_festival_hall.down.sql +++ /dev/null @@ -1,10 +0,0 @@ -BEGIN; - -ALTER TABLE guilds - DROP COLUMN comment, - DROP COLUMN festival_colour, - DROP COLUMN guild_hall; - -DROP TYPE festival_colour; - -END; \ No newline at end of file diff --git a/migrations/000010_guild_comments_festival_hall.up.sql b/migrations/000010_guild_comments_festival_hall.up.sql deleted file mode 100644 index 3caec4149..000000000 --- a/migrations/000010_guild_comments_festival_hall.up.sql +++ /dev/null @@ -1,11 +0,0 @@ -BEGIN; - -CREATE TYPE festival_colour AS ENUM ('none', 'red', 'blue'); - -ALTER TABLE guilds - ADD COLUMN comment varchar(255) NOT NULL DEFAULT '', - ADD COLUMN festival_colour festival_colour DEFAULT 'none', - ADD COLUMN guild_hall int DEFAULT 0; - - -END; \ No newline at end of file diff --git a/migrations/000011_character_points_minidata.down.sql b/migrations/000011_character_points_minidata.down.sql deleted file mode 100644 index 557608be9..000000000 --- a/migrations/000011_character_points_minidata.down.sql +++ /dev/null @@ -1,24 +0,0 @@ -BEGIN; - -ALTER TABLE characters - DROP COLUMN minidata, - DROP COLUMN gacha_trial, - DROP COLUMN gacha_prem, - DROP COLUMN gacha_items, - DROP COLUMN daily_time, - DROP COLUMN frontier_points, - DROP COLUMN netcafe_points, - DROP COLUMN house_info, - DROP COLUMN login_boost, - DROP COLUMN skin_hist, - DROP COLUMN gcp; - -DROP TABLE fpoint_items; -DROP TABLE gacha_shop; -DROP TABLE gacha_shop_items; -DROP TABLE lucky_box_state; -DROP TABLE stepup_state; -DROP TABLE normal_shop_items; -DROP TABLE shop_item_state; - -END; \ No newline at end of file diff --git a/migrations/000011_character_points_minidata.up.sql b/migrations/000011_character_points_minidata.up.sql deleted file mode 100644 index 29baa0790..000000000 --- a/migrations/000011_character_points_minidata.up.sql +++ /dev/null @@ -1,100 +0,0 @@ -BEGIN; -ALTER TABLE characters - ADD COLUMN minidata bytea, - ADD COLUMN gacha_trial int, - ADD COLUMN gacha_prem int, - ADD COLUMN gacha_items bytea, - ADD COLUMN daily_time timestamp, - ADD COLUMN frontier_points int, - ADD COLUMN netcafe_points int, - ADD COLUMN house_info bytea, - ADD COLUMN login_boost bytea, - ADD COLUMN skin_hist bytea, - ADD COLUMN kouryou_point int, - ADD COLUMN gcp int; - -CREATE TABLE fpoint_items -( - hash int, - itemType uint8, - itemID uint16, - quant uint16, - itemValue uint16, - tradeType uint8 -); - - -CREATE TABLE gacha_shop -( - hash bigint, - reqGR int, - reqHR int, - gachaName varchar(255), - gachaLink0 varchar(255), - gachaLink1 varchar(255), - gachaLink2 varchar(255), - extraIcon int, - gachaType int, - hideFlag bool -); - -CREATE TABLE gacha_shop_items -( - shophash int, - entryType uint8, - itemhash int UNIQUE NOT NULL, - currType uint8, - currNumber uint16, - currQuant uint16, - percentage uint16, - rarityIcon uint8, - rollsCount uint8, - itemCount uint8, - dailyLimit uint8, - itemType int[], - itemId int[], - quantity int[] -); - -CREATE TABLE lucky_box_state -( - char_id bigint REFERENCES characters (id), - shophash int UNIQUE NOT NULL, - used_itemhash int[] -); - - -CREATE TABLE stepup_state -( - char_id bigint REFERENCES characters (id), - shophash int UNIQUE NOT NULL, - step_progression int, - step_time timestamp -); - -CREATE TABLE normal_shop_items -( - shoptype int, - shopid int, - itemhash int UNIQUE NOT NULL, - itemID uint16, - Points uint16, - TradeQuantity uint16, - rankReqLow uint16, - rankReqHigh uint16, - rankReqG uint16, - storeLevelReq uint16, - maximumQuantity uint16, - boughtQuantity uint16, - roadFloorsRequired uint16, - weeklyFatalisKills uint16 -); - -CREATE TABLE shop_item_state -( - char_id bigint REFERENCES characters (id), - itemhash int UNIQUE NOT NULL, - usedquantity int -); - -END; \ No newline at end of file diff --git a/migrations/000012_loginboost_etc.down.sql b/migrations/000012_loginboost_etc.down.sql deleted file mode 100644 index 13102b0b0..000000000 --- a/migrations/000012_loginboost_etc.down.sql +++ /dev/null @@ -1,5 +0,0 @@ -BEGIN; - -DROP TABLE login_boost_state; - -END; \ No newline at end of file diff --git a/migrations/000012_loginboost_etc.up.sql b/migrations/000012_loginboost_etc.up.sql deleted file mode 100644 index 4feff1790..000000000 --- a/migrations/000012_loginboost_etc.up.sql +++ /dev/null @@ -1,13 +0,0 @@ -BEGIN; - -CREATE TABLE login_boost_state -( - char_id bigint REFERENCES characters (id), - week_req uint8, - week_count uint8, - available bool, - end_time int, - CONSTRAINT id_week UNIQUE(char_id, week_req) -); - -END; \ No newline at end of file diff --git a/migrations/000013_shop_constraints.down.sql b/migrations/000013_shop_constraints.down.sql deleted file mode 100644 index 7b5ac1242..000000000 --- a/migrations/000013_shop_constraints.down.sql +++ /dev/null @@ -1,12 +0,0 @@ -BEGIN; - -ALTER TABLE shop_item_state DROP CONSTRAINT shop_item_state_id_itemhash; -ALTER TABLE shop_item_state ADD CONSTRAINT shop_item_state_itemhash_key UNIQUE (itemhash); - -ALTER TABLE stepup_state DROP CONSTRAINT stepup_state_id_shophash; -ALTER TABLE stepup_state ADD CONSTRAINT stepup_state_shophash_key UNIQUE (shophash); - -ALTER TABLE lucky_box_state DROP CONSTRAINT lucky_box_state_id_shophash; -ALTER TABLE lucky_box_state ADD CONSTRAINT lucky_box_state_shophash_key UNIQUE (shophash); - -END; \ No newline at end of file diff --git a/migrations/000013_shop_constraints.up.sql b/migrations/000013_shop_constraints.up.sql deleted file mode 100644 index a48e81ac2..000000000 --- a/migrations/000013_shop_constraints.up.sql +++ /dev/null @@ -1,12 +0,0 @@ -BEGIN; - -ALTER TABLE shop_item_state DROP CONSTRAINT shop_item_state_itemhash_key; -ALTER TABLE shop_item_state ADD CONSTRAINT shop_item_state_id_itemhash UNIQUE(char_id, itemhash); - -ALTER TABLE stepup_state DROP CONSTRAINT stepup_state_shophash_key; -ALTER TABLE stepup_state ADD CONSTRAINT stepup_state_id_shophash UNIQUE(char_id, shophash); - -ALTER TABLE lucky_box_state DROP CONSTRAINT lucky_box_state_shophash_key; -ALTER TABLE lucky_box_state ADD CONSTRAINT lucky_box_state_id_shophash UNIQUE(char_id, shophash); - -END; \ No newline at end of file diff --git a/migrations/000014_guild_flags_applications.down.sql b/migrations/000014_guild_flags_applications.down.sql deleted file mode 100644 index 6cfe86288..000000000 --- a/migrations/000014_guild_flags_applications.down.sql +++ /dev/null @@ -1,18 +0,0 @@ -BEGIN; -ALTER TABLE guild_characters - RENAME COLUMN avoid_leadership TO is_sub_leader; - -ALTER TABLE guild_characters - ADD COLUMN is_applicant bool NOT NULL DEFAULT false; - -ALTER TABLE guilds - DROP COLUMN icon, - ALTER COLUMN main_motto TYPE varchar USING '', - DROP COLUMN sub_motto; - -ALTER TABLE guilds - ALTER COLUMN main_motto SET DEFAULT ''; - -DROP TABLE guild_applications; -DROP TYPE guild_application_type; -END; \ No newline at end of file diff --git a/migrations/000014_guild_flags_applications.up.sql b/migrations/000014_guild_flags_applications.up.sql deleted file mode 100644 index 4bc09668a..000000000 --- a/migrations/000014_guild_flags_applications.up.sql +++ /dev/null @@ -1,30 +0,0 @@ -BEGIN; -CREATE TYPE guild_application_type AS ENUM ('applied', 'invited'); - -CREATE TABLE guild_applications -( - id serial NOT NULL PRIMARY KEY, - guild_id int NOT NULL REFERENCES guilds (id), - character_id int NOT NULL REFERENCES characters (id), - actor_id int NOT NULL REFERENCES characters (id), - application_type guild_application_type NOT NULL, - created_at timestamp NOT NULL DEFAULT now(), - CONSTRAINT guild_application_character_id UNIQUE (guild_id, character_id) -); - -CREATE INDEX guild_application_type_index ON guild_applications (application_type); - -ALTER TABLE guild_characters - DROP COLUMN is_applicant; - -ALTER TABLE guild_characters - RENAME COLUMN is_sub_leader TO avoid_leadership; - -ALTER TABLE guilds - ALTER COLUMN main_motto SET DEFAULT 0; - -ALTER TABLE guilds - ADD COLUMN icon bytea, - ADD COLUMN sub_motto int DEFAULT 0, - ALTER COLUMN main_motto TYPE int USING 0; -END; \ No newline at end of file diff --git a/migrations/000015_mail.down.sql b/migrations/000015_mail.down.sql deleted file mode 100644 index 8ed5b834f..000000000 --- a/migrations/000015_mail.down.sql +++ /dev/null @@ -1,3 +0,0 @@ -BEGIN; -DROP TABLE mail; -END; \ No newline at end of file diff --git a/migrations/000015_mail.up.sql b/migrations/000015_mail.up.sql deleted file mode 100644 index ba0dc4edd..000000000 --- a/migrations/000015_mail.up.sql +++ /dev/null @@ -1,19 +0,0 @@ -BEGIN; -CREATE TABLE mail -( - id SERIAL NOT NULL PRIMARY KEY, - sender_id INT NOT NULL REFERENCES characters (id), - recipient_id INT NOT NULL REFERENCES characters (id), - subject VARCHAR NOT NULL DEFAULT '', - body VARCHAR NOT NULL DEFAULT '', - read BOOL NOT NULL DEFAULT FALSE, - attached_item_received BOOL NOT NULL DEFAULT FALSE, - attached_item INT DEFAULT NULL, - attached_item_amount INT NOT NULL DEFAULT 1, - is_guild_invite BOOL NOT NULL DEFAULT FALSE, - created_at TIMESTAMP NOT NULL DEFAULT NOW(), - deleted BOOL NOT NULL DEFAULT FALSE -); - -CREATE INDEX mail_recipient_deleted_created_id_index ON mail (recipient_id, deleted, created_at DESC, id DESC); -END; \ No newline at end of file diff --git a/migrations/000016_server.down.sql b/migrations/000016_server.down.sql deleted file mode 100644 index a5fb2d6b0..000000000 --- a/migrations/000016_server.down.sql +++ /dev/null @@ -1,3 +0,0 @@ -BEGIN; -DROP TABLE public.servers; -END; \ No newline at end of file diff --git a/migrations/000016_server.up.sql b/migrations/000016_server.up.sql deleted file mode 100644 index f6a7798e7..000000000 --- a/migrations/000016_server.up.sql +++ /dev/null @@ -1,21 +0,0 @@ -BEGIN; --- Table: public.servers - --- DROP TABLE IF EXISTS public.servers; - -CREATE TABLE IF NOT EXISTS public.servers -( - server_id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ), - server_name text COLLATE pg_catalog."default", - season integer, - current_players integer, - event_id integer, - event_expiration integer, - CONSTRAINT servers_pkey PRIMARY KEY (server_id) -) - -TABLESPACE pg_default; - -ALTER TABLE IF EXISTS public.servers - OWNER to postgres; -END; \ No newline at end of file diff --git a/migrations/000017_account.down.sql b/migrations/000017_account.down.sql deleted file mode 100644 index c52957af0..000000000 --- a/migrations/000017_account.down.sql +++ /dev/null @@ -1,6 +0,0 @@ -BEGIN; -DROP TABLE public.account_ban; -DROP TABLE public.account_history; -DROP TABLE public.account_moderation; -DROP TABLE public.account_sub; -END; \ No newline at end of file diff --git a/migrations/000017_account.up.sql b/migrations/000017_account.up.sql deleted file mode 100644 index f636d619f..000000000 --- a/migrations/000017_account.up.sql +++ /dev/null @@ -1,45 +0,0 @@ -BEGIN; - -CREATE TABLE IF NOT EXISTS public.account_ban -( - user_id integer NOT NULL, - title text COLLATE pg_catalog."default", - reason text COLLATE pg_catalog."default", - date text COLLATE pg_catalog."default", - pass_origin text COLLATE pg_catalog."default", - pass_block text COLLATE pg_catalog."default", - CONSTRAINT ban_pkey PRIMARY KEY (user_id) -); - -CREATE TABLE IF NOT EXISTS public.account_history -( - report_id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ), - user_id integer, - title text COLLATE pg_catalog."default", - reason text COLLATE pg_catalog."default", - date date, - CONSTRAINT account_history_pkey PRIMARY KEY (report_id) -); - -CREATE TABLE IF NOT EXISTS public.account_moderation -( - id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ), - username text COLLATE pg_catalog."default", - password text COLLATE pg_catalog."default", - type text COLLATE pg_catalog."default", - CONSTRAINT account_moderation_pkey PRIMARY KEY (id) -); - -CREATE TABLE IF NOT EXISTS public.account_sub -( - id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ), - discord_id text COLLATE pg_catalog."default", - erupe_account text COLLATE pg_catalog."default", - erupe_password text COLLATE pg_catalog."default", - date_inscription date, - country text COLLATE pg_catalog."default", - presentation text COLLATE pg_catalog."default", - CONSTRAINT account_auth_pkey PRIMARY KEY (id) -); - -END; \ No newline at end of file diff --git a/migrations/000018_event_week.down.sql b/migrations/000018_event_week.down.sql deleted file mode 100644 index 756df1f22..000000000 --- a/migrations/000018_event_week.down.sql +++ /dev/null @@ -1,3 +0,0 @@ -BEGIN; -DROP TABLE public.event_week; -END; \ No newline at end of file diff --git a/migrations/000018_event_week.up.sql b/migrations/000018_event_week.up.sql deleted file mode 100644 index f536871f2..000000000 --- a/migrations/000018_event_week.up.sql +++ /dev/null @@ -1,11 +0,0 @@ -BEGIN; - -CREATE TABLE IF NOT EXISTS public.event_week -( - id integer NOT NULL, - event_id integer NOT NULL, - date_expiration integer NOT NULL, - CONSTRAINT event_week_pkey PRIMARY KEY (id) -); - -END; \ No newline at end of file diff --git a/migrations/000019_gook.down.sql b/migrations/000019_gook.down.sql deleted file mode 100644 index a4b544e9a..000000000 --- a/migrations/000019_gook.down.sql +++ /dev/null @@ -1,3 +0,0 @@ -BEGIN; -DROP TABLE public.gook; -END; \ No newline at end of file diff --git a/migrations/000019_gook.up.sql b/migrations/000019_gook.up.sql deleted file mode 100644 index fe5c051c0..000000000 --- a/migrations/000019_gook.up.sql +++ /dev/null @@ -1,20 +0,0 @@ -BEGIN; - -CREATE TABLE IF NOT EXISTS public.gook -( - id serial NOT NULL PRIMARY KEY, - gook0 bytea, - gook1 bytea, - gook2 bytea, - gook3 bytea, - gook4 bytea, - gook5 bytea, - gook0status boolean, - gook1status boolean, - gook2status boolean, - gook3status boolean, - gook4status boolean, - gook5status boolean -); - -END; \ No newline at end of file diff --git a/migrations/000020_history.down.sql b/migrations/000020_history.down.sql deleted file mode 100644 index 623bd53c8..000000000 --- a/migrations/000020_history.down.sql +++ /dev/null @@ -1,3 +0,0 @@ -BEGIN; -DROP TABLE public.history; -END; \ No newline at end of file diff --git a/migrations/000020_history.up.sql b/migrations/000020_history.up.sql deleted file mode 100644 index 96d6b36c8..000000000 --- a/migrations/000020_history.up.sql +++ /dev/null @@ -1,13 +0,0 @@ -BEGIN; - -CREATE TABLE IF NOT EXISTS public.history -( - user_id integer, - admin_id integer, - report_id integer NOT NULL, - title text COLLATE pg_catalog."default", - reason text COLLATE pg_catalog."default", - CONSTRAINT history_pkey PRIMARY KEY (report_id) -); - -END; \ No newline at end of file From 82eeb792296e4749f841422f6c89702eaa07a433 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 27 Oct 2022 13:04:52 +1100 Subject: [PATCH 83/95] crash client on missing quest file --- server/channelserver/handlers_quest.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 5d662b06c..1ef5e9ea3 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -28,7 +28,10 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { // Read the scenario file. data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("scenarios/%s.bin", filename))) if err != nil { - panic(err) + s.logger.Error(fmt.Sprintf("Failed to open file: %s/scenarios/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename)) + // This will crash the game. + doAckBufSucceed(s, pkt.AckHandle, data) + return } doAckBufSucceed(s, pkt.AckHandle, data) } else { @@ -48,7 +51,10 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { // Get quest file. data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))) if err != nil { - s.logger.Fatal(fmt.Sprintf("Failed to open quest file: quests/%s.bin", pkt.Filename)) + s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename)) + // This will crash the game. + doAckBufSucceed(s, pkt.AckHandle, data) + return } doAckBufSucceed(s, pkt.AckHandle, data) } From e943b54df40f7aab212e818af4942737638174af Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 27 Oct 2022 13:11:56 +1100 Subject: [PATCH 84/95] add patch server option --- config.json | 2 ++ config/config.go | 2 ++ server/signserver/dsgn_resp.go | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index f0feb790e..b94d6c868 100644 --- a/config.json +++ b/config.json @@ -5,6 +5,8 @@ "FeaturedWeapons": 2, "DevMode": true, "DevModeOptions": { + "PatchServerManifest": "", + "PatchServerFile": "", "AutoCreateAccount": true, "EnableLauncherServer": false, "HideLoginNotice": false, diff --git a/config/config.go b/config/config.go index 48da57344..5d21c2240 100644 --- a/config/config.go +++ b/config/config.go @@ -30,6 +30,8 @@ type Config struct { // DevModeOptions holds various debug/temporary options for use while developing Erupe. type DevModeOptions struct { + PatchServerManifest string // Manifest patch server override + PatchServerFile string // File patch server override AutoCreateAccount bool // Automatically create accounts if they don't exist HideLoginNotice bool // Hide the Erupe notice on login LoginNotice string // MHFML string of the login notice displayed diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go index cbad6405c..3966af8d6 100644 --- a/server/signserver/dsgn_resp.go +++ b/server/signserver/dsgn_resp.go @@ -42,13 +42,23 @@ func (s *Session) makeSignInResp(uid int) []byte { bf := byteframe.NewByteFrame() - bf.WriteUint8(1) // resp_code - bf.WriteUint8(0) // file/patch server count + bf.WriteUint8(1) // resp_code + if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.PatchServerManifest != "" && s.server.erupeConfig.DevModeOptions.PatchServerFile != "" { + bf.WriteUint8(2) + } else { + bf.WriteUint8(0) + } bf.WriteUint8(1) // entrance server count bf.WriteUint8(uint8(len(chars))) // character count bf.WriteUint32(0xFFFFFFFF) // login_token_number bf.WriteBytes([]byte(token)) // login_token bf.WriteUint32(uint32(time.Now().Unix())) // current time + if s.server.erupeConfig.DevMode { + if s.server.erupeConfig.DevModeOptions.PatchServerManifest != "" && s.server.erupeConfig.DevModeOptions.PatchServerFile != "" { + ps.Uint8(bf, s.server.erupeConfig.DevModeOptions.PatchServerManifest, false) + ps.Uint8(bf, s.server.erupeConfig.DevModeOptions.PatchServerFile, false) + } + } ps.Uint8(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.Host, s.server.erupeConfig.Entrance.Port), false) lastPlayed := uint32(0) From 702471577bf6b001f85e8e6dab2b99d5d96cbc99 Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 28 Oct 2022 08:54:45 +1100 Subject: [PATCH 85/95] print correct missing scenario path --- server/channelserver/handlers_quest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 1ef5e9ea3..0be884c2b 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -28,7 +28,7 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { // Read the scenario file. data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("scenarios/%s.bin", filename))) if err != nil { - s.logger.Error(fmt.Sprintf("Failed to open file: %s/scenarios/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename)) + s.logger.Error(fmt.Sprintf("Failed to open file: %s/scenarios/%s.bin", s.server.erupeConfig.BinPath, filename)) // This will crash the game. doAckBufSucceed(s, pkt.AckHandle, data) return From a99939eba13a6b0f6c187d212a989e424cb355d0 Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 28 Oct 2022 09:11:14 +1100 Subject: [PATCH 86/95] set default featured weapons to 1 --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index b94d6c868..4bc422280 100644 --- a/config.json +++ b/config.json @@ -2,7 +2,7 @@ "Host": "127.0.0.1", "BinPath": "bin", "DisableSoftCrash": false, - "FeaturedWeapons": 2, + "FeaturedWeapons": 1, "DevMode": true, "DevModeOptions": { "PatchServerManifest": "", From da1a48ee2c3bcb59209d223bbeb72bcd23d4b3c9 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 30 Oct 2022 09:59:07 +1100 Subject: [PATCH 87/95] gitkeep files for quest folders --- bin/quests/.gitkeep | 0 bin/scenarios/.gitkeep | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 bin/quests/.gitkeep create mode 100644 bin/scenarios/.gitkeep diff --git a/bin/quests/.gitkeep b/bin/quests/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/bin/scenarios/.gitkeep b/bin/scenarios/.gitkeep new file mode 100644 index 000000000..e69de29bb From bac4e70be41a9fec114872eaa03dda71523ca6df Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 30 Oct 2022 11:44:22 +1100 Subject: [PATCH 88/95] course enumeration concept --- network/mhfpacket/msg_sys_update_right.go | 38 ++++++++++++++++++++--- server/channelserver/handlers.go | 25 +++++---------- server/channelserver/sys_session.go | 12 ++++++- 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/network/mhfpacket/msg_sys_update_right.go b/network/mhfpacket/msg_sys_update_right.go index b343dd0c4..9d1dfc52a 100644 --- a/network/mhfpacket/msg_sys_update_right.go +++ b/network/mhfpacket/msg_sys_update_right.go @@ -2,6 +2,7 @@ package mhfpacket import ( "errors" + ps "erupe-ce/common/pascalstring" "erupe-ce/common/byteframe" "erupe-ce/network" @@ -34,6 +35,12 @@ type ClientRight struct { Timestamp uint32 } +type Course struct { + Name string + ID uint16 + Value uint32 +} + // MsgSysUpdateRight represents the MSG_SYS_UPDATE_RIGHT type MsgSysUpdateRight struct { ClientRespAckHandle uint32 // If non-0, requests the client to send back a MSG_SYS_ACK packet with this value. @@ -63,9 +70,32 @@ func (m *MsgSysUpdateRight) Build(bf *byteframe.ByteFrame, ctx *clientctx.Client bf.WriteUint16(v.Unk0) bf.WriteUint32(v.Timestamp) } - - bf.WriteUint16(m.UnkSize) // String of upto 0x800 bytes, update client login token / password in the game's launcherstate struct. - //bf.WriteBytes(m.UpdatedClientLoginToken) - + ps.Uint16(bf, "", false) // update client login token / password in the game's launcherstate struct return nil } + +// GetCourseStruct returns a slice of Course(s) from a rights integer +func GetCourseStruct(rights uint32) []Course { + var courses = []Course{ + {"Trial", 1, 0x00000002}, + {"HunterLife", 2, 0x00000004}, + {"ExtraA", 3, 0x00000008}, + {"ExtraB", 4, 0x00000010}, + {"Mobile", 5, 0x00000020}, + {"Premium", 6, 0x00000040}, + {"Pallone", 7, 0x00000080}, + {"Assist", 8, 0x00000100}, // Legend + {"Netcafe", 9, 0x00000200}, + {"Hiden", 10, 0x00000400}, // Secret + {"HunterSupport", 11, 0x00000800}, // Royal + {"NetcafeBoost", 12, 0x00001000}, + } + var resp []Course + for _, course := range courses { + if rights-course.Value < 0x80000000 { + resp = append(resp, course) + rights -= course.Value + } + } + return resp +} diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index be2d37794..94c32d8bd 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -6,7 +6,6 @@ import ( "erupe-ce/common/stringsupport" "fmt" "io" - "math" "net" "strings" "time" @@ -74,26 +73,18 @@ func doAckSimpleFail(s *Session, ackHandle uint32, data []byte) { } func updateRights(s *Session) { - s.rights = uint32(0x0E) - s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&s.rights) + rightsInt := uint32(0x0E) + s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt) - rights := make([]mhfpacket.ClientRight, 0) - tempRights := s.rights - for i := 30; i > 0; i-- { - right := uint32(math.Pow(2, float64(i))) - if tempRights-right < 0x80000000 { - if i == 1 { - continue - } - rights = append(rights, mhfpacket.ClientRight{ID: uint16(i), Timestamp: 0x70DB59F0}) - tempRights -= right - } + courses := mhfpacket.GetCourseStruct(rightsInt) + rights := []mhfpacket.ClientRight{{1, 0, 0}} + for _, course := range courses { + rights = append(rights, mhfpacket.ClientRight{ID: course.ID, Timestamp: 0x70DB59F0}) } - rights = append(rights, mhfpacket.ClientRight{ID: 1, Timestamp: 0}) update := &mhfpacket.MsgSysUpdateRight{ ClientRespAckHandle: 0, - Bitfield: s.rights, + Bitfield: rightsInt, Rights: rights, UnkSize: 0, } @@ -224,7 +215,7 @@ func logoutPlayer(s *Session) { timePlayed += sessionTime var rpGained int - if s.rights >= 0x40000000 { // N Course + if s.CourseExists("Netcafe") { rpGained = timePlayed / 900 timePlayed = timePlayed % 900 } else { diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index 90430f4da..2d3ce9bd1 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net" + "strings" "sync" "time" @@ -43,7 +44,7 @@ type Session struct { charID uint32 logKey []byte sessionStart int64 - rights uint32 + courses []mhfpacket.Course token string kqf []byte kqfOverride bool @@ -268,3 +269,12 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien fmt.Printf("Data [%d bytes]:\n(Too long!)\n\n", len(data)) } } + +func (s *Session) CourseExists(name string) bool { + for _, course := range s.courses { + if strings.ToLower(name) == strings.ToLower(course.Name) { + return true + } + } + return false +} From 31bac7bd68bbe32b8919a2f78c2bfce535c61112 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 30 Oct 2022 15:03:12 +1100 Subject: [PATCH 89/95] initial course command --- config.json | 14 +++++++ config/config.go | 6 +++ network/mhfpacket/msg_sys_update_right.go | 40 +++++++++++--------- server/channelserver/handlers.go | 6 +-- server/channelserver/handlers_cast_binary.go | 37 ++++++++++++++++++ server/channelserver/sys_session.go | 6 ++- 6 files changed, 85 insertions(+), 24 deletions(-) diff --git a/config.json b/config.json index 4bc422280..a29d7aff4 100644 --- a/config.json +++ b/config.json @@ -55,8 +55,22 @@ "Name": "KeyQuest", "Enabled": false, "Prefix": "!kqf" + }, { + "Name": "Course", + "Enabled": true, + "Prefix": "!course" } ], + "Courses": [ + {"Name": "HunterLife", "Enabled": true}, + {"Name": "ExtraA", "Enabled": true}, + {"Name": "Premium", "Enabled": true}, + {"Name": "Assist", "Enabled": true}, + {"Name": "Netcafe", "Enabled": true}, + {"Name": "Hiden", "Enabled": true}, + {"Name": "HunterSupport", "Enabled": true}, + {"Name": "NetcafeBoost", "Enabled": true} + ], "Database": { "Host": "localhost", "Port": 5432, diff --git a/config/config.go b/config/config.go index 5d21c2240..f15d71276 100644 --- a/config/config.go +++ b/config/config.go @@ -70,6 +70,12 @@ type Command struct { Prefix string } +// Courses is an array of enabled courses +type Courses struct { + Name string + Enabled bool +} + // Database holds the postgres database config. type Database struct { Host string diff --git a/network/mhfpacket/msg_sys_update_right.go b/network/mhfpacket/msg_sys_update_right.go index 9d1dfc52a..cf4232573 100644 --- a/network/mhfpacket/msg_sys_update_right.go +++ b/network/mhfpacket/msg_sys_update_right.go @@ -36,9 +36,9 @@ type ClientRight struct { } type Course struct { - Name string - ID uint16 - Value uint32 + Aliases []string + ID uint16 + Value uint32 } // MsgSysUpdateRight represents the MSG_SYS_UPDATE_RIGHT @@ -74,24 +74,28 @@ func (m *MsgSysUpdateRight) Build(bf *byteframe.ByteFrame, ctx *clientctx.Client return nil } +func Courses() []Course { + var courses = []Course{ + {[]string{"Trial", "TL"}, 1, 0x00000002}, + {[]string{"HunterLife", "HL"}, 2, 0x00000004}, + {[]string{"ExtraA", "Extra", "EX"}, 3, 0x00000008}, + {[]string{"ExtraB"}, 4, 0x00000010}, + {[]string{"Mobile"}, 5, 0x00000020}, + {[]string{"Premium"}, 6, 0x00000040}, + {[]string{"Pallone"}, 7, 0x00000080}, + {[]string{"Assist", "Legend", "Rasta"}, 8, 0x00000100}, // Legend + {[]string{"Netcafe", "N", "Cafe"}, 9, 0x00000200}, + {[]string{"Hiden", "Secret"}, 10, 0x00000400}, // Secret + {[]string{"HunterSupport", "HunterAid", "Support", "Royal", "Aid"}, 11, 0x00000800}, // Royal + {[]string{"NetcafeBoost", "NBoost", "Boost"}, 12, 0x00001000}, + } + return courses +} + // GetCourseStruct returns a slice of Course(s) from a rights integer func GetCourseStruct(rights uint32) []Course { - var courses = []Course{ - {"Trial", 1, 0x00000002}, - {"HunterLife", 2, 0x00000004}, - {"ExtraA", 3, 0x00000008}, - {"ExtraB", 4, 0x00000010}, - {"Mobile", 5, 0x00000020}, - {"Premium", 6, 0x00000040}, - {"Pallone", 7, 0x00000080}, - {"Assist", 8, 0x00000100}, // Legend - {"Netcafe", 9, 0x00000200}, - {"Hiden", 10, 0x00000400}, // Secret - {"HunterSupport", 11, 0x00000800}, // Royal - {"NetcafeBoost", 12, 0x00001000}, - } var resp []Course - for _, course := range courses { + for _, course := range Courses() { if rights-course.Value < 0x80000000 { resp = append(resp, course) rights -= course.Value diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 94c32d8bd..19547fec8 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -75,13 +75,11 @@ func doAckSimpleFail(s *Session, ackHandle uint32, data []byte) { func updateRights(s *Session) { rightsInt := uint32(0x0E) s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt) - - courses := mhfpacket.GetCourseStruct(rightsInt) + s.courses = mhfpacket.GetCourseStruct(rightsInt) rights := []mhfpacket.ClientRight{{1, 0, 0}} - for _, course := range courses { + for _, course := range s.courses { rights = append(rights, mhfpacket.ClientRight{ID: course.ID, Timestamp: 0x70DB59F0}) } - update := &mhfpacket.MsgSysUpdateRight{ ClientRespAckHandle: 0, Bitfield: rightsInt, diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index fb0d0331f..05206ad0a 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -311,6 +311,43 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { } } + if strings.HasPrefix(chatMessage.Message, commands["Course"].Prefix) { + if commands["Course"].Enabled { + var name string + n, err := fmt.Sscanf(chatMessage.Message, "!course %s", &name) + if err != nil || n != 1 { + sendServerChatMessage(s, "Error in command. Format: !course ") + } else { + name = strings.ToLower(name) + for _, course := range mhfpacket.Courses() { + for _, alias := range course.Aliases { + if strings.ToLower(name) == strings.ToLower(alias) { + if s.CourseExists(name) { + existingIndex := -1 + for i, course := range s.courses { + for _, alias := range course.Aliases { + if strings.ToLower(name) == strings.ToLower(alias) { + existingIndex = i + } + } + } + if existingIndex >= 0 { + s.courses = append(s.courses[:existingIndex], s.courses[existingIndex+1:]...) + sendServerChatMessage(s, fmt.Sprintf(`%s Course disabled.`, course.Aliases[0])) + } + } else { + s.courses = append(s.courses, course) + sendServerChatMessage(s, fmt.Sprintf(`%s Course enabled.`, course.Aliases[0])) + } + } + } + } + } + } else { + sendDisabledCommandMessage(s, commands["Course"]) + } + } + if strings.HasPrefix(chatMessage.Message, commands["Raviente"].Prefix) { if commands["Raviente"].Enabled { if getRaviSemaphore(s) != "" { diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index 2d3ce9bd1..e7c626d09 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -272,8 +272,10 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien func (s *Session) CourseExists(name string) bool { for _, course := range s.courses { - if strings.ToLower(name) == strings.ToLower(course.Name) { - return true + for _, alias := range course.Aliases { + if strings.ToLower(name) == strings.ToLower(alias) { + return true + } } } return false From 8afec7a7dfef7bcd09a201e56cd9f03148817fe8 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 30 Oct 2022 16:42:10 +1100 Subject: [PATCH 90/95] upgrade to go 1.19 --- go.mod | 33 ++++++++++++++++++++++++--------- go.sum | 26 +++++++++----------------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index f4e7f1033..1d7f83e7b 100644 --- a/go.mod +++ b/go.mod @@ -1,23 +1,38 @@ module erupe-ce -go 1.16 +go 1.19 require ( github.com/bwmarrin/discordgo v0.23.2 - github.com/golang/mock v1.6.0 // indirect github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 - github.com/gorilla/websocket v1.4.2 // indirect github.com/jmoiron/sqlx v1.3.4 github.com/lib/pq v1.10.4 - github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/sachaos/lottery v0.0.0-20180520074626-61949d99bd96 github.com/spf13/viper v1.8.1 + go.uber.org/zap v1.18.1 + golang.org/x/crypto v0.1.0 + golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f + golang.org/x/text v0.4.0 +) + +require ( + github.com/felixge/httpsnoop v1.0.1 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/pelletier/go-toml v1.9.3 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.2.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.7.0 // indirect - go.uber.org/zap v1.18.1 - golang.org/x/crypto v0.0.0-20211202192323-5770296d904e - golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect - golang.org/x/text v0.3.7 - golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect + golang.org/x/sys v0.1.0 // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 1e7747306..ca2bd44a9 100644 --- a/go.sum +++ b/go.sum @@ -261,7 +261,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= @@ -291,9 +290,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8= -golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -304,6 +302,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f h1:Al51T6tzvuh3oiwX11vex3QgJ2XTedFPGmbEVh8cdoc= +golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -330,7 +330,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -367,8 +366,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -432,12 +429,9 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -446,9 +440,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -505,8 +498,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg= -golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 676bb736bf6ec3773486bf83609a493e1ce775d0 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 30 Oct 2022 16:43:58 +1100 Subject: [PATCH 91/95] lockable courses via config --- config/config.go | 5 ++-- server/channelserver/handlers.go | 2 +- server/channelserver/handlers_cast_binary.go | 29 ++++++++++++-------- server/channelserver/sys_session.go | 24 ++++++---------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/config/config.go b/config/config.go index f15d71276..d2804b9fc 100644 --- a/config/config.go +++ b/config/config.go @@ -21,6 +21,7 @@ type Config struct { DevModeOptions DevModeOptions Discord Discord Commands []Command + Courses []Course Database Database Launcher Launcher Sign Sign @@ -70,8 +71,8 @@ type Command struct { Prefix string } -// Courses is an array of enabled courses -type Courses struct { +// Course represents a course within MHF +type Course struct { Name string Enabled bool } diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 19547fec8..851f4c1df 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -213,7 +213,7 @@ func logoutPlayer(s *Session) { timePlayed += sessionTime var rpGained int - if s.CourseExists("Netcafe") { + if s.FindCourse("Netcafe").Value != 0 { rpGained = timePlayed / 900 timePlayed = timePlayed % 900 } else { diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 05206ad0a..9372d1572 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -7,6 +7,7 @@ import ( "erupe-ce/network/binpacket" "erupe-ce/network/mhfpacket" "fmt" + "golang.org/x/exp/slices" "math" "math/rand" "strings" @@ -322,22 +323,26 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { for _, course := range mhfpacket.Courses() { for _, alias := range course.Aliases { if strings.ToLower(name) == strings.ToLower(alias) { - if s.CourseExists(name) { - existingIndex := -1 - for i, course := range s.courses { - for _, alias := range course.Aliases { - if strings.ToLower(name) == strings.ToLower(alias) { - existingIndex = i + if slices.Contains(s.server.erupeConfig.Courses, config.Course{Name: course.Aliases[0], Enabled: true}) { + if s.FindCourse(name).Value != 0 { + existingIndex := -1 + for i, course := range s.courses { + for _, alias := range course.Aliases { + if strings.ToLower(name) == strings.ToLower(alias) { + existingIndex = i + } } } - } - if existingIndex >= 0 { - s.courses = append(s.courses[:existingIndex], s.courses[existingIndex+1:]...) - sendServerChatMessage(s, fmt.Sprintf(`%s Course disabled.`, course.Aliases[0])) + if existingIndex >= 0 { + s.courses = append(s.courses[:existingIndex], s.courses[existingIndex+1:]...) + sendServerChatMessage(s, fmt.Sprintf(`%s Course disabled.`, course.Aliases[0])) + } + } else { + s.courses = append(s.courses, course) + sendServerChatMessage(s, fmt.Sprintf(`%s Course enabled.`, course.Aliases[0])) } } else { - s.courses = append(s.courses, course) - sendServerChatMessage(s, fmt.Sprintf(`%s Course enabled.`, course.Aliases[0])) + sendServerChatMessage(s, fmt.Sprintf(`%s Course is locked.`, course.Aliases[0])) } } } diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index e7c626d09..4e7429bf8 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -12,12 +12,10 @@ import ( "erupe-ce/common/byteframe" "erupe-ce/common/stringstack" - "erupe-ce/common/stringsupport" "erupe-ce/network" "erupe-ce/network/clientctx" "erupe-ce/network/mhfpacket" "go.uber.org/zap" - "golang.org/x/text/encoding/japanese" ) type packet struct { @@ -69,16 +67,12 @@ type Session struct { // NewSession creates a new Session type. func NewSession(server *Server, conn net.Conn) *Session { s := &Session{ - logger: server.logger.Named(conn.RemoteAddr().String()), - server: server, - rawConn: conn, - cryptConn: network.NewCryptConn(conn), - sendPackets: make(chan packet, 20), - clientContext: &clientctx.ClientContext{ - StrConv: &stringsupport.StringConverter{ - Encoding: japanese.ShiftJIS, - }, - }, + logger: server.logger.Named(conn.RemoteAddr().String()), + server: server, + rawConn: conn, + cryptConn: network.NewCryptConn(conn), + sendPackets: make(chan packet, 20), + clientContext: &clientctx.ClientContext{}, sessionStart: Time_Current_Adjusted().Unix(), stageMoveStack: stringstack.New(), } @@ -270,13 +264,13 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien } } -func (s *Session) CourseExists(name string) bool { +func (s *Session) FindCourse(name string) mhfpacket.Course { for _, course := range s.courses { for _, alias := range course.Aliases { if strings.ToLower(name) == strings.ToLower(alias) { - return true + return course } } } - return false + return mhfpacket.Course{} } From 4390617ccfd90570d5da3cc06dd06784e6be5fa8 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 30 Oct 2022 23:18:53 +1100 Subject: [PATCH 92/95] update rights integer via struct --- network/mhfpacket/msg_sys_update_right.go | 7 ++++++- server/channelserver/handlers.go | 2 +- server/channelserver/handlers_cast_binary.go | 20 +++++++++++++------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/network/mhfpacket/msg_sys_update_right.go b/network/mhfpacket/msg_sys_update_right.go index cf4232573..0702a5b3e 100644 --- a/network/mhfpacket/msg_sys_update_right.go +++ b/network/mhfpacket/msg_sys_update_right.go @@ -3,6 +3,7 @@ package mhfpacket import ( "errors" ps "erupe-ce/common/pascalstring" + "golang.org/x/exp/slices" "erupe-ce/common/byteframe" "erupe-ce/network" @@ -95,7 +96,11 @@ func Courses() []Course { // GetCourseStruct returns a slice of Course(s) from a rights integer func GetCourseStruct(rights uint32) []Course { var resp []Course - for _, course := range Courses() { + s := Courses() + slices.SortStableFunc(s, func(i, j Course) bool { + return i.ID > j.ID + }) + for _, course := range s { if rights-course.Value < 0x80000000 { resp = append(resp, course) rights -= course.Value diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 851f4c1df..edd2dc33c 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -213,7 +213,7 @@ func logoutPlayer(s *Session) { timePlayed += sessionTime var rpGained int - if s.FindCourse("Netcafe").Value != 0 { + if s.FindCourse("Netcafe").ID != 0 { rpGained = timePlayed / 900 timePlayed = timePlayed % 900 } else { diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 9372d1572..64666d9af 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -325,22 +325,28 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { if strings.ToLower(name) == strings.ToLower(alias) { if slices.Contains(s.server.erupeConfig.Courses, config.Course{Name: course.Aliases[0], Enabled: true}) { if s.FindCourse(name).Value != 0 { - existingIndex := -1 - for i, course := range s.courses { - for _, alias := range course.Aliases { + ei := slices.IndexFunc(s.courses, func(c mhfpacket.Course) bool { + for _, alias := range c.Aliases { if strings.ToLower(name) == strings.ToLower(alias) { - existingIndex = i + return true } } - } - if existingIndex >= 0 { - s.courses = append(s.courses[:existingIndex], s.courses[existingIndex+1:]...) + return false + }) + if ei != -1 { + s.courses = append(s.courses[:ei], s.courses[ei+1:]...) sendServerChatMessage(s, fmt.Sprintf(`%s Course disabled.`, course.Aliases[0])) } } else { s.courses = append(s.courses, course) sendServerChatMessage(s, fmt.Sprintf(`%s Course enabled.`, course.Aliases[0])) } + var newInt uint32 + for _, course := range s.courses { + newInt += course.Value + } + s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", newInt, s.charID) + updateRights(s) } else { sendServerChatMessage(s, fmt.Sprintf(`%s Course is locked.`, course.Aliases[0])) } From fe413b897ac10ff6b8ffca42963b3e2781cd7ad8 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 30 Oct 2022 23:19:52 +1100 Subject: [PATCH 93/95] update default config --- config.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config.json b/config.json index a29d7aff4..31ecd8416 100644 --- a/config.json +++ b/config.json @@ -37,7 +37,7 @@ "Commands": [ { "Name": "Rights", - "Enabled": true, + "Enabled": false, "Prefix": "!rights" }, { "Name": "Raviente", @@ -65,11 +65,11 @@ {"Name": "HunterLife", "Enabled": true}, {"Name": "ExtraA", "Enabled": true}, {"Name": "Premium", "Enabled": true}, - {"Name": "Assist", "Enabled": true}, - {"Name": "Netcafe", "Enabled": true}, - {"Name": "Hiden", "Enabled": true}, - {"Name": "HunterSupport", "Enabled": true}, - {"Name": "NetcafeBoost", "Enabled": true} + {"Name": "Assist", "Enabled": false}, + {"Name": "Netcafe", "Enabled": false}, + {"Name": "Hiden", "Enabled": false}, + {"Name": "HunterSupport", "Enabled": false}, + {"Name": "NetcafeBoost", "Enabled": false} ], "Database": { "Host": "localhost", From 4a7cde77ea359fade37d27599ee8584740ef0bc5 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 1 Nov 2022 10:49:28 +1100 Subject: [PATCH 94/95] fix nil StrConv on save --- server/channelserver/handlers_data.go | 4 ++-- server/channelserver/sys_session.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index b641d3973..28521d10d 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -2,6 +2,7 @@ package channelserver import ( "encoding/hex" + "erupe-ce/common/bfutil" "erupe-ce/common/stringsupport" "fmt" "io" @@ -9,7 +10,6 @@ import ( "os" "path/filepath" - "erupe-ce/common/bfutil" "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" "erupe-ce/server/channelserver/compression/deltacomp" @@ -49,7 +49,7 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { characterSaveData.Save(s) s.logger.Info("Wrote recompressed savedata back to DB.") - characterSaveData.Name = s.clientContext.StrConv.MustDecode(bfutil.UpToNull(characterSaveData.decompSave[88:100])) + characterSaveData.Name = stringsupport.SJISToUTF8(bfutil.UpToNull(characterSaveData.decompSave[88:100])) _, err = s.server.db.Exec("UPDATE characters SET name=$1 WHERE id=$2", characterSaveData.Name, s.charID) if err != nil { s.logger.Fatal("Failed to update character name in db", zap.Error(err)) diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index 4e7429bf8..39a96f40f 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -72,7 +72,7 @@ func NewSession(server *Server, conn net.Conn) *Session { rawConn: conn, cryptConn: network.NewCryptConn(conn), sendPackets: make(chan packet, 20), - clientContext: &clientctx.ClientContext{}, + clientContext: &clientctx.ClientContext{}, // Unused sessionStart: Time_Current_Adjusted().Unix(), stageMoveStack: stringstack.New(), } From 8326e22d9f666e13770cc52c411c7a29c1b102e2 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 1 Nov 2022 10:54:30 +1100 Subject: [PATCH 95/95] empty ClientContext struct --- network/clientctx/clientcontext.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/network/clientctx/clientcontext.go b/network/clientctx/clientcontext.go index 0f890f6d7..021ae3299 100644 --- a/network/clientctx/clientcontext.go +++ b/network/clientctx/clientcontext.go @@ -1,8 +1,4 @@ package clientctx -import "erupe-ce/common/stringsupport" - // ClientContext holds contextual data required for packet encoding/decoding. -type ClientContext struct { - StrConv *stringsupport.StringConverter -} +type ClientContext struct{} // Unused