diff --git a/.gitignore b/.gitignore index fc2d952ed..04a9d02ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ www/tw/ www/jp/ -bin_resp/ -custom_entrance_server_resp.bin -dec_bin8_data_dump.bin -entrance_resp_bin8_encrypted.bin -tw_server_list_resp.bin \ No newline at end of file +bin/quests/*.bin +bin/scenarios/*.bin +bin/debug/*.bin +savedata/ +Erupe.exe \ No newline at end of file diff --git a/README.md b/README.md index 65f41de81..944f1fcb0 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,61 @@ # Erupe ## WARNING -This project is in its infancy and currently doesn't do anything worth noting. Additionally, it has no documentation, no support, and cannot be used without binary resources that are not in the repo. +This project is in its infancy and currently doesn't do anything worth noting. Additionally, it has no documentation and no support. + +This project is soley developed in my spare time for the educational experience of making a server emulator, which I haven't done before. Expectations regarding functionally and code quality should be set accordingly. # General info -Originally based on the TW version, but (slowly) transitioning to JP. +Currently allows a JP MHF client (with GameGuard removed) to: +* Login and register an account (registration is automatic if account doesn't exist) +* Create a character +* Get ingame to the main city +* See other players walk around (Names and character data are not correct, placeholders are in use) +* Use (local) chat. # Installation 1. Clone the repo with `git clone https://github.com/Andoryuuta/Erupe.git` 2. Install PostgreSQL 3. Launch psql shell, `CREATE DATABASE erupe;`. - 4. Setup database with golang-migrate: -``` -> go get -tags 'postgres' -u github.com/golang-migrate/migrate/cmd/migrate -> set POSTGRESQL_URL=postgres://postgres:password@localhost:5432/erupe?sslmode=disable + Windows: + ``` + > go get -tags 'postgres' -u github.com/golang-migrate/migrate/cmd/migrate -> migrate -database %POSTGRESQL_URL% -path migrations up -``` + > set POSTGRESQL_URL=postgres://postgres:password@localhost:5432/erupe?sslmode=disable -5. Open psql shell and manually insert an account into the users table. + > cd erupe -6. Manually extract the binary response from a pcap, strip the header, and decrypt the ~50 packets that are used in `./channelserver/session.go`, and place them in `./bin_resp/{OPCODE}_resp.bin`. (**These are not included in the repo**) + > migrate -database %POSTGRESQL_URL% -path migrations up + ``` + Linux: + ``` + > go get -tags 'postgres' -u github.com/golang-migrate/migrate/cmd/migrate + > export POSTGRESQL_URL=postgres://postgres:password@localhost:5432/erupe?sslmode=disable + + > cd erupe + + > migrate -database $POSTGRESQL_URL -path migrations up + ``` + + (Replacing `postgres:password` with your postgres username and password) + +5. Edit the config.json + Namely: + * Update the database username and password + * Update the `host_ip` and `ip` fields (there are multiple) to your external IP if you are hosting for multiple clients. ## Launcher -Erupe now ships with a rudimentary custom launcher, so you don't need to obtain the original TW/JP files to simply get ingame. However, it does still support using the original files if you choose to. To set this up, place a copy of the original launcher html/js/css in `./www/tw/`, and `/www/jp/` for the TW and JP files respectively. +Erupe ships with a rudimentary custom launcher, so you don't need to obtain the original TW/JP files to simply get ingame. However, it does still support using the original files if you choose to. To set this up, place a copy of the original launcher html/js/css in `./www/tw/`, and `/www/jp/` for the TW and JP files respectively. Then, modify the the `/launcher/js/launcher.js` file as such: * Find the call to `startUpdateProcess();` in a case statement and replace it with `finishUpdateProcess();`. (This disables the file check and updating) * (JP ONLY): replace all uses of "https://" with "http://" in the file. -Finally, edit `main.go` and change: - -`go serveLauncherHTML(":80", false)` - -to: - -`go serveLauncherHTML(":80", true)` +Finally, edit the config.json and set `UseOriginalLauncherFiles` to `true` under the launcher settings. # Usage ### Note: If you are switching to/from the custom launcher html, you will have to clear your IE cache @ `C:\Users\\AppData\Local\Microsoft\Windows\INetCache`. diff --git a/bin/quests/__PLACE_YOUR_QUEST_.bin_FILES_HERE__.txt b/bin/quests/__PLACE_YOUR_QUEST_.bin_FILES_HERE__.txt new file mode 100644 index 000000000..aa01a92bf --- /dev/null +++ b/bin/quests/__PLACE_YOUR_QUEST_.bin_FILES_HERE__.txt @@ -0,0 +1,2 @@ +place your quest .bin files here +e.g. 22031d0.bin \ No newline at end of file diff --git a/channelserver/channel_server.go b/channelserver/channel_server.go deleted file mode 100644 index d7aa386d8..000000000 --- a/channelserver/channel_server.go +++ /dev/null @@ -1,84 +0,0 @@ -package channelserver - -import ( - "database/sql" - "fmt" - "net" - "sync" -) - -// Config struct allows configuring the server. -type Config struct { - DB *sql.DB - ListenAddr string -} - -// Server is a MHF channel server. -type Server struct { - sync.Mutex - acceptConns chan net.Conn - deleteConns chan net.Conn - sessions map[net.Conn]*Session - db *sql.DB - listenAddr string - listener net.Listener // Listener that is created when Server.Start is called. -} - -// NewServer creates a new Server type. -func NewServer(config *Config) *Server { - s := &Server{ - acceptConns: make(chan net.Conn), - deleteConns: make(chan net.Conn), - sessions: make(map[net.Conn]*Session), - db: config.DB, - listenAddr: config.ListenAddr, - } - return s -} - -// Start starts the server in a new goroutine. -func (s *Server) Start() error { - l, err := net.Listen("tcp", s.listenAddr) - if err != nil { - return err - } - s.listener = l - //defer l.Close() - - go s.acceptClients() - go s.manageSessions() - - return nil -} - -func (s *Server) acceptClients() { - for { - conn, err := s.listener.Accept() - if err != nil { - // TODO(Andoryuuta): Implement shutdown logic to end this goroutine cleanly here. - fmt.Println(err) - continue - } - s.acceptConns <- conn - } -} - -func (s *Server) manageSessions() { - for { - select { - case newConn := <-s.acceptConns: - session := NewSession(s, newConn) - - s.Lock() - s.sessions[newConn] = session - s.Unlock() - - session.Start() - - case delConn := <-s.deleteConns: - s.Lock() - delete(s.sessions, delConn) - s.Unlock() - } - } -} diff --git a/channelserver/handlers.go b/channelserver/handlers.go deleted file mode 100644 index de185f0f1..000000000 --- a/channelserver/handlers.go +++ /dev/null @@ -1,910 +0,0 @@ -package channelserver - -import ( - "github.com/Andoryuuta/Erupe/network" - "github.com/Andoryuuta/Erupe/network/mhfpacket" - "github.com/Andoryuuta/byteframe" -) - -func handleMsgHead(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve01(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve02(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve03(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve04(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve05(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve06(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve07(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysAddObject(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysDelObject(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysDispObject(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysHideObject(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve0C(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve0D(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve0E(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysExtendThreshold(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysEnd(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysNop(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysAck(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysTerminalLog(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgSysLogin) - - bf := byteframe.NewByteFrame() - bf.WriteUint16(uint16(network.MSG_SYS_ACK)) - bf.WriteUint32(pkt.AckHandle) - bf.WriteUint64(0x000000005E00B9C2) // Timestamp? - s.cryptConn.SendPacket(bf.Data()) -} - -func handleMsgSysLogout(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysSetStatus(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysPing(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgSysPing) - - bf := byteframe.NewByteFrame() - bf.WriteUint16(uint16(network.MSG_SYS_ACK)) - ack := mhfpacket.MsgSysAck{ - AckHandle: pkt.AckHandle, - Unk0: 0, - Unk1: 0, - } - ack.Build(bf) - s.cryptConn.SendPacket(bf.Data()) -} - -func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysHideClient(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysTime(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgSysTime) - - bf := byteframe.NewByteFrame() - bf.WriteUint16(uint16(network.MSG_SYS_TIME)) - resp := mhfpacket.MsgSysTime{ - Unk0: pkt.Unk0, - Timestamp: pkt.Timestamp, - } - resp.Build(bf) - s.cryptConn.SendPacket(bf.Data()) -} - -func handleMsgSysCastedBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysIssueLogkey(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysRecordLog(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysEcho(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysMoveStage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysLeaveStage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysLockStage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysUnreserveStage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysSetStagePass(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysWaitStageBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysSetStageBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysGetStageBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysEnumerateClient(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysCreateMutex(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysCreateOpenMutex(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysDeleteMutex(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysOpenMutex(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysCloseMutex(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReleaseSemaphore(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysLockGlobalSema(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysUnlockGlobalSema(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysLoadRegister(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysNotifyRegister(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysCreateObject(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysDeleteObject(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysPositionObject(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysRotateObject(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysDuplicateObject(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysGetObjectBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysGetObjectOwner(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysUpdateObjectBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysCleanupObject(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve4A(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve4B(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve4C(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve4D(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve4E(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve4F(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysInsertUser(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysDeleteUser(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysGetUserBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysNotifyUserBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve55(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve56(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve57(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysUpdateRight(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysAuthQuery(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysAuthData(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysAuthTerminal(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve5C(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysRightsReload(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve5E(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve5F(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfListMember(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfOprMember(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetDistDescription(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSendMail(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReleaseEvent(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve71(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve72(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve73(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve74(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve75(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve76(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve77(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve78(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve79(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve7A(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve7B(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve7C(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgCaExchangeItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve7E(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPresentBox(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfServerCommand(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfShutClient(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAnnounce(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetLoginwindow(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysTransBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysCollectBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysGetState(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysSerialize(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysEnumlobby(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysEnumuser(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysInfokyserver(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetCaUniqueID(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetCaAchievement(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCaravanMyScore(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCaravanMyRank(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCreateGuild(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfOperateGuildMember(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateGuild(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfArrangeGuildMember(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfApplyCampaign(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfTransferItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfMercenaryHuntdata(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEntryRookieGuild(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateEvent(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumeratePrice(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateOrder(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetExtraInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateWarehouse(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateWarehouse(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateGuildItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateUnionItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateUnionItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCreateJoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateGuildIcon(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEntryFesta(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfChargeFesta(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireFesta(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfVoteFesta(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireCafeItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateCafepoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetCogInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCheckMonthlyItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireMonthlyItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCreateMercenary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSaveMercenary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReadMercenaryM(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfContractMercenary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateMercenaryLog(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfInfoTournament(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEntryTournament(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnterTournamentQuest(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireTournament(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetAchievement(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfResetAchievement(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAddAchievement(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPaymentAchievement(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfDisplayedAchievement(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetBbsSnsStatus(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfApplyBbsArticle(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateEtcPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateInvGuild(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfOperationInvGuild(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfStampcardPrize(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUnreserveSrg(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadPlateData(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadPlateBox(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReadGuildcard(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateGuildcard(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReadBeatLevel(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateBeatLevel(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReadBeatLevelAllRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReadBeatLevelMyRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReadLastWeekBeatRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcceptReadReward(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetAdditionalBeatReward(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetFixedSeibatuRankingTable(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetBbsUserStatus(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfKickExportForce(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetBreakSeibatuLevelReward(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetWeeklySeibatuRankingReward(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadPartner(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSavePartner(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGuildMissionList(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGuildMissionRecord(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAddGuildMissionCount(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetGuildMissionTarget(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCancelGuildMissionTarget(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadOtomoAirou(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateAiroulist(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireGuildTresure(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfOperateGuildTresureReport(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReserve010F(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfRegistGuildAdventure(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireGuildAdventure(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfChargeGuildAdventure(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfRegistSpabiTime(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGuildWeeklyBonusMaster(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGuildWeeklyBonusActiveCount(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAddGuildWeeklyBonusExceptionalUser(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetEarthValue(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfDebugPostValue(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetPaperData(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetNotice(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostNotice(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetBoostTime(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostBoostTime(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetBoostTimeLimit(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostBoostTimeLimit(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetRandFromTable(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetCafeDurationBonusInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReceiveCafeDurationBonus(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostCafeDurationBonusReceived(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGachaPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUseGachaPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfExchangeFpoint2Item(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfExchangeItem2Fpoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetFpointExchangeList(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetStepupStatus(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPlayFreeGacha(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetTinyBin(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostTinyBin(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGuildTargetMemberNum(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetBoostRight(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfStartBoostTime(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostBoostTimeQuestReturn(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfResetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetRyoudama(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostRyoudama(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfCancelGuildScout(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetDailyMissionMaster(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetGachaPlayHistory(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetCaAchievementHist(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetCaAchievementHist(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetKijuInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetKiju(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAddUdPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdMyPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdTotalPointInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdBonusQuestInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdSelectedColorInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdMonsterPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdDailyPresentList(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdNormaPresentList(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdRankingRewardList(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireUdItem(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetRewardSong(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUseRewardSong(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAddRewardSongCount(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdMyRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAcquireMonthlyReward(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdGuildMapInfo(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGenerateUdGuildMap(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdTacticsPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAddUdTacticsPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdTacticsRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdTacticsRewardList(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdTacticsLog(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdTacticsFollower(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetUdTacticsFollower(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdShopCoin(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUseUdShopCoin(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetLobbyCrowd(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve180(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfAddKouryouPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetKouryouPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfExchangeKouryouPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdTacticsBonusQuest(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdTacticsFirstQuestBonus(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetUdTacticsRemainingPoint(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve188(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadPlateMyset(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSavePlateMyset(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve18B(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve18E(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve18F(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetTrendWeapon(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateUseTrendWeaponLog(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve192(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve193(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve194(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSaveRengokuData(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadRengokuData(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetRengokuBinary(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfGetRengokuRankingRank(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfGetRengokuRankingRank) - - bf := byteframe.NewByteFrame() - bf.WriteUint16(uint16(network.MSG_SYS_ACK)) - bf.WriteUint32(pkt.AckHandle) - bf.WriteBytes([]byte{0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) - s.cryptConn.SendPacket(bf.Data()) -} - -func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve19B(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfSaveMezfesData(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfLoadMezfesData(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve19E(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve19F(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfUpdateForceGuildRank(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgMhfResetTitle(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve202(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve203(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve204(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve205(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve206(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve207(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve208(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve209(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve20A(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve20B(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve20C(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve20D(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve20E(s *Session, p mhfpacket.MHFPacket) {} - -func handleMsgSysReserve20F(s *Session, p mhfpacket.MHFPacket) {} diff --git a/channelserver/session.go b/channelserver/session.go deleted file mode 100644 index 0e95d1b14..000000000 --- a/channelserver/session.go +++ /dev/null @@ -1,433 +0,0 @@ -package channelserver - -import ( - "encoding/hex" - "fmt" - "io/ioutil" - "net" - "sync" - - "github.com/Andoryuuta/Erupe/network" - "github.com/Andoryuuta/Erupe/network/mhfpacket" - "github.com/Andoryuuta/byteframe" -) - -// Session holds state for the channel server connection. -type Session struct { - sync.Mutex - server *Server - rawConn net.Conn - cryptConn *network.CryptConn -} - -// NewSession creates a new Session type. -func NewSession(server *Server, conn net.Conn) *Session { - s := &Session{ - server: server, - rawConn: conn, - cryptConn: network.NewCryptConn(conn), - } - return s -} - -// Start starts the session packet read&handle loop. -func (s *Session) Start() { - go func() { - fmt.Println("Channel server got connection!") - // Unlike the sign and entrance server, - // the client DOES NOT initalize the channel connection with 8 NULL bytes. - - for { - pkt, err := s.cryptConn.ReadPacket() - if err != nil { - fmt.Println(err) - fmt.Println("Error on channel server readpacket") - return - } - - s.handlePacketGroup(pkt) - - } - }() -} - -var loadDataCount int -var getPaperDataCount int - -func (s *Session) handlePacketGroup(pktGroup []byte) { - defer func() { - if r := recover(); r != nil { - fmt.Println("Recovered from panic.") - } - }() - - bf := byteframe.NewByteFrameFromBytes(pktGroup) - opcode := network.PacketID(bf.ReadUint16()) - - if opcode != network.MSG_SYS_END { - fmt.Printf("Opcode: %s\n", opcode) - fmt.Printf("Data:\n%s\n", hex.Dump(pktGroup)) - } - - switch opcode { - case network.MSG_MHF_ENUMERATE_EVENT: - fallthrough - case network.MSG_MHF_ENUMERATE_QUEST: - fallthrough - case network.MSG_MHF_ENUMERATE_RANKING: - fallthrough - case network.MSG_MHF_READ_MERCENARY_W: - fallthrough - case network.MSG_MHF_GET_ETC_POINTS: - fallthrough - case network.MSG_MHF_READ_GUILDCARD: - fallthrough - case network.MSG_MHF_READ_BEAT_LEVEL: - fallthrough - case network.MSG_MHF_GET_EARTH_STATUS: - fallthrough - case network.MSG_MHF_GET_EARTH_VALUE: - fallthrough - case network.MSG_MHF_GET_WEEKLY_SCHEDULE: - fallthrough - case network.MSG_MHF_LIST_MEMBER: - fallthrough - case network.MSG_MHF_LOAD_PLATE_DATA: - fallthrough - case network.MSG_MHF_LOAD_PLATE_BOX: - fallthrough - case network.MSG_MHF_LOAD_FAVORITE_QUEST: - fallthrough - case network.MSG_MHF_LOAD_PARTNER: - fallthrough - case network.MSG_MHF_GET_TOWER_INFO: - fallthrough - case network.MSG_MHF_LOAD_OTOMO_AIROU: - fallthrough - case network.MSG_MHF_LOAD_DECO_MYSET: - fallthrough - case network.MSG_MHF_LOAD_HUNTER_NAVI: - fallthrough - case network.MSG_MHF_GET_UD_SCHEDULE: - fallthrough - case network.MSG_MHF_GET_UD_INFO: - fallthrough - case network.MSG_MHF_GET_UD_MONSTER_POINT: - fallthrough - case network.MSG_MHF_GET_RAND_FROM_TABLE: - fallthrough - case network.MSG_MHF_ACQUIRE_MONTHLY_REWARD: - fallthrough - case network.MSG_MHF_LOAD_PLATE_MYSET: - fallthrough - case network.MSG_MHF_LOAD_RENGOKU_DATA: - fallthrough - case network.MSG_MHF_ENUMERATE_SHOP: - fallthrough - case network.MSG_MHF_LOAD_SCENARIO_DATA: - fallthrough - case network.MSG_MHF_GET_BOOST_TIME_LIMIT: - fallthrough - case network.MSG_MHF_GET_BOOST_RIGHT: - fallthrough - case network.MSG_MHF_GET_REWARD_SONG: - fallthrough - case network.MSG_MHF_GET_GACHA_POINT: - fallthrough - case network.MSG_MHF_GET_KOURYOU_POINT: - fallthrough - case network.MSG_MHF_GET_ENHANCED_MINIDATA: - - ackHandle := bf.ReadUint32() - - data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp.bin", opcode.String())) - if err != nil { - panic(err) - } - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_ACK)) - bfw.WriteUint32(ackHandle) - bfw.WriteBytes(data) - s.cryptConn.SendPacket(bfw.Data()) - - case network.MSG_MHF_INFO_FESTA: - ackHandle := bf.ReadUint32() - _ = bf.ReadUint32() - - data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp.bin", opcode.String())) - if err != nil { - panic(err) - } - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_ACK)) - bfw.WriteUint32(ackHandle) - bfw.WriteBytes(data) - s.cryptConn.SendPacket(bfw.Data()) - - case network.MSG_MHF_LOADDATA: - ackHandle := bf.ReadUint32() - - data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp%d.bin", opcode.String(), loadDataCount)) - if err != nil { - panic(err) - } - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_ACK)) - bfw.WriteUint32(ackHandle) - bfw.WriteBytes(data) - s.cryptConn.SendPacket(bfw.Data()) - - loadDataCount++ - if loadDataCount > 1 { - loadDataCount = 0 - } - case network.MSG_MHF_GET_PAPER_DATA: - ackHandle := bf.ReadUint32() - - data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp%d.bin", opcode.String(), getPaperDataCount)) - if err != nil { - panic(err) - } - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_ACK)) - bfw.WriteUint32(ackHandle) - bfw.WriteBytes(data) - s.cryptConn.SendPacket(bfw.Data()) - - getPaperDataCount++ - if getPaperDataCount > 7 { - getPaperDataCount = 0 - } - default: - // Get the packet parser and handler for this opcode. - mhfPkt := mhfpacket.FromOpcode(opcode) - if mhfPkt == nil { - fmt.Println("Got opcode which we don't know how to parse, can't parse anymore for this group") - return - } - - // Parse and handle the packet - mhfPkt.Parse(bf) - handlerTable[opcode](s, mhfPkt) - break - } - - // If there is more data on the stream that the .Parse method didn't read, then read another packet off it. - remainingData := bf.DataFromCurrent() - if len(remainingData) >= 2 && (opcode == network.MSG_SYS_TIME || opcode == network.MSG_MHF_INFO_FESTA || opcode == network.MSG_SYS_EXTEND_THRESHOLD) { - s.handlePacketGroup(remainingData) - } -} - -/* -func handlePacket(cc *network.CryptConn, pkt []byte) { - defer func() { - if r := recover(); r != nil { - fmt.Println("Recovered from panic.") - } - }() - - bf := byteframe.NewByteFrameFromBytes(pkt) - opcode := network.PacketID(bf.ReadUint16()) - - if opcode == network.MSG_SYS_EXTEND_THRESHOLD { - opcode = network.PacketID(bf.ReadUint16()) - } - - fmt.Printf("Opcode: %s\n", opcode) - switch opcode { - case network.MSG_SYS_PING: - ackHandle := bf.ReadUint32() - _ = bf.ReadUint16() - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_ACK)) - bfw.WriteUint32(ackHandle) - bfw.WriteUint32(0) - bfw.WriteUint32(0) - cc.SendPacket(bfw.Data()) - case network.MSG_SYS_TIME: - _ = bf.ReadUint8() - timestamp := bf.ReadUint32() // unix timestamp, e.g. 1577105879 - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_TIME)) - bfw.WriteUint8(0) - bfw.WriteUint32(timestamp) - cc.SendPacket(bfw.Data()) - case network.MSG_SYS_LOGIN: - ackHandle := bf.ReadUint32() - charID0 := bf.ReadUint32() - loginTokenNumber := bf.ReadUint32() - hardcodedZero0 := bf.ReadUint16() - requestVersion := bf.ReadUint16() - charID1 := bf.ReadUint32() - hardcodedZero1 := bf.ReadUint16() - loginTokenLength := bf.ReadUint16() // hardcoded to 0x11 - loginTokenString := bf.ReadBytes(17) - - _ = ackHandle - _ = charID0 - _ = loginTokenNumber - _ = hardcodedZero0 - _ = requestVersion - _ = charID1 - _ = hardcodedZero1 - _ = loginTokenLength - _ = loginTokenString - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_ACK)) - bfw.WriteUint32(ackHandle) - bfw.WriteUint64(0x000000005E00B9C2) // Timestamp? - cc.SendPacket(bfw.Data()) - - case network.MSG_MHF_ENUMERATE_EVENT: - fallthrough - case network.MSG_MHF_ENUMERATE_QUEST: - fallthrough - case network.MSG_MHF_ENUMERATE_RANKING: - fallthrough - case network.MSG_MHF_READ_MERCENARY_W: - fallthrough - case network.MSG_MHF_GET_ETC_POINTS: - fallthrough - case network.MSG_MHF_READ_GUILDCARD: - fallthrough - case network.MSG_MHF_READ_BEAT_LEVEL: - fallthrough - case network.MSG_MHF_GET_EARTH_STATUS: - fallthrough - case network.MSG_MHF_GET_EARTH_VALUE: - fallthrough - case network.MSG_MHF_GET_WEEKLY_SCHEDULE: - fallthrough - case network.MSG_MHF_LIST_MEMBER: - fallthrough - case network.MSG_MHF_LOAD_PLATE_DATA: - fallthrough - case network.MSG_MHF_LOAD_PLATE_BOX: - fallthrough - case network.MSG_MHF_LOAD_FAVORITE_QUEST: - fallthrough - case network.MSG_MHF_LOAD_PARTNER: - fallthrough - case network.MSG_MHF_GET_TOWER_INFO: - fallthrough - case network.MSG_MHF_LOAD_OTOMO_AIROU: - fallthrough - case network.MSG_MHF_LOAD_DECO_MYSET: - fallthrough - case network.MSG_MHF_LOAD_HUNTER_NAVI: - fallthrough - case network.MSG_MHF_GET_UD_SCHEDULE: - fallthrough - case network.MSG_MHF_GET_UD_INFO: - fallthrough - case network.MSG_MHF_GET_UD_MONSTER_POINT: - fallthrough - case network.MSG_MHF_GET_RAND_FROM_TABLE: - fallthrough - case network.MSG_MHF_ACQUIRE_MONTHLY_REWARD: - fallthrough - case network.MSG_MHF_GET_RENGOKU_RANKING_RANK: - fallthrough - case network.MSG_MHF_LOAD_PLATE_MYSET: - fallthrough - case network.MSG_MHF_LOAD_RENGOKU_DATA: - fallthrough - case network.MSG_MHF_ENUMERATE_SHOP: - fallthrough - case network.MSG_MHF_LOAD_SCENARIO_DATA: - fallthrough - case network.MSG_MHF_GET_BOOST_TIME_LIMIT: - fallthrough - case network.MSG_MHF_GET_BOOST_RIGHT: - fallthrough - case network.MSG_MHF_GET_REWARD_SONG: - fallthrough - case network.MSG_MHF_GET_GACHA_POINT: - fallthrough - case network.MSG_MHF_GET_KOURYOU_POINT: - fallthrough - case network.MSG_MHF_GET_ENHANCED_MINIDATA: - - ackHandle := bf.ReadUint32() - - data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp.bin", opcode.String())) - if err != nil { - panic(err) - } - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_ACK)) - bfw.WriteUint32(ackHandle) - bfw.WriteBytes(data) - cc.SendPacket(bfw.Data()) - - case network.MSG_MHF_INFO_FESTA: - ackHandle := bf.ReadUint32() - _ = bf.ReadUint32() - - data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp.bin", opcode.String())) - if err != nil { - panic(err) - } - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_ACK)) - bfw.WriteUint32(ackHandle) - bfw.WriteBytes(data) - cc.SendPacket(bfw.Data()) - - case network.MSG_MHF_LOADDATA: - ackHandle := bf.ReadUint32() - - data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp%d.bin", opcode.String(), loadDataCount)) - if err != nil { - panic(err) - } - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_ACK)) - bfw.WriteUint32(ackHandle) - bfw.WriteBytes(data) - cc.SendPacket(bfw.Data()) - - loadDataCount++ - if loadDataCount > 1 { - loadDataCount = 0 - } - case network.MSG_MHF_GET_PAPER_DATA: - ackHandle := bf.ReadUint32() - - data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp%d.bin", opcode.String(), getPaperDataCount)) - if err != nil { - panic(err) - } - - bfw := byteframe.NewByteFrame() - bfw.WriteUint16(uint16(network.MSG_SYS_ACK)) - bfw.WriteUint32(ackHandle) - bfw.WriteBytes(data) - cc.SendPacket(bfw.Data()) - - getPaperDataCount++ - if getPaperDataCount > 7 { - getPaperDataCount = 0 - } - default: - fmt.Printf("Data:\n%s\n", hex.Dump(pkt)) - break - } - - remainingData := bf.DataFromCurrent() - if len(remainingData) >= 2 && (opcode == network.MSG_SYS_TIME || opcode == network.MSG_MHF_INFO_FESTA) { - handlePacket(cc, remainingData) - } -} -*/ diff --git a/common/stringstack/stringstack.go b/common/stringstack/stringstack.go new file mode 100644 index 000000000..aff33842e --- /dev/null +++ b/common/stringstack/stringstack.go @@ -0,0 +1,40 @@ +package stringstack + +import ( + "errors" + "sync" +) + +// StringStack is a basic LIFO "stack" for storing strings. +type StringStack struct { + sync.Mutex + stack []string +} + +// New creates a new instance of StringStack +func New() *StringStack { + return &StringStack{} +} + +// Push pushes a string onto the stack. +func (s *StringStack) Push(v string) { + s.Lock() + defer s.Unlock() + + s.stack = append(s.stack, v) +} + +// Pop pops a string from the stack. +func (s *StringStack) Pop() (string, error) { + s.Lock() + defer s.Unlock() + + if len(s.stack) == 0 { + return "", errors.New("no items on stack") + } + + x := s.stack[len(s.stack)-1] + s.stack = s.stack[:len(s.stack)-1] + + return x, nil +} diff --git a/config.json b/config.json new file mode 100644 index 000000000..280857944 --- /dev/null +++ b/config.json @@ -0,0 +1,85 @@ +{ + "host_ip": "127.0.0.1", + "bin_path": "bin", + + "devmode": false, + "devmodeoptions": { + "cleandb": false, + "maxlauncherhr": true + }, + + "database": { + "host": "localhost", + "port": 5432, + "user": "postgres", + "password": "admin", + "database": "erupe" + }, + "launcher": { + "port": 80, + "UseOriginalLauncherFiles": false + }, + "sign": { + "port": 53312 + }, + "channel": { + "port": 54001 + }, + "entrance": { + "port": 53310, + "entries": [ + { + "name": "AErupe server noob", + "ip": "127.0.0.1", + "unk2": 0, + "type": 3, + "season": 0, + "unk6": 0, + "allowedclientflags": "4096", + "channels": [ + { + "port": 54001, + "MaxPlayers": 10, + "CurrentPlayers": 0, + "Unk4": 0, + "Unk5": 0, + "Unk6": 0, + "Unk7": 0, + "Unk8": 0, + "Unk9": 0, + "Unk10": 319, + "Unk11": 248, + "Unk12": 159, + "Unk13": 12345 + } + ] + }, + { + "name": "AErupe server open", + "ip": "127.0.0.1", + "unk2": 0, + "type": 1, + "season": 0, + "unk6": 0, + "allowedclientflags": 0, + "channels": [ + { + "port": 54001, + "MaxPlayers": 10, + "CurrentPlayers": 0, + "Unk4": 0, + "Unk5": 0, + "Unk6": 0, + "Unk7": 0, + "Unk8": 0, + "Unk9": 0, + "Unk10": 318, + "Unk11": 251, + "Unk12": 155, + "Unk13": 12345 + } + ] + } + ] + } +} \ No newline at end of file diff --git a/config/config.go b/config/config.go index 1cb7cd0fc..30a420708 100644 --- a/config/config.go +++ b/config/config.go @@ -1,25 +1,129 @@ package config -import "github.com/BurntSushi/toml" +import ( + "log" + "net" -// Config holds the configuration settings from the toml file. + "github.com/spf13/viper" +) + +// Config holds the global server-wide config. type Config struct { - DB Database `toml:"database"` + HostIP string `mapstructure:"host_ip"` + BinPath string `mapstructure:"bin_path"` + DevMode bool + + DevModeOptions DevModeOptions + Database Database + Launcher Launcher + Sign Sign + Channel Channel + Entrance Entrance +} + +// DevModeOptions holds various debug/temporary options for use while developing Erupe. +type DevModeOptions struct { + 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. } // Database holds the postgres database config. type Database struct { - Server string - Port int + Host string + Port int + User string + Password string + Database string +} + +// Launcher holds the launcher server config. +type Launcher struct { + Port int + UseOriginalLauncherFiles bool +} + +// Sign holds the sign server config. +type Sign struct { + Port int +} + +// Channel holds the channel server config. +type Channel struct { + Port int +} + +// Entrance holds the entrance server config. +type Entrance struct { + Port uint16 + Entries []EntranceServerInfo +} + +// EntranceServerInfo represents an entry in the serverlist. +type EntranceServerInfo struct { + IP string + Unk2 uint16 + Type uint8 // Server type. 0=?, 1=open, 2=cities, 3=newbie, 4=bar + Season uint8 // Server activity. 0 = green, 1 = orange, 2 = blue + Unk6 uint8 // Something to do with server recommendation on 0, 3, and 5. + Name string // Server name, 66 byte null terminated Shift-JIS(JP) or Big5(TW). + + // 4096(PC, PS3/PS4)?, 8258(PC, PS3/PS4)?, 8192 == nothing? + // THIS ONLY EXISTS IF Binary8Header.type == "SV2", NOT "SVR"! + AllowedClientFlags uint32 + + Channels []EntranceChannelInfo +} + +// EntranceChannelInfo represents an entry in a server's channel list. +type EntranceChannelInfo struct { + Port uint16 + MaxPlayers uint16 + CurrentPlayers uint16 + Unk4 uint16 + Unk5 uint16 + Unk6 uint16 + Unk7 uint16 + Unk8 uint16 + Unk9 uint16 + Unk10 uint16 + Unk11 uint16 + Unk12 uint16 + Unk13 uint16 +} + +// getOutboundIP4 gets the preferred outbound ip4 of this machine +// From https://stackoverflow.com/a/37382208 +func getOutboundIP4() net.IP { + conn, err := net.Dial("udp4", "8.8.8.8:80") + if err != nil { + log.Fatal(err) + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + + return localAddr.IP.To4() } // LoadConfig loads the given config toml file. -func LoadConfig(filepath string) (*Config, error) { - c := &Config{} - _, err := toml.DecodeFile(filepath, c) +func LoadConfig() (*Config, error) { + viper.SetConfigName("config") + viper.AddConfigPath(".") + + err := viper.ReadInConfig() if err != nil { return nil, err } + c := &Config{} + err = viper.Unmarshal(c) + if err != nil { + return nil, err + } + + if c.HostIP == "" { + c.HostIP = getOutboundIP4().To4().String() + } + return c, nil } diff --git a/entranceserver/entrance_server.go b/entranceserver/entrance_server.go deleted file mode 100644 index e43ede422..000000000 --- a/entranceserver/entrance_server.go +++ /dev/null @@ -1,80 +0,0 @@ -package entranceserver - -import ( - "encoding/hex" - "fmt" - "io" - "net" - - "github.com/Andoryuuta/Erupe/network" -) - -func handleEntranceServerConnection(conn net.Conn) { - // Client initalizes the connection with a one-time buffer of 8 NULL bytes. - nullInit := make([]byte, 8) - n, err := io.ReadFull(conn, nullInit) - if err != nil { - fmt.Println(err) - return - } else if n != len(nullInit) { - fmt.Println("io.ReadFull couldn't read the full 8 byte init.") - return - } - - cc := network.NewCryptConn(conn) - for { - pkt, err := cc.ReadPacket() - if err != nil { - return - } - - fmt.Printf("Got entrance server command:\n%s\n", hex.Dump(pkt)) - - data := makeResp([]ServerInfo{ - ServerInfo{ - IP: net.ParseIP("127.0.0.1"), - Unk2: 0, - Type: 1, - Season: 0, - Unk6: 3, - Name: "AErupe Server in Go! @localhost", - AllowedClientFlags: 4096, - Channels: []ChannelInfo{ - ChannelInfo{ - Port: 54001, - MaxPlayers: 100, - CurrentPlayers: 0, - Unk4: 0, - Unk5: 0, - Unk6: 0, - Unk7: 0, - Unk8: 0, - Unk9: 0, - Unk10: 319, - Unk11: 248, - Unk12: 159, - Unk13: 12345, - }, - }, - }, - }) - cc.SendPacket(data) - - } -} - -func DoEntranceServer(listenAddr string) { - l, err := net.Listen("tcp", listenAddr) - if err != nil { - panic(err) - } - defer l.Close() - - for { - conn, err := l.Accept() - if err != nil { - panic(err) - } - go handleEntranceServerConnection(conn) - } -} diff --git a/go.mod b/go.mod index 7148e08f1..a2635d524 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,17 @@ module github.com/Andoryuuta/Erupe go 1.13 require ( - github.com/Andoryuuta/byteframe v0.0.0-20191219124302-41f4085eb4c0 + github.com/Andoryuuta/byteframe v0.0.0-20200114030334-8979c5cc4c4a github.com/BurntSushi/toml v0.3.1 github.com/gorilla/handlers v1.4.2 github.com/gorilla/mux v1.7.3 + github.com/jmoiron/sqlx v1.2.0 github.com/lib/pq v1.3.0 + github.com/spf13/viper v1.6.1 + go.uber.org/atomic v1.5.1 // indirect + go.uber.org/multierr v1.4.0 // indirect + go.uber.org/zap v1.13.0 + golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect + golang.org/x/text v0.3.0 + golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2 // indirect ) diff --git a/go.sum b/go.sum index d300d1197..575a8db8b 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,199 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/Andoryuuta/byteframe v0.0.0-20191219124302-41f4085eb4c0 h1:2pVgen9rh18IxSWxOa80bObcpyfrS6d5bJtZeCUN7rY= github.com/Andoryuuta/byteframe v0.0.0-20191219124302-41f4085eb4c0/go.mod h1:koVyx+gN3TfE70rpOidywETVODk87304YpwW69Y27J4= +github.com/Andoryuuta/byteframe v0.0.0-20200114030334-8979c5cc4c4a h1:41dzqxDfdVhYjpkr8lxwrBdJe0RE/AXsGV1AGpP6wig= +github.com/Andoryuuta/byteframe v0.0.0-20200114030334-8979c5cc4c4a/go.mod h1:koVyx+gN3TfE70rpOidywETVODk87304YpwW69Y27J4= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk= +github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2 h1:V9r/14uGBqLgNlHRYWdVqjMdWkcOHnE2KG8DwVqQSEc= +golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +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= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/main.go b/main.go index ed6d0d43c..8c3318382 100644 --- a/main.go +++ b/main.go @@ -1,60 +1,137 @@ package main import ( - "database/sql" "fmt" + "os" + "os/signal" + "syscall" "time" - "github.com/Andoryuuta/Erupe/channelserver" - "github.com/Andoryuuta/Erupe/signserver" - "github.com/Andoryuuta/Erupe/entranceserver" + "github.com/Andoryuuta/Erupe/config" + "github.com/Andoryuuta/Erupe/server/channelserver" + "github.com/Andoryuuta/Erupe/server/entranceserver" + "github.com/Andoryuuta/Erupe/server/launcherserver" + "github.com/Andoryuuta/Erupe/server/signserver" + "github.com/jmoiron/sqlx" _ "github.com/lib/pq" + "go.uber.org/zap" ) -func main() { - fmt.Println("Starting!") +// Temporary DB auto clean on startup for quick development & testing. +func cleanDB(db *sqlx.DB) { + _ = db.MustExec("DELETE FROM characters") + _ = db.MustExec("DELETE FROM sign_sessions") + _ = db.MustExec("DELETE FROM users") +} - // Load the config.toml configuration. - // TODO(Andoryuuta): implement config loading. +func main() { + zapLogger, _ := zap.NewDevelopment() + defer zapLogger.Sync() + logger := zapLogger.Named("main") + + logger.Info("Starting Erupe") + + // Load the configuration. + erupeConfig, err := config.LoadConfig() + if err != nil { + logger.Fatal("Failed to load config", zap.Error(err)) + } // Create the postgres DB pool. - db, err := sql.Open("postgres", "host=localhost port=5432 user=postgres password=admin dbname=erupe sslmode=disable") + 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, + ) + + db, err := sqlx.Open("postgres", connectString) if err != nil { - panic(err) + logger.Fatal("Failed to open sql database", zap.Error(err)) } // Test the DB connection. err = db.Ping() if err != nil { - panic(err) + logger.Fatal("Failed to ping database", zap.Error(err)) + } + logger.Info("Connected to database") + + // Clean the DB if the option is on. + if erupeConfig.DevMode && erupeConfig.DevModeOptions.CleanDB { + logger.Info("Cleaning DB") + cleanDB(db) + logger.Info("Done cleaning DB") } - // Finally start our server(s). - go serveLauncherHTML(":80", false) - go entranceserver.DoEntranceServer(":53310") + // Now start our server(s). + // Launcher HTTP server. + launcherServer := launcherserver.NewServer( + &launcherserver.Config{ + Logger: logger.Named("launcher"), + ErupeConfig: erupeConfig, + DB: db, + UseOriginalLauncherFiles: erupeConfig.Launcher.UseOriginalLauncherFiles, + }) + err = launcherServer.Start() + if err != nil { + logger.Fatal("Failed to start launcher server", zap.Error(err)) + } + logger.Info("Started launcher server.") + + // Entrance server. + entranceServer := entranceserver.NewServer( + &entranceserver.Config{ + Logger: logger.Named("entrance"), + ErupeConfig: erupeConfig, + DB: db, + }) + err = entranceServer.Start() + if err != nil { + logger.Fatal("Failed to start entrance server", zap.Error(err)) + } + logger.Info("Started entrance server.") + + // Sign server. signServer := signserver.NewServer( &signserver.Config{ - DB: db, - ListenAddr: ":53312", + Logger: logger.Named("sign"), + ErupeConfig: erupeConfig, + DB: db, }) err = signServer.Start() if err != nil { - panic(err) + logger.Fatal("Failed to start sign server", zap.Error(err)) } + logger.Info("Started sign server.") + // Channel Server channelServer := channelserver.NewServer( &channelserver.Config{ - DB: db, - ListenAddr: ":54001", + Logger: logger.Named("channel"), + ErupeConfig: erupeConfig, + DB: db, }) err = channelServer.Start() if err != nil { - panic(err) + logger.Fatal("Failed to start channel server", zap.Error(err)) } + logger.Info("Started channel server.") - for { - time.Sleep(1 * time.Second) - } + // Wait for exit or interrupt with ctrl+C. + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + <-c + + logger.Info("Trying to shutdown gracefully.") + channelServer.Shutdown() + signServer.Shutdown() + entranceServer.Shutdown() + launcherServer.Shutdown() + + time.Sleep(1 * time.Second) } diff --git a/migrations/000002_alter_characters.down.sql b/migrations/000002_alter_characters.down.sql new file mode 100644 index 000000000..c5eeb425b --- /dev/null +++ b/migrations/000002_alter_characters.down.sql @@ -0,0 +1,8 @@ +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 new file mode 100644 index 000000000..8e92154dc --- /dev/null +++ b/migrations/000002_alter_characters.up.sql @@ -0,0 +1,8 @@ +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 new file mode 100644 index 000000000..d8d1ca8c6 --- /dev/null +++ b/migrations/000003_character_savedata.down.sql @@ -0,0 +1,6 @@ +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 new file mode 100644 index 000000000..d0f39a223 --- /dev/null +++ b/migrations/000003_character_savedata.up.sql @@ -0,0 +1,6 @@ +BEGIN; + +ALTER TABLE characters + ADD COLUMN savedata bytea; + +END; \ No newline at end of file diff --git a/network/crypt_conn.go b/network/crypt_conn.go index 7cce26d37..6aeedad8e 100644 --- a/network/crypt_conn.go +++ b/network/crypt_conn.go @@ -1,6 +1,7 @@ package network import ( + "encoding/hex" "errors" "fmt" "io" @@ -16,17 +17,16 @@ type CryptConn struct { readKeyRot uint32 sendKeyRot uint32 sentPackets int32 + prevRecvPacketCombinedCheck uint16 prevSendPacketCombinedCheck uint16 } // NewCryptConn creates a new CryptConn with proper default values. func NewCryptConn(conn net.Conn) *CryptConn { cc := &CryptConn{ - conn: conn, - readKeyRot: 995117, - sendKeyRot: 995117, - sentPackets: 0, - prevSendPacketCombinedCheck: 0, + conn: conn, + readKeyRot: 995117, + sendKeyRot: 995117, } return cc } @@ -41,8 +41,6 @@ func (cc *CryptConn) ReadPacket() ([]byte, error) { return nil, err } - //fmt.Printf("Header: %s\n", hex.Dump(headerData)) - // Parse the data into a usable struct. cph, err := NewCryptPacketHeader(headerData) if err != nil { @@ -65,10 +63,29 @@ func (cc *CryptConn) ReadPacket() ([]byte, error) { if cph.Check0 != check0 || cph.Check1 != check1 || cph.Check2 != check2 { fmt.Printf("got c0 %X, c1 %X, c2 %X\n", check0, check1, check2) fmt.Printf("want c0 %X, c1 %X, c2 %X\n", cph.Check0, cph.Check1, cph.Check2) + fmt.Printf("headerData:\n%s\n", hex.Dump(headerData)) + fmt.Printf("encryptedPacketBody:\n%s\n", hex.Dump(encryptedPacketBody)) + + // Attempt to bruteforce it. + fmt.Println("Crypto out of sync? Attempting bruteforce") + for key := byte(0); key < 255; key++ { + out, combinedCheck, check0, check1, check2 = crypto.Decrypt(encryptedPacketBody, 0, &key) + //fmt.Printf("Key: 0x%X\n%s\n", key, hex.Dump(out)) + if cph.Check0 == check0 && cph.Check1 == check1 && cph.Check2 == check2 { + fmt.Printf("Bruceforce successful, override key: 0x%X\n", key) + + // Try to fix key for subsequent packets? + //cc.readKeyRot = (uint32(key) << 1) + 999983 + + cc.prevRecvPacketCombinedCheck = combinedCheck + return out, nil + } + } + return nil, errors.New("decrypted data checksum doesn't match header") } - _ = combinedCheck + cc.prevRecvPacketCombinedCheck = combinedCheck return out, nil } diff --git a/network/crypto/crypto.go b/network/crypto/crypto.go index 6d4c9e662..87746fa90 100644 --- a/network/crypto/crypto.go +++ b/network/crypto/crypto.go @@ -28,7 +28,7 @@ func _generalCrypt(data []byte, rotKey uint32, cryptType int, overrideByteKey *b cryptKeyTruncByte = *overrideByteKey } - derivedCryptKey := int32((uint32(len(data)) * uint32(cryptKeyTruncByte+1)) & 0xFFFFFFFF) + derivedCryptKey := int32((uint32(len(data)) * (uint32(cryptKeyTruncByte) + 1)) & 0xFFFFFFFF) sharedBufIdx := byte(1) accumulator0 := uint32(0) accumulator1 := uint32(0) diff --git a/network/crypto/crypto_test.go b/network/crypto/crypto_test.go index 83dc57d90..32ff7ee7c 100644 --- a/network/crypto/crypto_test.go +++ b/network/crypto/crypto_test.go @@ -53,6 +53,12 @@ var tests = []struct { []byte{0x46, 0xB5, 0xDC, 0xB2}, 0x2ADD, 0x09A6, 0x021E, 0x08FB3, }, + { + []byte{0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x12, 0x00, 0xDE, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x18, 0x46, 0x00, 0x00, 0x80, 0x3F, 0xDC, 0xE4, 0x0A, 0x46, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x67, 0xD3, 0x5B, 0x00, 0x77, 0x01, 0x78, 0x00, 0x77, 0x01, 0x4F, 0x01, 0x5B, 0x6F, 0x76, 0xC5, 0x30, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xDD, 0x17, 0x46, 0x00, 0x00, 0x80, 0x3F, 0x9E, 0x11, 0x0C, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x37, 0x64, 0x00, 0x2C, 0x01, 0x64, 0x00, 0x2C, 0x01, 0x4F, 0x01, 0x5B, 0x6F, 0x76, 0xC5, 0x00, 0x10}, + 2000476, + []byte{0x2E, 0x52, 0x24, 0xE3, 0x05, 0x2B, 0xFC, 0x04, 0x0B, 0x26, 0x90, 0xEA, 0x61, 0xDB, 0x8D, 0x27, 0xCB, 0xB1, 0x69, 0xA1, 0x77, 0x80, 0x4A, 0xC2, 0xA0, 0xBD, 0x50, 0x54, 0xF5, 0xC2, 0x94, 0x66, 0xBB, 0xCE, 0x53, 0x29, 0xEE, 0xB4, 0xFA, 0xF6, 0x5F, 0x8D, 0x80, 0x3E, 0x5D, 0x5F, 0xB0, 0x53, 0xE6, 0x92, 0x17, 0x80, 0xE7, 0xED, 0xE7, 0xDC, 0x61, 0xF0, 0xCD, 0xE4, 0x41, 0x82, 0x21, 0xBA, 0x47, 0xAB, 0x58, 0xFF, 0x30, 0x76, 0x80, 0x2D, 0x38, 0xF4, 0xDF, 0x86, 0x8C, 0x6C, 0x8D, 0x33, 0x4C, 0x37, 0xA3, 0xDA, 0x01, 0x3C, 0x98, 0x66, 0x1F, 0xB9, 0xE2, 0xEA, 0xF0, 0x84, 0xE8, 0xAA, 0x00, 0x3D, 0x4A, 0xB6, 0xF2, 0x3D, 0x91, 0x58, 0x4B, 0x0B, 0xE2, 0xD5, 0xC7, 0x39, 0x4D, 0x59, 0xED, 0xC3, 0x61, 0x6F, 0x6E, 0x69, 0x9B, 0x3C}, + 0xCFF8, 0x086B, 0x3BAE, 0x4057, + }, } func TestEncrypt(t *testing.T) { diff --git a/network/mhfpacket/msg_mhf_check_weekly_stamp.go b/network/mhfpacket/msg_mhf_check_weekly_stamp.go index d5f725a87..b748c74d7 100644 --- a/network/mhfpacket/msg_mhf_check_weekly_stamp.go +++ b/network/mhfpacket/msg_mhf_check_weekly_stamp.go @@ -6,7 +6,12 @@ import ( ) // MsgMhfCheckWeeklyStamp represents the MSG_MHF_CHECK_WEEKLY_STAMP -type MsgMhfCheckWeeklyStamp struct{} +type MsgMhfCheckWeeklyStamp struct { + AckHandle uint32 + Unk0 uint8 + Unk1 bool + Unk2 uint16 // Hardcoded 0 in the binary +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfCheckWeeklyStamp) Opcode() network.PacketID { @@ -15,10 +20,14 @@ func (m *MsgMhfCheckWeeklyStamp) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfCheckWeeklyStamp) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadBool() + m.Unk2 = bf.ReadUint16() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfCheckWeeklyStamp) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_enumerate_guild_member.go b/network/mhfpacket/msg_mhf_enumerate_guild_member.go index f30f24319..3167ca951 100644 --- a/network/mhfpacket/msg_mhf_enumerate_guild_member.go +++ b/network/mhfpacket/msg_mhf_enumerate_guild_member.go @@ -6,7 +6,12 @@ import ( ) // MsgMhfEnumerateGuildMember represents the MSG_MHF_ENUMERATE_GUILD_MEMBER -type MsgMhfEnumerateGuildMember struct{} +type MsgMhfEnumerateGuildMember struct { + AckHandle uint32 + Unk0 uint16 // Hardcoed 00 01 in the binary + Unk1 uint32 + Unk2 uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfEnumerateGuildMember) Opcode() network.PacketID { @@ -15,10 +20,14 @@ func (m *MsgMhfEnumerateGuildMember) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateGuildMember) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfEnumerateGuildMember) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_enumerate_order.go b/network/mhfpacket/msg_mhf_enumerate_order.go index 5c3dc0a93..a5c26eb9a 100644 --- a/network/mhfpacket/msg_mhf_enumerate_order.go +++ b/network/mhfpacket/msg_mhf_enumerate_order.go @@ -6,7 +6,11 @@ import ( ) // MsgMhfEnumerateOrder represents the MSG_MHF_ENUMERATE_ORDER -type MsgMhfEnumerateOrder struct{} +type MsgMhfEnumerateOrder struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfEnumerateOrder) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgMhfEnumerateOrder) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateOrder) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfEnumerateOrder) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_enumerate_price.go b/network/mhfpacket/msg_mhf_enumerate_price.go index ade7862c8..1e5b5fa6d 100644 --- a/network/mhfpacket/msg_mhf_enumerate_price.go +++ b/network/mhfpacket/msg_mhf_enumerate_price.go @@ -6,7 +6,11 @@ import ( ) // MsgMhfEnumeratePrice represents the MSG_MHF_ENUMERATE_PRICE -type MsgMhfEnumeratePrice struct{} +type MsgMhfEnumeratePrice struct { + AckHandle uint32 + Unk0 uint16 // Hardcoded 0 in the binary + Unk1 uint16 // Hardcoded 0 in the binary +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfEnumeratePrice) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgMhfEnumeratePrice) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumeratePrice) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint16() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfEnumeratePrice) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_enumerate_shop.go b/network/mhfpacket/msg_mhf_enumerate_shop.go index 938393c44..da3ad308f 100644 --- a/network/mhfpacket/msg_mhf_enumerate_shop.go +++ b/network/mhfpacket/msg_mhf_enumerate_shop.go @@ -6,7 +6,15 @@ import ( ) // MsgMhfEnumerateShop represents the MSG_MHF_ENUMERATE_SHOP -type MsgMhfEnumerateShop struct{} +type MsgMhfEnumerateShop struct { + AckHandle uint32 + Unk0 uint8 // Shop ID maybe? I seen 0 -> 10. + Unk1 uint32 + Unk2 uint16 + Unk3 uint8 + Unk4 uint8 + Unk5 uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfEnumerateShop) Opcode() network.PacketID { @@ -15,10 +23,17 @@ func (m *MsgMhfEnumerateShop) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateShop) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadUint16() + m.Unk3 = bf.ReadUint8() + m.Unk4 = bf.ReadUint8() + m.Unk5 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfEnumerateShop) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_boost_right.go b/network/mhfpacket/msg_mhf_get_boost_right.go index d520aab3d..4b48c2203 100644 --- a/network/mhfpacket/msg_mhf_get_boost_right.go +++ b/network/mhfpacket/msg_mhf_get_boost_right.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetBoostRight represents the MSG_MHF_GET_BOOST_RIGHT -type MsgMhfGetBoostRight struct{} +type MsgMhfGetBoostRight struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetBoostRight) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfGetBoostRight) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetBoostRight) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetBoostRight) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_boost_time.go b/network/mhfpacket/msg_mhf_get_boost_time.go index e0bea7a18..12da72f23 100644 --- a/network/mhfpacket/msg_mhf_get_boost_time.go +++ b/network/mhfpacket/msg_mhf_get_boost_time.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetBoostTime represents the MSG_MHF_GET_BOOST_TIME -type MsgMhfGetBoostTime struct{} +type MsgMhfGetBoostTime struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetBoostTime) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfGetBoostTime) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetBoostTime) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetBoostTime) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_boost_time_limit.go b/network/mhfpacket/msg_mhf_get_boost_time_limit.go index d2ad3a758..0c234e12f 100644 --- a/network/mhfpacket/msg_mhf_get_boost_time_limit.go +++ b/network/mhfpacket/msg_mhf_get_boost_time_limit.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetBoostTimeLimit represents the MSG_MHF_GET_BOOST_TIME_LIMIT -type MsgMhfGetBoostTimeLimit struct{} +type MsgMhfGetBoostTimeLimit struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetBoostTimeLimit) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfGetBoostTimeLimit) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetBoostTimeLimit) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetBoostTimeLimit) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_earth_status.go b/network/mhfpacket/msg_mhf_get_earth_status.go index f1e699d25..0ba575040 100644 --- a/network/mhfpacket/msg_mhf_get_earth_status.go +++ b/network/mhfpacket/msg_mhf_get_earth_status.go @@ -6,7 +6,11 @@ import ( ) // MsgMhfGetEarthStatus represents the MSG_MHF_GET_EARTH_STATUS -type MsgMhfGetEarthStatus struct{} +type MsgMhfGetEarthStatus struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetEarthStatus) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgMhfGetEarthStatus) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetEarthStatus) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetEarthStatus) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_earth_value.go b/network/mhfpacket/msg_mhf_get_earth_value.go index da435d462..de83c0a61 100644 --- a/network/mhfpacket/msg_mhf_get_earth_value.go +++ b/network/mhfpacket/msg_mhf_get_earth_value.go @@ -6,7 +6,16 @@ import ( ) // MsgMhfGetEarthValue represents the MSG_MHF_GET_EARTH_VALUE -type MsgMhfGetEarthValue struct{} +type MsgMhfGetEarthValue struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 + Unk2 uint32 + Unk3 uint32 + Unk4 uint32 + Unk5 uint32 + Unk6 uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetEarthValue) Opcode() network.PacketID { @@ -15,10 +24,18 @@ func (m *MsgMhfGetEarthValue) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetEarthValue) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadUint32() + m.Unk3 = bf.ReadUint32() + m.Unk4 = bf.ReadUint32() + m.Unk5 = bf.ReadUint32() + m.Unk6 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetEarthValue) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_enhanced_minidata.go b/network/mhfpacket/msg_mhf_get_enhanced_minidata.go index cf2d56592..ff03df97a 100644 --- a/network/mhfpacket/msg_mhf_get_enhanced_minidata.go +++ b/network/mhfpacket/msg_mhf_get_enhanced_minidata.go @@ -6,7 +6,10 @@ import ( ) // MsgMhfGetEnhancedMinidata represents the MSG_MHF_GET_ENHANCED_MINIDATA -type MsgMhfGetEnhancedMinidata struct{} +type MsgMhfGetEnhancedMinidata struct { + AckHandle uint32 + CharID uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetEnhancedMinidata) Opcode() network.PacketID { @@ -15,10 +18,12 @@ func (m *MsgMhfGetEnhancedMinidata) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetEnhancedMinidata) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.CharID = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetEnhancedMinidata) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_keep_login_boost_status.go b/network/mhfpacket/msg_mhf_get_keep_login_boost_status.go index 9ca1ed5a1..43022755a 100644 --- a/network/mhfpacket/msg_mhf_get_keep_login_boost_status.go +++ b/network/mhfpacket/msg_mhf_get_keep_login_boost_status.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetKeepLoginBoostStatus represents the MSG_MHF_GET_KEEP_LOGIN_BOOST_STATUS -type MsgMhfGetKeepLoginBoostStatus struct{} +type MsgMhfGetKeepLoginBoostStatus struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetKeepLoginBoostStatus) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfGetKeepLoginBoostStatus) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetKeepLoginBoostStatus) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetKeepLoginBoostStatus) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_kouryou_point.go b/network/mhfpacket/msg_mhf_get_kouryou_point.go index 434c07876..e279509da 100644 --- a/network/mhfpacket/msg_mhf_get_kouryou_point.go +++ b/network/mhfpacket/msg_mhf_get_kouryou_point.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetKouryouPoint represents the MSG_MHF_GET_KOURYOU_POINT -type MsgMhfGetKouryouPoint struct{} +type MsgMhfGetKouryouPoint struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetKouryouPoint) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfGetKouryouPoint) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetKouryouPoint) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetKouryouPoint) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_paper_data.go b/network/mhfpacket/msg_mhf_get_paper_data.go index 7782f6f0f..19d5207f6 100644 --- a/network/mhfpacket/msg_mhf_get_paper_data.go +++ b/network/mhfpacket/msg_mhf_get_paper_data.go @@ -6,7 +6,12 @@ import ( ) // MsgMhfGetPaperData represents the MSG_MHF_GET_PAPER_DATA -type MsgMhfGetPaperData struct{} +type MsgMhfGetPaperData struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 + Unk2 uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetPaperData) Opcode() network.PacketID { @@ -15,10 +20,14 @@ func (m *MsgMhfGetPaperData) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetPaperData) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetPaperData) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_seibattle.go b/network/mhfpacket/msg_mhf_get_seibattle.go index f0ab6ca82..9c6efe62f 100644 --- a/network/mhfpacket/msg_mhf_get_seibattle.go +++ b/network/mhfpacket/msg_mhf_get_seibattle.go @@ -6,7 +6,14 @@ import ( ) // MsgMhfGetSeibattle represents the MSG_MHF_GET_SEIBATTLE -type MsgMhfGetSeibattle struct{} +type MsgMhfGetSeibattle struct { + AckHandle uint32 + Unk0 uint8 + Unk1 uint8 + Unk2 uint32 // Some shared ID with MSG_SYS_RECORD_LOG, world ID? + Unk3 uint8 + Unk4 uint16 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetSeibattle) Opcode() network.PacketID { @@ -15,10 +22,16 @@ func (m *MsgMhfGetSeibattle) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetSeibattle) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint8() + m.Unk2 = bf.ReadUint32() + m.Unk3 = bf.ReadUint8() + m.Unk4 = bf.ReadUint16() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetSeibattle) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_tower_info.go b/network/mhfpacket/msg_mhf_get_tower_info.go index c2bbcdf62..5cb86cbc7 100644 --- a/network/mhfpacket/msg_mhf_get_tower_info.go +++ b/network/mhfpacket/msg_mhf_get_tower_info.go @@ -5,8 +5,23 @@ import ( "github.com/Andoryuuta/byteframe" ) +// The server sends different responses based on these values. +const ( + TowerInfoTypeUnk0 = iota + TowerInfoTypeTowerRankPoint + TowerInfoTypeGetOwnTowerSkill + TowerInfoTypeUnk3 + TowerInfoTypeTowerTouhaHistory + TowerInfoTypeUnk5 +) + // MsgMhfGetTowerInfo represents the MSG_MHF_GET_TOWER_INFO -type MsgMhfGetTowerInfo struct{} +type MsgMhfGetTowerInfo struct { + AckHandle uint32 + InfoType uint32 // Requested response type + Unk0 uint32 + Unk1 uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetTowerInfo) Opcode() network.PacketID { @@ -15,10 +30,14 @@ func (m *MsgMhfGetTowerInfo) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetTowerInfo) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.InfoType = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetTowerInfo) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_ud_bonus_quest_info.go b/network/mhfpacket/msg_mhf_get_ud_bonus_quest_info.go index 3f77e96ae..35f586522 100644 --- a/network/mhfpacket/msg_mhf_get_ud_bonus_quest_info.go +++ b/network/mhfpacket/msg_mhf_get_ud_bonus_quest_info.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetUdBonusQuestInfo represents the MSG_MHF_GET_UD_BONUS_QUEST_INFO -type MsgMhfGetUdBonusQuestInfo struct{} +type MsgMhfGetUdBonusQuestInfo struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetUdBonusQuestInfo) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfGetUdBonusQuestInfo) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetUdBonusQuestInfo) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetUdBonusQuestInfo) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_ud_info.go b/network/mhfpacket/msg_mhf_get_ud_info.go index d73402c97..0647fb198 100644 --- a/network/mhfpacket/msg_mhf_get_ud_info.go +++ b/network/mhfpacket/msg_mhf_get_ud_info.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetUdInfo represents the MSG_MHF_GET_UD_INFO -type MsgMhfGetUdInfo struct{} +type MsgMhfGetUdInfo struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetUdInfo) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfGetUdInfo) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetUdInfo) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetUdInfo) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_ud_monster_point.go b/network/mhfpacket/msg_mhf_get_ud_monster_point.go index 01de9256b..1311541ed 100644 --- a/network/mhfpacket/msg_mhf_get_ud_monster_point.go +++ b/network/mhfpacket/msg_mhf_get_ud_monster_point.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetUdMonsterPoint represents the MSG_MHF_GET_UD_MONSTER_POINT -type MsgMhfGetUdMonsterPoint struct{} +type MsgMhfGetUdMonsterPoint struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetUdMonsterPoint) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfGetUdMonsterPoint) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetUdMonsterPoint) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetUdMonsterPoint) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_ud_schedule.go b/network/mhfpacket/msg_mhf_get_ud_schedule.go index bbe23ea56..f543cce0c 100644 --- a/network/mhfpacket/msg_mhf_get_ud_schedule.go +++ b/network/mhfpacket/msg_mhf_get_ud_schedule.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetUdSchedule represents the MSG_MHF_GET_UD_SCHEDULE -type MsgMhfGetUdSchedule struct{} +type MsgMhfGetUdSchedule struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetUdSchedule) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfGetUdSchedule) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetUdSchedule) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetUdSchedule) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_get_ud_tactics_follower.go b/network/mhfpacket/msg_mhf_get_ud_tactics_follower.go index 4c6231710..be80d9123 100644 --- a/network/mhfpacket/msg_mhf_get_ud_tactics_follower.go +++ b/network/mhfpacket/msg_mhf_get_ud_tactics_follower.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetUdTacticsFollower represents the MSG_MHF_GET_UD_TACTICS_FOLLOWER -type MsgMhfGetUdTacticsFollower struct{} +type MsgMhfGetUdTacticsFollower struct{ + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetUdTacticsFollower) Opcode() network.PacketID { @@ -15,7 +17,8 @@ func (m *MsgMhfGetUdTacticsFollower) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetUdTacticsFollower) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_get_weekly_schedule.go b/network/mhfpacket/msg_mhf_get_weekly_schedule.go index b6458028b..c8a01cb7b 100644 --- a/network/mhfpacket/msg_mhf_get_weekly_schedule.go +++ b/network/mhfpacket/msg_mhf_get_weekly_schedule.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfGetWeeklySchedule represents the MSG_MHF_GET_WEEKLY_SCHEDULE -type MsgMhfGetWeeklySchedule struct{} +type MsgMhfGetWeeklySchedule struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetWeeklySchedule) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfGetWeeklySchedule) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetWeeklySchedule) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfGetWeeklySchedule) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_info_festa.go b/network/mhfpacket/msg_mhf_info_festa.go index 0e65fac3d..f376f77ff 100644 --- a/network/mhfpacket/msg_mhf_info_festa.go +++ b/network/mhfpacket/msg_mhf_info_festa.go @@ -6,7 +6,11 @@ import ( ) // MsgMhfInfoFesta represents the MSG_MHF_INFO_FESTA -type MsgMhfInfoFesta struct{} +type MsgMhfInfoFesta struct { + AckHandle uint32 + Unk0 uint16 // Hardcoded 0 in the binary + Unk1 uint16 // Hardcoded 0 in the binary +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfInfoFesta) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgMhfInfoFesta) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfInfoFesta) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint16() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfInfoFesta) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_info_guild.go b/network/mhfpacket/msg_mhf_info_guild.go index dad8df62a..111831cac 100644 --- a/network/mhfpacket/msg_mhf_info_guild.go +++ b/network/mhfpacket/msg_mhf_info_guild.go @@ -6,7 +6,10 @@ import ( ) // MsgMhfInfoGuild represents the MSG_MHF_INFO_GUILD -type MsgMhfInfoGuild struct{} +type MsgMhfInfoGuild struct { + AckHandle uint32 + Unk0 uint32 // Probably a guild ID, but unverified. +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfInfoGuild) Opcode() network.PacketID { @@ -15,10 +18,12 @@ func (m *MsgMhfInfoGuild) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfInfoGuild) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfInfoGuild) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_info_scenario_counter.go b/network/mhfpacket/msg_mhf_info_scenario_counter.go index 9e38aa353..4a415a9e6 100644 --- a/network/mhfpacket/msg_mhf_info_scenario_counter.go +++ b/network/mhfpacket/msg_mhf_info_scenario_counter.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfInfoScenarioCounter represents the MSG_MHF_INFO_SCENARIO_COUNTER -type MsgMhfInfoScenarioCounter struct{} +type MsgMhfInfoScenarioCounter struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfInfoScenarioCounter) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfInfoScenarioCounter) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfInfoScenarioCounter) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfInfoScenarioCounter) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_list_member.go b/network/mhfpacket/msg_mhf_list_member.go index 1d1023bdf..d4759378d 100644 --- a/network/mhfpacket/msg_mhf_list_member.go +++ b/network/mhfpacket/msg_mhf_list_member.go @@ -6,7 +6,10 @@ import ( ) // MsgMhfListMember represents the MSG_MHF_LIST_MEMBER -type MsgMhfListMember struct{} +type MsgMhfListMember struct{ + AckHandle uint32 + Unk0 uint16 // Hardcoded 01 00 in the JP client. +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfListMember) Opcode() network.PacketID { @@ -15,7 +18,9 @@ func (m *MsgMhfListMember) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfListMember) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_load_deco_myset.go b/network/mhfpacket/msg_mhf_load_deco_myset.go index 9b0040f9d..e2f97f326 100644 --- a/network/mhfpacket/msg_mhf_load_deco_myset.go +++ b/network/mhfpacket/msg_mhf_load_deco_myset.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadDecoMyset represents the MSG_MHF_LOAD_DECO_MYSET -type MsgMhfLoadDecoMyset struct{} +type MsgMhfLoadDecoMyset struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadDecoMyset) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfLoadDecoMyset) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadDecoMyset) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfLoadDecoMyset) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_load_favorite_quest.go b/network/mhfpacket/msg_mhf_load_favorite_quest.go index b1da3c9f5..f3224962a 100644 --- a/network/mhfpacket/msg_mhf_load_favorite_quest.go +++ b/network/mhfpacket/msg_mhf_load_favorite_quest.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadFavoriteQuest represents the MSG_MHF_LOAD_FAVORITE_QUEST -type MsgMhfLoadFavoriteQuest struct{} +type MsgMhfLoadFavoriteQuest struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadFavoriteQuest) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfLoadFavoriteQuest) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadFavoriteQuest) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfLoadFavoriteQuest) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_load_hunter_navi.go b/network/mhfpacket/msg_mhf_load_hunter_navi.go index fb30a0562..777e983a7 100644 --- a/network/mhfpacket/msg_mhf_load_hunter_navi.go +++ b/network/mhfpacket/msg_mhf_load_hunter_navi.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadHunterNavi represents the MSG_MHF_LOAD_HUNTER_NAVI -type MsgMhfLoadHunterNavi struct{} +type MsgMhfLoadHunterNavi struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadHunterNavi) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfLoadHunterNavi) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadHunterNavi) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfLoadHunterNavi) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_load_mezfes_data.go b/network/mhfpacket/msg_mhf_load_mezfes_data.go index 1e265f3a6..4f31a61e9 100644 --- a/network/mhfpacket/msg_mhf_load_mezfes_data.go +++ b/network/mhfpacket/msg_mhf_load_mezfes_data.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadMezfesData represents the MSG_MHF_LOAD_MEZFES_DATA -type MsgMhfLoadMezfesData struct{} +type MsgMhfLoadMezfesData struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadMezfesData) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfLoadMezfesData) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadMezfesData) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfLoadMezfesData) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_load_otomo_airou.go b/network/mhfpacket/msg_mhf_load_otomo_airou.go index bf3bbdbe8..33b7dc92c 100644 --- a/network/mhfpacket/msg_mhf_load_otomo_airou.go +++ b/network/mhfpacket/msg_mhf_load_otomo_airou.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadOtomoAirou represents the MSG_MHF_LOAD_OTOMO_AIROU -type MsgMhfLoadOtomoAirou struct{} +type MsgMhfLoadOtomoAirou struct{ + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadOtomoAirou) Opcode() network.PacketID { @@ -15,7 +17,8 @@ func (m *MsgMhfLoadOtomoAirou) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadOtomoAirou) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_load_partner.go b/network/mhfpacket/msg_mhf_load_partner.go index 63b0e9a53..703308a2e 100644 --- a/network/mhfpacket/msg_mhf_load_partner.go +++ b/network/mhfpacket/msg_mhf_load_partner.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadPartner represents the MSG_MHF_LOAD_PARTNER -type MsgMhfLoadPartner struct{} +type MsgMhfLoadPartner struct{ + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadPartner) Opcode() network.PacketID { @@ -15,7 +17,8 @@ func (m *MsgMhfLoadPartner) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadPartner) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_load_plate_box.go b/network/mhfpacket/msg_mhf_load_plate_box.go index 8625e2038..b6d2e2ca2 100644 --- a/network/mhfpacket/msg_mhf_load_plate_box.go +++ b/network/mhfpacket/msg_mhf_load_plate_box.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadPlateBox represents the MSG_MHF_LOAD_PLATE_BOX -type MsgMhfLoadPlateBox struct{} +type MsgMhfLoadPlateBox struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadPlateBox) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfLoadPlateBox) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadPlateBox) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfLoadPlateBox) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_load_plate_data.go b/network/mhfpacket/msg_mhf_load_plate_data.go index 5fc835c06..f7b16339c 100644 --- a/network/mhfpacket/msg_mhf_load_plate_data.go +++ b/network/mhfpacket/msg_mhf_load_plate_data.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadPlateData represents the MSG_MHF_LOAD_PLATE_DATA -type MsgMhfLoadPlateData struct{} +type MsgMhfLoadPlateData struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadPlateData) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfLoadPlateData) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadPlateData) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfLoadPlateData) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_load_plate_myset.go b/network/mhfpacket/msg_mhf_load_plate_myset.go index 831d807ce..429f62c37 100644 --- a/network/mhfpacket/msg_mhf_load_plate_myset.go +++ b/network/mhfpacket/msg_mhf_load_plate_myset.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadPlateMyset represents the MSG_MHF_LOAD_PLATE_MYSET -type MsgMhfLoadPlateMyset struct{} +type MsgMhfLoadPlateMyset struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadPlateMyset) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfLoadPlateMyset) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadPlateMyset) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfLoadPlateMyset) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_load_rengoku_data.go b/network/mhfpacket/msg_mhf_load_rengoku_data.go index 9005716a8..98c9396cf 100644 --- a/network/mhfpacket/msg_mhf_load_rengoku_data.go +++ b/network/mhfpacket/msg_mhf_load_rengoku_data.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadRengokuData represents the MSG_MHF_LOAD_RENGOKU_DATA -type MsgMhfLoadRengokuData struct{} +type MsgMhfLoadRengokuData struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadRengokuData) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfLoadRengokuData) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadRengokuData) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfLoadRengokuData) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_load_scenario_data.go b/network/mhfpacket/msg_mhf_load_scenario_data.go index b115c0712..911a555c0 100644 --- a/network/mhfpacket/msg_mhf_load_scenario_data.go +++ b/network/mhfpacket/msg_mhf_load_scenario_data.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoadScenarioData represents the MSG_MHF_LOAD_SCENARIO_DATA -type MsgMhfLoadScenarioData struct{} +type MsgMhfLoadScenarioData struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoadScenarioData) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfLoadScenarioData) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadScenarioData) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfLoadScenarioData) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_loaddata.go b/network/mhfpacket/msg_mhf_loaddata.go index f34ec6b96..0cb5499f2 100644 --- a/network/mhfpacket/msg_mhf_loaddata.go +++ b/network/mhfpacket/msg_mhf_loaddata.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfLoaddata represents the MSG_MHF_LOADDATA -type MsgMhfLoaddata struct{} +type MsgMhfLoaddata struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfLoaddata) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfLoaddata) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoaddata) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfLoaddata) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_post_boost_time.go b/network/mhfpacket/msg_mhf_post_boost_time.go index 82ad78f7d..ad298c5e2 100644 --- a/network/mhfpacket/msg_mhf_post_boost_time.go +++ b/network/mhfpacket/msg_mhf_post_boost_time.go @@ -6,7 +6,10 @@ import ( ) // MsgMhfPostBoostTime represents the MSG_MHF_POST_BOOST_TIME -type MsgMhfPostBoostTime struct{} +type MsgMhfPostBoostTime struct{ + AckHandle uint32 + BoostTime uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfPostBoostTime) Opcode() network.PacketID { @@ -15,7 +18,9 @@ func (m *MsgMhfPostBoostTime) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfPostBoostTime) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.BoostTime = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_post_boost_time_quest_return.go b/network/mhfpacket/msg_mhf_post_boost_time_quest_return.go index 1cac00928..566caa60e 100644 --- a/network/mhfpacket/msg_mhf_post_boost_time_quest_return.go +++ b/network/mhfpacket/msg_mhf_post_boost_time_quest_return.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfPostBoostTimeQuestReturn represents the MSG_MHF_POST_BOOST_TIME_QUEST_RETURN -type MsgMhfPostBoostTimeQuestReturn struct{} +type MsgMhfPostBoostTimeQuestReturn struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfPostBoostTimeQuestReturn) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfPostBoostTimeQuestReturn) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfPostBoostTimeQuestReturn) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfPostBoostTimeQuestReturn) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_read_beat_level.go b/network/mhfpacket/msg_mhf_read_beat_level.go index 85a6cd334..2110c580c 100644 --- a/network/mhfpacket/msg_mhf_read_beat_level.go +++ b/network/mhfpacket/msg_mhf_read_beat_level.go @@ -6,7 +6,12 @@ import ( ) // MsgMhfReadBeatLevel represents the MSG_MHF_READ_BEAT_LEVEL -type MsgMhfReadBeatLevel struct{} +type MsgMhfReadBeatLevel struct { + AckHandle uint32 + Unk0 uint32 + ValidIDCount uint32 // Valid entries in the array + IDs [16]uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfReadBeatLevel) Opcode() network.PacketID { @@ -15,10 +20,19 @@ func (m *MsgMhfReadBeatLevel) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfReadBeatLevel) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + // I assume this used to be dynamic, but as of the last JP client version, all of this data is hard-coded literals. + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() // Always 1 + m.ValidIDCount = bf.ReadUint32() // Always 4 + + // Always 0x74, 0x6B, 0x02, 0x24 followed by 12 zero values. + for i := 0; i < len(m.IDs); i++ { + m.IDs[i] = bf.ReadUint32() + } + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfReadBeatLevel) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_read_mercenary_w.go b/network/mhfpacket/msg_mhf_read_mercenary_w.go index 89aa4a530..cfd4c6719 100644 --- a/network/mhfpacket/msg_mhf_read_mercenary_w.go +++ b/network/mhfpacket/msg_mhf_read_mercenary_w.go @@ -10,7 +10,7 @@ type MsgMhfReadMercenaryW struct { AckHandle uint32 Unk0 uint8 Unk1 uint8 - Unk2 uint16 + Unk2 uint16 // Hardcoded 0 in the binary } // Opcode returns the ID associated with this packet type. diff --git a/network/mhfpacket/msg_mhf_save_hunter_navi.go b/network/mhfpacket/msg_mhf_save_hunter_navi.go index d62f39254..36b1bdbc1 100644 --- a/network/mhfpacket/msg_mhf_save_hunter_navi.go +++ b/network/mhfpacket/msg_mhf_save_hunter_navi.go @@ -6,7 +6,12 @@ import ( ) // MsgMhfSaveHunterNavi represents the MSG_MHF_SAVE_HUNTER_NAVI -type MsgMhfSaveHunterNavi struct{} +type MsgMhfSaveHunterNavi struct { + AckHandle uint32 + DataSize uint32 + Unk0 bool + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfSaveHunterNavi) Opcode() network.PacketID { @@ -15,10 +20,14 @@ func (m *MsgMhfSaveHunterNavi) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfSaveHunterNavi) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.DataSize = bf.ReadUint32() + m.Unk0 = bf.ReadBool() + m.RawDataPayload = bf.ReadBytes(uint(m.DataSize)) + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfSaveHunterNavi) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_save_mezfes_data.go b/network/mhfpacket/msg_mhf_save_mezfes_data.go index 0c7daa000..96746627f 100644 --- a/network/mhfpacket/msg_mhf_save_mezfes_data.go +++ b/network/mhfpacket/msg_mhf_save_mezfes_data.go @@ -6,7 +6,11 @@ import ( ) // MsgMhfSaveMezfesData represents the MSG_MHF_SAVE_MEZFES_DATA -type MsgMhfSaveMezfesData struct{} +type MsgMhfSaveMezfesData struct { + AckHandle uint32 + DataSize uint32 + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfSaveMezfesData) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgMhfSaveMezfesData) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfSaveMezfesData) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.DataSize = bf.ReadUint32() + m.RawDataPayload = bf.ReadBytes(uint(m.DataSize)) + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfSaveMezfesData) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_save_partner.go b/network/mhfpacket/msg_mhf_save_partner.go index 0bdb84b8c..ee341ab55 100644 --- a/network/mhfpacket/msg_mhf_save_partner.go +++ b/network/mhfpacket/msg_mhf_save_partner.go @@ -6,7 +6,11 @@ import ( ) // MsgMhfSavePartner represents the MSG_MHF_SAVE_PARTNER -type MsgMhfSavePartner struct{} +type MsgMhfSavePartner struct { + AckHandle uint32 + DataSize uint16 + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfSavePartner) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgMhfSavePartner) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfSavePartner) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.DataSize = bf.ReadUint16() + m.RawDataPayload = bf.ReadBytes(uint(m.DataSize)) + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfSavePartner) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_save_scenario_data.go b/network/mhfpacket/msg_mhf_save_scenario_data.go index 6b4ce46a9..7b2d880e0 100644 --- a/network/mhfpacket/msg_mhf_save_scenario_data.go +++ b/network/mhfpacket/msg_mhf_save_scenario_data.go @@ -6,7 +6,11 @@ import ( ) // MsgMhfSaveScenarioData represents the MSG_MHF_SAVE_SCENARIO_DATA -type MsgMhfSaveScenarioData struct{} +type MsgMhfSaveScenarioData struct { + AckHandle uint32 + DataSize uint32 + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfSaveScenarioData) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgMhfSaveScenarioData) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfSaveScenarioData) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.DataSize = bf.ReadUint32() + m.RawDataPayload = bf.ReadBytes(uint(m.DataSize)) + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfSaveScenarioData) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_savedata.go b/network/mhfpacket/msg_mhf_savedata.go index 76ca02722..556d4f3ab 100644 --- a/network/mhfpacket/msg_mhf_savedata.go +++ b/network/mhfpacket/msg_mhf_savedata.go @@ -6,7 +6,14 @@ import ( ) // MsgMhfSavedata represents the MSG_MHF_SAVEDATA -type MsgMhfSavedata struct{} +type MsgMhfSavedata struct { + AckHandle uint32 + AllocMemSize uint32 + Unk0 uint8 // Either 1 or 2, representing a true or false value for some reason. + Unk1 uint32 + DataSize uint32 + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfSavedata) Opcode() network.PacketID { @@ -15,10 +22,16 @@ func (m *MsgMhfSavedata) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfSavedata) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.AllocMemSize = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint32() + m.DataSize = bf.ReadUint32() + m.RawDataPayload = bf.ReadBytes(uint(m.DataSize)) + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfSavedata) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_set_enhanced_minidata.go b/network/mhfpacket/msg_mhf_set_enhanced_minidata.go index cae548e7c..3ab5ac480 100644 --- a/network/mhfpacket/msg_mhf_set_enhanced_minidata.go +++ b/network/mhfpacket/msg_mhf_set_enhanced_minidata.go @@ -6,7 +6,11 @@ import ( ) // MsgMhfSetEnhancedMinidata represents the MSG_MHF_SET_ENHANCED_MINIDATA -type MsgMhfSetEnhancedMinidata struct{} +type MsgMhfSetEnhancedMinidata struct { + AckHandle uint32 + Unk0 uint16 // Hardcoded 4 in the binary. + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfSetEnhancedMinidata) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgMhfSetEnhancedMinidata) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfSetEnhancedMinidata) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + m.RawDataPayload = bf.ReadBytes(0x400) + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfSetEnhancedMinidata) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_mhf_state_festa_g.go b/network/mhfpacket/msg_mhf_state_festa_g.go index ba5d7158f..5651b611d 100644 --- a/network/mhfpacket/msg_mhf_state_festa_g.go +++ b/network/mhfpacket/msg_mhf_state_festa_g.go @@ -6,7 +6,12 @@ import ( ) // MsgMhfStateFestaG represents the MSG_MHF_STATE_FESTA_G -type MsgMhfStateFestaG struct{} +type MsgMhfStateFestaG struct{ + AckHandle uint32 + Unk0 uint32 // Shared ID of something. + Unk1 uint32 + Unk2 uint16 // Hardcoded 0 in the binary. +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfStateFestaG) Opcode() network.PacketID { @@ -15,7 +20,12 @@ func (m *MsgMhfStateFestaG) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfStateFestaG) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadUint16() + + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_update_use_trend_weapon_log.go b/network/mhfpacket/msg_mhf_update_use_trend_weapon_log.go index 35bc9d1ca..be42fa1ba 100644 --- a/network/mhfpacket/msg_mhf_update_use_trend_weapon_log.go +++ b/network/mhfpacket/msg_mhf_update_use_trend_weapon_log.go @@ -6,7 +6,11 @@ import ( ) // MsgMhfUpdateUseTrendWeaponLog represents the MSG_MHF_UPDATE_USE_TREND_WEAPON_LOG -type MsgMhfUpdateUseTrendWeaponLog struct{} +type MsgMhfUpdateUseTrendWeaponLog struct { + AckHandle uint32 + Unk0 uint8 + Unk1 uint16 // Weapon/item ID probably? +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfUpdateUseTrendWeaponLog) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgMhfUpdateUseTrendWeaponLog) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfUpdateUseTrendWeaponLog) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint16() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfUpdateUseTrendWeaponLog) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_ack.go b/network/mhfpacket/msg_sys_ack.go index 978e0f5d6..0b8dccad5 100644 --- a/network/mhfpacket/msg_sys_ack.go +++ b/network/mhfpacket/msg_sys_ack.go @@ -8,8 +8,7 @@ import ( // MsgSysAck represents the MSG_SYS_ACK type MsgSysAck struct { AckHandle uint32 - Unk0 uint32 - Unk1 uint32 + AckData []byte } // Opcode returns the ID associated with this packet type. @@ -20,16 +19,12 @@ func (m *MsgSysAck) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysAck) Parse(bf *byteframe.ByteFrame) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint32() - m.Unk1 = bf.ReadUint32() - - return nil + panic("No way to parse without prior context as the packet doesn't include it's own length.") } // Build builds a binary packet from the current data. func (m *MsgSysAck) Build(bf *byteframe.ByteFrame) error { bf.WriteUint32(m.AckHandle) - bf.WriteUint32(m.Unk0) - bf.WriteUint32(m.Unk1) + bf.WriteBytes(m.AckData) return nil } diff --git a/network/mhfpacket/msg_sys_back_stage.go b/network/mhfpacket/msg_sys_back_stage.go index 3473f46da..1d435e7f6 100644 --- a/network/mhfpacket/msg_sys_back_stage.go +++ b/network/mhfpacket/msg_sys_back_stage.go @@ -6,7 +6,9 @@ import ( ) // MsgSysBackStage represents the MSG_SYS_BACK_STAGE -type MsgSysBackStage struct{} +type MsgSysBackStage struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysBackStage) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgSysBackStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysBackStage) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgSysBackStage) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_cast_binary.go b/network/mhfpacket/msg_sys_cast_binary.go index 69c9a727b..90667fd36 100644 --- a/network/mhfpacket/msg_sys_cast_binary.go +++ b/network/mhfpacket/msg_sys_cast_binary.go @@ -6,7 +6,13 @@ import ( ) // MsgSysCastBinary represents the MSG_SYS_CAST_BINARY -type MsgSysCastBinary struct{} +type MsgSysCastBinary struct { + Unk0 uint16 + Unk1 uint16 + Type0 uint8 + Type1 uint8 + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgSysCastBinary) Opcode() network.PacketID { @@ -15,10 +21,16 @@ func (m *MsgSysCastBinary) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysCastBinary) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint16() + m.Type0 = bf.ReadUint8() + m.Type1 = bf.ReadUint8() + dataSize := bf.ReadUint16() + m.RawDataPayload = bf.ReadBytes(uint(dataSize)) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysCastBinary) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_casted_binary.go b/network/mhfpacket/msg_sys_casted_binary.go index aeddac73c..d2c0145d4 100644 --- a/network/mhfpacket/msg_sys_casted_binary.go +++ b/network/mhfpacket/msg_sys_casted_binary.go @@ -6,7 +6,12 @@ import ( ) // MsgSysCastedBinary represents the MSG_SYS_CASTED_BINARY -type MsgSysCastedBinary struct{} +type MsgSysCastedBinary struct { + CharID uint32 + Type0 uint8 + Type1 uint8 + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgSysCastedBinary) Opcode() network.PacketID { @@ -20,5 +25,10 @@ func (m *MsgSysCastedBinary) Parse(bf *byteframe.ByteFrame) error { // Build builds a binary packet from the current data. func (m *MsgSysCastedBinary) Build(bf *byteframe.ByteFrame) error { - panic("Not implemented") -} \ No newline at end of file + bf.WriteUint32(m.CharID) + bf.WriteUint8(m.Type0) + bf.WriteUint8(m.Type0) + bf.WriteUint16(uint16(len(m.RawDataPayload))) + bf.WriteBytes(m.RawDataPayload) + return nil +} diff --git a/network/mhfpacket/msg_sys_cleanup_object.go b/network/mhfpacket/msg_sys_cleanup_object.go index a5548cd4a..0f3881c8d 100644 --- a/network/mhfpacket/msg_sys_cleanup_object.go +++ b/network/mhfpacket/msg_sys_cleanup_object.go @@ -20,5 +20,6 @@ func (m *MsgSysCleanupObject) Parse(bf *byteframe.ByteFrame) error { // Build builds a binary packet from the current data. func (m *MsgSysCleanupObject) Build(bf *byteframe.ByteFrame) error { - panic("Not implemented") -} \ No newline at end of file + // This packet has no data. + return nil +} diff --git a/network/mhfpacket/msg_sys_create_object.go b/network/mhfpacket/msg_sys_create_object.go index 42c23b337..107e982be 100644 --- a/network/mhfpacket/msg_sys_create_object.go +++ b/network/mhfpacket/msg_sys_create_object.go @@ -6,7 +6,11 @@ import ( ) // MsgSysCreateObject represents the MSG_SYS_CREATE_OBJECT -type MsgSysCreateObject struct{} +type MsgSysCreateObject struct { + AckHandle uint32 + X, Y, Z float32 + Unk0 uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysCreateObject) Opcode() network.PacketID { @@ -15,10 +19,15 @@ func (m *MsgSysCreateObject) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysCreateObject) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.X = bf.ReadFloat32() + m.Y = bf.ReadFloat32() + m.Z = bf.ReadFloat32() + m.Unk0 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgSysCreateObject) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_create_stage.go b/network/mhfpacket/msg_sys_create_stage.go index 642a3c23d..8fec57798 100644 --- a/network/mhfpacket/msg_sys_create_stage.go +++ b/network/mhfpacket/msg_sys_create_stage.go @@ -6,7 +6,13 @@ import ( ) // MsgSysCreateStage represents the MSG_SYS_CREATE_STAGE -type MsgSysCreateStage struct{} +type MsgSysCreateStage struct { + AckHandle uint32 + Unk0 uint8 // Likely only has 1 and 2 as values. + PlayerCount uint8 + StageIDLength uint8 + StageID string // NULL terminated string. +} // Opcode returns the ID associated with this packet type. func (m *MsgSysCreateStage) Opcode() network.PacketID { @@ -15,10 +21,15 @@ func (m *MsgSysCreateStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysCreateStage) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.PlayerCount = bf.ReadUint8() + m.StageIDLength = bf.ReadUint8() + m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysCreateStage) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_delete_object.go b/network/mhfpacket/msg_sys_delete_object.go index 817060e03..13d951103 100644 --- a/network/mhfpacket/msg_sys_delete_object.go +++ b/network/mhfpacket/msg_sys_delete_object.go @@ -6,7 +6,9 @@ import ( ) // MsgSysDeleteObject represents the MSG_SYS_DELETE_OBJECT -type MsgSysDeleteObject struct{} +type MsgSysDeleteObject struct { + ObjID uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysDeleteObject) Opcode() network.PacketID { @@ -15,10 +17,12 @@ func (m *MsgSysDeleteObject) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysDeleteObject) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.ObjID = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgSysDeleteObject) Build(bf *byteframe.ByteFrame) error { - panic("Not implemented") -} \ No newline at end of file + bf.WriteUint32(m.ObjID) + return nil +} diff --git a/network/mhfpacket/msg_sys_duplicate_object.go b/network/mhfpacket/msg_sys_duplicate_object.go index 72105acad..3f5e43071 100644 --- a/network/mhfpacket/msg_sys_duplicate_object.go +++ b/network/mhfpacket/msg_sys_duplicate_object.go @@ -6,7 +6,12 @@ import ( ) // MsgSysDuplicateObject represents the MSG_SYS_DUPLICATE_OBJECT -type MsgSysDuplicateObject struct{} +type MsgSysDuplicateObject struct { + ObjID uint32 + X, Y, Z float32 + Unk0 uint32 + OwnerCharID uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysDuplicateObject) Opcode() network.PacketID { @@ -20,5 +25,11 @@ func (m *MsgSysDuplicateObject) Parse(bf *byteframe.ByteFrame) error { // Build builds a binary packet from the current data. func (m *MsgSysDuplicateObject) Build(bf *byteframe.ByteFrame) error { - panic("Not implemented") -} \ No newline at end of file + bf.WriteUint32(m.ObjID) + bf.WriteFloat32(m.X) + bf.WriteFloat32(m.Y) + bf.WriteFloat32(m.Z) + bf.WriteUint32(m.Unk0) + bf.WriteUint32(m.OwnerCharID) + return nil +} diff --git a/network/mhfpacket/msg_sys_end.go b/network/mhfpacket/msg_sys_end.go index f6c874657..07da6c0ce 100644 --- a/network/mhfpacket/msg_sys_end.go +++ b/network/mhfpacket/msg_sys_end.go @@ -15,10 +15,12 @@ func (m *MsgSysEnd) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysEnd) Parse(bf *byteframe.ByteFrame) error { + // No data aside from opcode. return nil } // Build builds a binary packet from the current data. func (m *MsgSysEnd) Build(bf *byteframe.ByteFrame) error { + // No data aside from opcode. return nil } diff --git a/network/mhfpacket/msg_sys_enter_stage.go b/network/mhfpacket/msg_sys_enter_stage.go index 8dd614b92..addea7cfa 100644 --- a/network/mhfpacket/msg_sys_enter_stage.go +++ b/network/mhfpacket/msg_sys_enter_stage.go @@ -6,7 +6,12 @@ import ( ) // MsgSysEnterStage represents the MSG_SYS_ENTER_STAGE -type MsgSysEnterStage struct{} +type MsgSysEnterStage struct { + AckHandle uint32 + UnkBool uint8 + StageIDLength uint8 + StageID string +} // Opcode returns the ID associated with this packet type. func (m *MsgSysEnterStage) Opcode() network.PacketID { @@ -15,10 +20,14 @@ func (m *MsgSysEnterStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysEnterStage) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.UnkBool = bf.ReadUint8() + m.StageIDLength = bf.ReadUint8() + m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysEnterStage) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_enumerate_client.go b/network/mhfpacket/msg_sys_enumerate_client.go index 5d3bf1e00..17115db11 100644 --- a/network/mhfpacket/msg_sys_enumerate_client.go +++ b/network/mhfpacket/msg_sys_enumerate_client.go @@ -6,7 +6,13 @@ import ( ) // MsgSysEnumerateClient represents the MSG_SYS_ENUMERATE_CLIENT -type MsgSysEnumerateClient struct{} +type MsgSysEnumerateClient struct { + AckHandle uint32 + Unk0 uint8 // Hardcoded 1 in the client + Unk1 uint8 + StageIDLength uint8 + StageID string +} // Opcode returns the ID associated with this packet type. func (m *MsgSysEnumerateClient) Opcode() network.PacketID { @@ -15,10 +21,15 @@ func (m *MsgSysEnumerateClient) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysEnumerateClient) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint8() + m.StageIDLength = bf.ReadUint8() + m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysEnumerateClient) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_enumerate_stage.go b/network/mhfpacket/msg_sys_enumerate_stage.go index 65d60c02f..79aff6016 100644 --- a/network/mhfpacket/msg_sys_enumerate_stage.go +++ b/network/mhfpacket/msg_sys_enumerate_stage.go @@ -6,7 +6,12 @@ import ( ) // MsgSysEnumerateStage represents the MSG_SYS_ENUMERATE_STAGE -type MsgSysEnumerateStage struct{} +type MsgSysEnumerateStage struct { + AckHandle uint32 + Unk0 uint8 // Hardcoded 1 in the binary + StageIDLength uint8 + StageID string // NULL terminated string. +} // Opcode returns the ID associated with this packet type. func (m *MsgSysEnumerateStage) Opcode() network.PacketID { @@ -15,10 +20,14 @@ func (m *MsgSysEnumerateStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysEnumerateStage) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.StageIDLength = bf.ReadUint8() + m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysEnumerateStage) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_extend_threshold.go b/network/mhfpacket/msg_sys_extend_threshold.go index f07dc384d..7058b42f8 100644 --- a/network/mhfpacket/msg_sys_extend_threshold.go +++ b/network/mhfpacket/msg_sys_extend_threshold.go @@ -15,10 +15,12 @@ func (m *MsgSysExtendThreshold) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysExtendThreshold) Parse(bf *byteframe.ByteFrame) error { + // No data aside from opcode. return nil } // Build builds a binary packet from the current data. func (m *MsgSysExtendThreshold) Build(bf *byteframe.ByteFrame) error { + // No data aside from opcode. return nil } diff --git a/network/mhfpacket/msg_sys_get_file.go b/network/mhfpacket/msg_sys_get_file.go index 30a4f0403..fccb1201b 100644 --- a/network/mhfpacket/msg_sys_get_file.go +++ b/network/mhfpacket/msg_sys_get_file.go @@ -5,8 +5,35 @@ import ( "github.com/Andoryuuta/byteframe" ) +type scenarioFileIdentifer struct { + CategoryID uint8 + MainID uint32 + ChapterID uint8 + /* + Flags represent the following bit flags: + + 11111111 -> Least significant bit on the right. + |||||||| + |||||||0x1: Chunk0-type, recursive chunks, quest name/description + 0x14 byte unk info + ||||||0x2: Chunk1-type, recursive chunks, npc dialog? + 0x2C byte unk info + |||||0x4: UNK NONE FOUND. (Guessing from the following that this might be a chunk2-type) + ||||0x8: Chunk0-type, NO RECURSIVE CHUNKS ([0x1] prefixed?), Episode listing + |||0x10: Chunk1-type, NO RECURSIVE CHUNKS, JKR blob, npc dialog? + ||0x20: Chunk2-type, NO RECURSIVE CHUNKS, JKR blob, Menu options or quest titles? + |0x40: UNK NONE FOUND + 0x80: UNK NONE FOUND + */ + Flags uint8 +} + // MsgSysGetFile represents the MSG_SYS_GET_FILE -type MsgSysGetFile struct{} +type MsgSysGetFile struct { + AckHandle uint32 + IsScenario bool + FilenameLength uint8 + Filename string + ScenarioIdentifer scenarioFileIdentifer +} // Opcode returns the ID associated with this packet type. func (m *MsgSysGetFile) Opcode() network.PacketID { @@ -15,10 +42,25 @@ func (m *MsgSysGetFile) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysGetFile) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.IsScenario = bf.ReadBool() + m.FilenameLength = bf.ReadUint8() + if m.FilenameLength > 0 { + m.Filename = string(bf.ReadBytes(uint(m.FilenameLength))) + } + + if m.IsScenario { + m.ScenarioIdentifer = scenarioFileIdentifer{ + bf.ReadUint8(), + bf.ReadUint32(), + bf.ReadUint8(), + bf.ReadUint8(), + } + } + return nil } // Build builds a binary packet from the current data. func (m *MsgSysGetFile) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_get_stage_binary.go b/network/mhfpacket/msg_sys_get_stage_binary.go index fa21aab36..a6368567c 100644 --- a/network/mhfpacket/msg_sys_get_stage_binary.go +++ b/network/mhfpacket/msg_sys_get_stage_binary.go @@ -6,7 +6,14 @@ import ( ) // MsgSysGetStageBinary represents the MSG_SYS_GET_STAGE_BINARY -type MsgSysGetStageBinary struct{} +type MsgSysGetStageBinary struct { + AckHandle uint32 + BinaryType0 uint8 + BinaryType1 uint8 + Unk0 uint32 // Hardcoded 0 + StageIDLength uint8 + StageID string +} // Opcode returns the ID associated with this packet type. func (m *MsgSysGetStageBinary) Opcode() network.PacketID { @@ -15,10 +22,16 @@ func (m *MsgSysGetStageBinary) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysGetStageBinary) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.BinaryType0 = bf.ReadUint8() + m.BinaryType1 = bf.ReadUint8() + m.Unk0 = bf.ReadUint32() + m.StageIDLength = bf.ReadUint8() + m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysGetStageBinary) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_get_user_binary.go b/network/mhfpacket/msg_sys_get_user_binary.go index 5db54bba4..27c279d3c 100644 --- a/network/mhfpacket/msg_sys_get_user_binary.go +++ b/network/mhfpacket/msg_sys_get_user_binary.go @@ -6,7 +6,11 @@ import ( ) // MsgSysGetUserBinary represents the MSG_SYS_GET_USER_BINARY -type MsgSysGetUserBinary struct{} +type MsgSysGetUserBinary struct { + AckHandle uint32 + CharID uint32 + BinaryType uint8 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysGetUserBinary) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgSysGetUserBinary) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysGetUserBinary) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.CharID = bf.ReadUint32() + m.BinaryType = bf.ReadUint8() + return nil } // Build builds a binary packet from the current data. func (m *MsgSysGetUserBinary) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_hide_client.go b/network/mhfpacket/msg_sys_hide_client.go index 95ff37edc..181305088 100644 --- a/network/mhfpacket/msg_sys_hide_client.go +++ b/network/mhfpacket/msg_sys_hide_client.go @@ -6,7 +6,11 @@ import ( ) // MsgSysHideClient represents the MSG_SYS_HIDE_CLIENT -type MsgSysHideClient struct{} +type MsgSysHideClient struct{ + Hide bool + Unk0 uint16 // Hardcoded 0 in binary + Unk1 uint8 // Hardcoded 0 in binary +} // Opcode returns the ID associated with this packet type. func (m *MsgSysHideClient) Opcode() network.PacketID { @@ -15,7 +19,10 @@ func (m *MsgSysHideClient) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysHideClient) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.Hide = bf.ReadBool() + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint8() + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_sys_insert_user.go b/network/mhfpacket/msg_sys_insert_user.go index b8aa206e6..13466c493 100644 --- a/network/mhfpacket/msg_sys_insert_user.go +++ b/network/mhfpacket/msg_sys_insert_user.go @@ -6,7 +6,9 @@ import ( ) // MsgSysInsertUser represents the MSG_SYS_INSERT_USER -type MsgSysInsertUser struct{} +type MsgSysInsertUser struct { + CharID uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysInsertUser) Opcode() network.PacketID { @@ -20,5 +22,6 @@ func (m *MsgSysInsertUser) Parse(bf *byteframe.ByteFrame) error { // Build builds a binary packet from the current data. func (m *MsgSysInsertUser) Build(bf *byteframe.ByteFrame) error { - panic("Not implemented") -} \ No newline at end of file + bf.WriteUint32(m.CharID) + return nil +} diff --git a/network/mhfpacket/msg_sys_issue_logkey.go b/network/mhfpacket/msg_sys_issue_logkey.go index b8d95ddb0..2114b4d12 100644 --- a/network/mhfpacket/msg_sys_issue_logkey.go +++ b/network/mhfpacket/msg_sys_issue_logkey.go @@ -6,7 +6,11 @@ import ( ) // MsgSysIssueLogkey represents the MSG_SYS_ISSUE_LOGKEY -type MsgSysIssueLogkey struct{} +type MsgSysIssueLogkey struct { + AckHandle uint32 + Unk0 uint16 // Hardcoded 00 01 in binary + Unk1 uint16 // Hardcoded 0 in binary. +} // Opcode returns the ID associated with this packet type. func (m *MsgSysIssueLogkey) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgSysIssueLogkey) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysIssueLogkey) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint16() + return nil } // Build builds a binary packet from the current data. func (m *MsgSysIssueLogkey) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_lock_stage.go b/network/mhfpacket/msg_sys_lock_stage.go index 7968ef332..085aadc46 100644 --- a/network/mhfpacket/msg_sys_lock_stage.go +++ b/network/mhfpacket/msg_sys_lock_stage.go @@ -6,7 +6,13 @@ import ( ) // MsgSysLockStage represents the MSG_SYS_LOCK_STAGE -type MsgSysLockStage struct{} +type MsgSysLockStage struct { + AckHandle uint32 + Unk0 uint8 // Hardcoded 1 in the binary + Unk1 uint8 // Hardcoded 1 in the binary + StageIDLength uint8 + StageID string +} // Opcode returns the ID associated with this packet type. func (m *MsgSysLockStage) Opcode() network.PacketID { @@ -15,10 +21,15 @@ func (m *MsgSysLockStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysLockStage) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint8() + m.StageIDLength = bf.ReadUint8() + m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysLockStage) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_move_stage.go b/network/mhfpacket/msg_sys_move_stage.go index 57bfdb942..c8ae87dd7 100644 --- a/network/mhfpacket/msg_sys_move_stage.go +++ b/network/mhfpacket/msg_sys_move_stage.go @@ -6,7 +6,12 @@ import ( ) // MsgSysMoveStage represents the MSG_SYS_MOVE_STAGE -type MsgSysMoveStage struct{} +type MsgSysMoveStage struct { + AckHandle uint32 + UnkBool uint8 + StageIDLength uint8 + StageID string +} // Opcode returns the ID associated with this packet type. func (m *MsgSysMoveStage) Opcode() network.PacketID { @@ -15,10 +20,14 @@ func (m *MsgSysMoveStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysMoveStage) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.UnkBool = bf.ReadUint8() + m.StageIDLength = bf.ReadUint8() + m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysMoveStage) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_nop.go b/network/mhfpacket/msg_sys_nop.go index e769142cd..6b56434a7 100644 --- a/network/mhfpacket/msg_sys_nop.go +++ b/network/mhfpacket/msg_sys_nop.go @@ -15,10 +15,12 @@ func (m *MsgSysNop) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysNop) Parse(bf *byteframe.ByteFrame) error { + // No data aside from opcode. return nil } // Build builds a binary packet from the current data. func (m *MsgSysNop) Build(bf *byteframe.ByteFrame) error { + // No data aside from opcode. return nil } diff --git a/network/mhfpacket/msg_sys_notify_user_binary.go b/network/mhfpacket/msg_sys_notify_user_binary.go index e4914aeef..2fbb5a9cf 100644 --- a/network/mhfpacket/msg_sys_notify_user_binary.go +++ b/network/mhfpacket/msg_sys_notify_user_binary.go @@ -6,7 +6,10 @@ import ( ) // MsgSysNotifyUserBinary represents the MSG_SYS_NOTIFY_USER_BINARY -type MsgSysNotifyUserBinary struct{} +type MsgSysNotifyUserBinary struct { + CharID uint32 + BinaryType uint8 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysNotifyUserBinary) Opcode() network.PacketID { @@ -20,5 +23,7 @@ func (m *MsgSysNotifyUserBinary) Parse(bf *byteframe.ByteFrame) error { // Build builds a binary packet from the current data. func (m *MsgSysNotifyUserBinary) Build(bf *byteframe.ByteFrame) error { - panic("Not implemented") -} \ No newline at end of file + bf.WriteUint32(m.CharID) + bf.WriteUint8(m.BinaryType) + return nil +} diff --git a/network/mhfpacket/msg_sys_ping.go b/network/mhfpacket/msg_sys_ping.go index ebbfe27ad..90d7343b6 100644 --- a/network/mhfpacket/msg_sys_ping.go +++ b/network/mhfpacket/msg_sys_ping.go @@ -8,7 +8,6 @@ import ( // MsgSysPing represents the MSG_SYS_PING type MsgSysPing struct { AckHandle uint32 - Unk0 uint16 } // Opcode returns the ID associated with this packet type. @@ -19,13 +18,11 @@ func (m *MsgSysPing) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysPing) Parse(bf *byteframe.ByteFrame) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() return nil } // Build builds a binary packet from the current data. func (m *MsgSysPing) Build(bf *byteframe.ByteFrame) error { bf.WriteUint32(m.AckHandle) - bf.WriteUint16(m.Unk0) return nil } diff --git a/network/mhfpacket/msg_sys_position_object.go b/network/mhfpacket/msg_sys_position_object.go index 335a526d3..5ba3152df 100644 --- a/network/mhfpacket/msg_sys_position_object.go +++ b/network/mhfpacket/msg_sys_position_object.go @@ -6,7 +6,10 @@ import ( ) // MsgSysPositionObject represents the MSG_SYS_POSITION_OBJECT -type MsgSysPositionObject struct{} +type MsgSysPositionObject struct{ + ObjID uint32 + X, Y, Z float32 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysPositionObject) Opcode() network.PacketID { @@ -15,10 +18,18 @@ func (m *MsgSysPositionObject) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysPositionObject) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.ObjID = bf.ReadUint32() + m.X = bf.ReadFloat32() + m.Y = bf.ReadFloat32() + m.Z = bf.ReadFloat32() + return nil } // Build builds a binary packet from the current data. func (m *MsgSysPositionObject) Build(bf *byteframe.ByteFrame) error { - panic("Not implemented") + bf.WriteUint32(m.ObjID) + bf.WriteFloat32(m.X) + bf.WriteFloat32(m.Y) + bf.WriteFloat32(m.Z) + return nil } \ No newline at end of file diff --git a/network/mhfpacket/msg_sys_record_log.go b/network/mhfpacket/msg_sys_record_log.go index 711a21d7d..2f72e30da 100644 --- a/network/mhfpacket/msg_sys_record_log.go +++ b/network/mhfpacket/msg_sys_record_log.go @@ -6,7 +6,14 @@ import ( ) // MsgSysRecordLog represents the MSG_SYS_RECORD_LOG -type MsgSysRecordLog struct{} +type MsgSysRecordLog struct { + AckHandle uint32 + Unk0 uint32 + Unk1 uint16 // Hardcoded 0 + HardcodedDataSize uint16 // Hardcoded 0x4AC + Unk3 uint32 // Some shared ID with MSG_MHF_GET_SEIBATTLE. World ID?? + DataBuf []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgSysRecordLog) Opcode() network.PacketID { @@ -15,10 +22,17 @@ func (m *MsgSysRecordLog) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysRecordLog) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint16() + m.HardcodedDataSize = bf.ReadUint16() + m.Unk3 = bf.ReadUint32() + m.DataBuf = bf.ReadBytes(uint(m.HardcodedDataSize)) + return nil + } // Build builds a binary packet from the current data. func (m *MsgSysRecordLog) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_reserve188.go b/network/mhfpacket/msg_sys_reserve188.go index 530ad4e9f..1f6f27860 100644 --- a/network/mhfpacket/msg_sys_reserve188.go +++ b/network/mhfpacket/msg_sys_reserve188.go @@ -6,7 +6,9 @@ import ( ) // MsgSysReserve188 represents the MSG_SYS_reserve188 -type MsgSysReserve188 struct{} +type MsgSysReserve188 struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysReserve188) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgSysReserve188) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysReserve188) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgSysReserve188) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_reserve18b.go b/network/mhfpacket/msg_sys_reserve18b.go index fd9492a13..3874772f8 100644 --- a/network/mhfpacket/msg_sys_reserve18b.go +++ b/network/mhfpacket/msg_sys_reserve18b.go @@ -6,7 +6,9 @@ import ( ) // MsgSysReserve18B represents the MSG_SYS_reserve18B -type MsgSysReserve18B struct{} +type MsgSysReserve18B struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysReserve18B) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgSysReserve18B) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysReserve18B) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgSysReserve18B) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_reserve203.go b/network/mhfpacket/msg_sys_reserve203.go index 5059a54f2..62f9e528c 100644 --- a/network/mhfpacket/msg_sys_reserve203.go +++ b/network/mhfpacket/msg_sys_reserve203.go @@ -5,8 +5,14 @@ import ( "github.com/Andoryuuta/byteframe" ) +// TODO(Andoryuuta): Make up a name for this packet, not reserved anymore. Called "Is_update_guild_msg_board" + // MsgSysReserve203 represents the MSG_SYS_reserve203 -type MsgSysReserve203 struct{} +type MsgSysReserve203 struct { + AckHandle uint32 + Unk0 uint16 // Hardcoded 0x0000 in the binary + Unk1 uint16 // Hardcoded 0x0500 in the binary. +} // Opcode returns the ID associated with this packet type. func (m *MsgSysReserve203) Opcode() network.PacketID { @@ -15,10 +21,13 @@ func (m *MsgSysReserve203) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysReserve203) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint16() + return nil } // Build builds a binary packet from the current data. func (m *MsgSysReserve203) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_reserve_stage.go b/network/mhfpacket/msg_sys_reserve_stage.go index daf097bd2..d6c65f7ea 100644 --- a/network/mhfpacket/msg_sys_reserve_stage.go +++ b/network/mhfpacket/msg_sys_reserve_stage.go @@ -6,7 +6,12 @@ import ( ) // MsgSysReserveStage represents the MSG_SYS_RESERVE_STAGE -type MsgSysReserveStage struct{} +type MsgSysReserveStage struct { + AckHandle uint32 + Unk0 uint8 // Made with: `16 * x | 1;`, unknown `x` values. + StageIDLength uint8 + StageID string // NULL terminated string. +} // Opcode returns the ID associated with this packet type. func (m *MsgSysReserveStage) Opcode() network.PacketID { @@ -15,10 +20,14 @@ func (m *MsgSysReserveStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysReserveStage) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.StageIDLength = bf.ReadUint8() + m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysReserveStage) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_set_object_binary.go b/network/mhfpacket/msg_sys_set_object_binary.go index 324a7db9d..5c37505fd 100644 --- a/network/mhfpacket/msg_sys_set_object_binary.go +++ b/network/mhfpacket/msg_sys_set_object_binary.go @@ -6,7 +6,11 @@ import ( ) // MsgSysSetObjectBinary represents the MSG_SYS_SET_OBJECT_BINARY -type MsgSysSetObjectBinary struct{} +type MsgSysSetObjectBinary struct { + ObjID uint32 + DataSize uint16 + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgSysSetObjectBinary) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgSysSetObjectBinary) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysSetObjectBinary) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.ObjID = bf.ReadUint32() + m.DataSize = bf.ReadUint16() + m.RawDataPayload = bf.ReadBytes(uint(m.DataSize)) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysSetObjectBinary) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_set_stage_binary.go b/network/mhfpacket/msg_sys_set_stage_binary.go index 5864cba6a..4f087b2ac 100644 --- a/network/mhfpacket/msg_sys_set_stage_binary.go +++ b/network/mhfpacket/msg_sys_set_stage_binary.go @@ -6,7 +6,14 @@ import ( ) // MsgSysSetStageBinary represents the MSG_SYS_SET_STAGE_BINARY -type MsgSysSetStageBinary struct{} +type MsgSysSetStageBinary struct { + BinaryType0 uint8 + BinaryType1 uint8 // Index + StageIDLength uint8 // <= 0x20 + DataSize uint16 // <= 0x400 + StageID string + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgSysSetStageBinary) Opcode() network.PacketID { @@ -15,10 +22,16 @@ func (m *MsgSysSetStageBinary) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysSetStageBinary) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.BinaryType0 = bf.ReadUint8() + m.BinaryType1 = bf.ReadUint8() + m.StageIDLength = bf.ReadUint8() + m.DataSize = bf.ReadUint16() + m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + m.RawDataPayload = bf.ReadBytes(uint(m.DataSize)) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysSetStageBinary) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_set_stage_pass.go b/network/mhfpacket/msg_sys_set_stage_pass.go index f3de3f5f2..587801bb1 100644 --- a/network/mhfpacket/msg_sys_set_stage_pass.go +++ b/network/mhfpacket/msg_sys_set_stage_pass.go @@ -6,7 +6,11 @@ import ( ) // MsgSysSetStagePass represents the MSG_SYS_SET_STAGE_PASS -type MsgSysSetStagePass struct{} +type MsgSysSetStagePass struct { + Unk0 uint8 // Hardcoded 0 in the binary + PasswordLength uint8 + Password string // NULL-terminated string +} // Opcode returns the ID associated with this packet type. func (m *MsgSysSetStagePass) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgSysSetStagePass) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysSetStagePass) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.Unk0 = bf.ReadUint8() + m.PasswordLength = bf.ReadUint8() + m.Password = string(bf.ReadBytes(uint(m.PasswordLength))) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysSetStagePass) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_set_user_binary.go b/network/mhfpacket/msg_sys_set_user_binary.go index 8a75b0409..ef6f05fcd 100644 --- a/network/mhfpacket/msg_sys_set_user_binary.go +++ b/network/mhfpacket/msg_sys_set_user_binary.go @@ -6,7 +6,11 @@ import ( ) // MsgSysSetUserBinary represents the MSG_SYS_SET_USER_BINARY -type MsgSysSetUserBinary struct{} +type MsgSysSetUserBinary struct { + BinaryType uint8 + DataSize uint16 + RawDataPayload []byte +} // Opcode returns the ID associated with this packet type. func (m *MsgSysSetUserBinary) Opcode() network.PacketID { @@ -15,10 +19,13 @@ func (m *MsgSysSetUserBinary) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysSetUserBinary) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.BinaryType = bf.ReadUint8() + m.DataSize = bf.ReadUint16() + m.RawDataPayload = bf.ReadBytes(uint(m.DataSize)) + return nil } // Build builds a binary packet from the current data. func (m *MsgSysSetUserBinary) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_terminal_log.go b/network/mhfpacket/msg_sys_terminal_log.go index c34a03a08..e786962ad 100644 --- a/network/mhfpacket/msg_sys_terminal_log.go +++ b/network/mhfpacket/msg_sys_terminal_log.go @@ -5,8 +5,20 @@ import ( "github.com/Andoryuuta/byteframe" ) +// 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 +} + // MsgSysTerminalLog represents the MSG_SYS_TERMINAL_LOG -type MsgSysTerminalLog struct{} +type MsgSysTerminalLog struct { + AckHandle uint32 + LogID uint32 // 0 on the first packet, and the server sends back a value to use for subsequent requests. + EntryCount uint16 + Unk0 uint16 // Hardcoded 0 in the binary + Entries []*TerminalLogEntry +} // Opcode returns the ID associated with this packet type. func (m *MsgSysTerminalLog) Opcode() network.PacketID { @@ -15,10 +27,29 @@ func (m *MsgSysTerminalLog) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysTerminalLog) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.LogID = bf.ReadUint32() + m.EntryCount = bf.ReadUint16() + m.Unk0 = bf.ReadUint16() + + 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() + m.Entries = append(m.Entries, e) + } + + return nil } // Build builds a binary packet from the current data. func (m *MsgSysTerminalLog) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_time.go b/network/mhfpacket/msg_sys_time.go index 715a97161..0029395db 100644 --- a/network/mhfpacket/msg_sys_time.go +++ b/network/mhfpacket/msg_sys_time.go @@ -7,8 +7,8 @@ import ( // MsgSysTime represents the MSG_SYS_TIME type MsgSysTime struct { - Unk0 uint8 - Timestamp uint32 // unix timestamp, e.g. 1577105879 + GetRemoteTime bool // Ask the other end to send it's time as well. + Timestamp uint32 // Unix timestamp, e.g. 1577105879 } // Opcode returns the ID associated with this packet type. @@ -18,14 +18,14 @@ func (m *MsgSysTime) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysTime) Parse(bf *byteframe.ByteFrame) error { - m.Unk0 = bf.ReadUint8() + m.GetRemoteTime = bf.ReadBool() m.Timestamp = bf.ReadUint32() return nil } // Build builds a binary packet from the current data. func (m *MsgSysTime) Build(bf *byteframe.ByteFrame) error { - bf.WriteUint8(m.Unk0) + bf.WriteBool(m.GetRemoteTime) bf.WriteUint32(m.Timestamp) return nil } diff --git a/network/mhfpacket/msg_sys_unlock_stage.go b/network/mhfpacket/msg_sys_unlock_stage.go index 043ba6ce3..054bb9574 100644 --- a/network/mhfpacket/msg_sys_unlock_stage.go +++ b/network/mhfpacket/msg_sys_unlock_stage.go @@ -6,7 +6,9 @@ import ( ) // MsgSysUnlockStage represents the MSG_SYS_UNLOCK_STAGE -type MsgSysUnlockStage struct{} +type MsgSysUnlockStage struct { + Unk0 uint16 // Hardcoded 0 in the binary. +} // Opcode returns the ID associated with this packet type. func (m *MsgSysUnlockStage) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgSysUnlockStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysUnlockStage) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.Unk0 = bf.ReadUint16() + return nil } // Build builds a binary packet from the current data. func (m *MsgSysUnlockStage) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_update_right.go b/network/mhfpacket/msg_sys_update_right.go index b3d7d33e2..628bd834f 100644 --- a/network/mhfpacket/msg_sys_update_right.go +++ b/network/mhfpacket/msg_sys_update_right.go @@ -5,8 +5,41 @@ import ( "github.com/Andoryuuta/byteframe" ) +/* +00 58 // Opcode + +00 00 00 00 +00 00 00 4e + +00 04 // Count +00 00 // Skipped(padding?) + +00 01 00 00 00 00 00 00 +00 02 00 00 5d fa 14 c0 +00 03 00 00 5d fa 14 c0 +00 06 00 00 5d e7 05 10 + +00 00 // Count of some buf up to 0x800 bytes following it. + +00 10 // Trailer +*/ + +// ClientRight represents a right that the client has. +type ClientRight struct { + ID uint16 + Unk0 uint16 + Timestamp uint32 +} + // MsgSysUpdateRight represents the MSG_SYS_UPDATE_RIGHT -type MsgSysUpdateRight struct{} +type MsgSysUpdateRight struct { + Unk0 uint32 + Unk1 uint32 + //RightCount uint16 + //Unk3 uint16 // Likely struct padding + Rights []ClientRight + UnkSize uint16 // Count of some buf up to 0x800 bytes following it. +} // Opcode returns the ID associated with this packet type. func (m *MsgSysUpdateRight) Opcode() network.PacketID { @@ -20,5 +53,15 @@ func (m *MsgSysUpdateRight) Parse(bf *byteframe.ByteFrame) error { // Build builds a binary packet from the current data. func (m *MsgSysUpdateRight) Build(bf *byteframe.ByteFrame) error { - panic("Not implemented") -} \ No newline at end of file + bf.WriteUint32(m.Unk0) + bf.WriteUint32(m.Unk1) + bf.WriteUint16(uint16(len(m.Rights))) + bf.WriteUint16(0) // m.Unk3, struct padding. + for _, v := range m.Rights { + bf.WriteUint16(v.ID) + bf.WriteUint16(v.Unk0) + bf.WriteUint32(v.Timestamp) + } + bf.WriteUint16(m.UnkSize) + return nil +} diff --git a/network/mhfpacket/msg_sys_wait_stage_binary.go b/network/mhfpacket/msg_sys_wait_stage_binary.go index caa4b0f5b..b897b527d 100644 --- a/network/mhfpacket/msg_sys_wait_stage_binary.go +++ b/network/mhfpacket/msg_sys_wait_stage_binary.go @@ -6,7 +6,14 @@ import ( ) // MsgSysWaitStageBinary represents the MSG_SYS_WAIT_STAGE_BINARY -type MsgSysWaitStageBinary struct{} +type MsgSysWaitStageBinary struct{ + AckHandle uint32 + BinaryType0 uint8 + BinaryType1 uint8 + Unk0 uint32 // Hardcoded 0 + StageIDLength uint8 + StageID string +} // Opcode returns the ID associated with this packet type. func (m *MsgSysWaitStageBinary) Opcode() network.PacketID { @@ -15,7 +22,13 @@ func (m *MsgSysWaitStageBinary) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysWaitStageBinary) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + m.BinaryType0 = bf.ReadUint8() + m.BinaryType1 = bf.ReadUint8() + m.Unk0 = bf.ReadUint32() + m.StageIDLength = bf.ReadUint8() + m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + return nil } // Build builds a binary packet from the current data. diff --git a/server/channelserver/channel_server.go b/server/channelserver/channel_server.go new file mode 100644 index 000000000..500a6bc3f --- /dev/null +++ b/server/channelserver/channel_server.go @@ -0,0 +1,169 @@ +package channelserver + +import ( + "fmt" + "net" + "sync" + + "github.com/Andoryuuta/Erupe/config" + "github.com/Andoryuuta/Erupe/network/mhfpacket" + "github.com/Andoryuuta/byteframe" + "github.com/jmoiron/sqlx" + "go.uber.org/zap" +) + +// Config struct allows configuring the server. +type Config struct { + Logger *zap.Logger + DB *sqlx.DB + ErupeConfig *config.Config +} + +// Map key type for a user binary part. +type userBinaryPartID struct { + charID uint32 + index uint8 +} + +// Server is a MHF channel server. +type Server struct { + sync.Mutex + logger *zap.Logger + db *sqlx.DB + erupeConfig *config.Config + acceptConns chan net.Conn + deleteConns chan net.Conn + sessions map[net.Conn]*Session + listener net.Listener // Listener that is created when Server.Start is called. + + isShuttingDown bool + + stagesLock sync.RWMutex + stages map[string]*Stage + + userBinaryPartsLock sync.RWMutex + userBinaryParts map[userBinaryPartID][]byte +} + +// NewServer creates a new Server type. +func NewServer(config *Config) *Server { + s := &Server{ + logger: config.Logger, + db: config.DB, + erupeConfig: config.ErupeConfig, + acceptConns: make(chan net.Conn), + deleteConns: make(chan net.Conn), + sessions: make(map[net.Conn]*Session), + stages: make(map[string]*Stage), + userBinaryParts: make(map[userBinaryPartID][]byte), + } + + // Default town stage that clients try to enter without creating. + stage := NewStage("sl1Ns200p0a0u0") + s.stages[stage.id] = stage + + // Town underground left area -- rasta bar stage (Maybe private bar ID as well?). + stage2 := NewStage("sl1Ns211p0a0u0") + s.stages[stage2.id] = stage2 + + // Diva fountain / prayer fountain. + stage3 := NewStage("sl2Ns379p0a0u0") + s.stages[stage3.id] = stage3 + + // sl1Ns257p0a0uE31111 -- house for charID E31111. + + return s +} + +// Start starts the server in a new goroutine. +func (s *Server) Start() error { + l, err := net.Listen("tcp", fmt.Sprintf(":%d", s.erupeConfig.Channel.Port)) + if err != nil { + return err + } + s.listener = l + + go s.acceptClients() + go s.manageSessions() + + return nil +} + +// Shutdown tries to shut down the server gracefully. +func (s *Server) Shutdown() { + s.Lock() + s.isShuttingDown = true + s.Unlock() + + s.listener.Close() + close(s.acceptConns) +} + +func (s *Server) acceptClients() { + for { + conn, err := s.listener.Accept() + if err != nil { + s.Lock() + shutdown := s.isShuttingDown + s.Unlock() + + if shutdown { + break + } else { + s.logger.Warn("Error accepting client", zap.Error(err)) + continue + } + } + s.acceptConns <- conn + } +} + +func (s *Server) manageSessions() { + for { + select { + case newConn := <-s.acceptConns: + // Gracefully handle acceptConns channel closing. + if newConn == nil { + s.Lock() + shutdown := s.isShuttingDown + s.Unlock() + + if shutdown { + return + } + } + + session := NewSession(s, newConn) + + s.Lock() + s.sessions[newConn] = session + s.Unlock() + + session.Start() + + case delConn := <-s.deleteConns: + s.Lock() + delete(s.sessions, delConn) + s.Unlock() + } + } +} + +// BroadcastMHF queues a MHFPacket to be sent to all sessions. +func (s *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { + // Make the header + bf := byteframe.NewByteFrame() + bf.WriteUint16(uint16(pkt.Opcode())) + + // Build the packet onto the byteframe. + pkt.Build(bf) + + // Broadcast the data. + for _, session := range s.sessions { + if session == ignoredSession { + continue + } + // Enqueue in a non-blocking way that drops the packet if the connections send buffer channel is full. + session.QueueSendNonBlocking(bf.Data()) + } +} diff --git a/channelserver/handler_table.go b/server/channelserver/handler_table.go similarity index 100% rename from channelserver/handler_table.go rename to server/channelserver/handler_table.go diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go new file mode 100644 index 000000000..8dc7b26c6 --- /dev/null +++ b/server/channelserver/handlers.go @@ -0,0 +1,2286 @@ +package channelserver + +import ( + "bytes" + "crypto/rand" + "encoding/base64" + "fmt" + "io/ioutil" + "path/filepath" + "strings" + "time" + + "github.com/Andoryuuta/Erupe/network/mhfpacket" + "github.com/Andoryuuta/byteframe" + "go.uber.org/zap" + "golang.org/x/text/encoding/japanese" + "golang.org/x/text/transform" +) + +// Temporary function to just return no results for a MSG_MHF_ENUMERATE* packet +func stubEnumerateNoResults(s *Session, ackHandle uint32) { + enumBf := byteframe.NewByteFrame() + enumBf.WriteUint16(0) // Entry count (count for quests, rankings, events, etc.) + + doSizedAckResp(s, ackHandle, enumBf.Data()) +} + +// Temporary function to just return no results for many MSG_MHF_GET* packets. +func stubGetNoResults(s *Session, ackHandle uint32) { + resp := byteframe.NewByteFrame() + resp.WriteUint32(0x0A218EAD) // Unk shared ID. Sent in response of MSG_MHF_GET_TOWER_INFO, MSG_MHF_GET_PAPER_DATA etc. (World ID?) + resp.WriteUint32(0) // Unk + resp.WriteUint32(0) // Unk + resp.WriteUint32(0) // Entry count + + doSizedAckResp(s, ackHandle, resp.Data()) +} + +// Some common ACK response header that a lot (but not all) of the packet responses use. +func doSizedAckResp(s *Session, ackHandle uint32, data []byte) { + // Wrap the data into another container with the data size. + bfw := byteframe.NewByteFrame() + bfw.WriteUint8(1) // Unk + bfw.WriteUint8(0) // Unk + bfw.WriteUint16(uint16(len(data))) // Data size + if len(data) > 0 { + bfw.WriteBytes(data) + } + + s.QueueAck(ackHandle, bfw.Data()) +} + +func updateRights(s *Session) { + update := &mhfpacket.MsgSysUpdateRight{ + Unk0: 0, + Unk1: 0x4E, + Rights: []mhfpacket.ClientRight{ + { + ID: 1, + Timestamp: 0, + }, + { + ID: 2, + Timestamp: 0x5dfa14c0, + }, + { + ID: 3, + Timestamp: 0x5dfa14c0, + }, + { + ID: 6, + Timestamp: 0x5de70510, + }, + }, + UnkSize: 0, + } + s.QueueSendMHF(update) +} + +func fixedSizeShiftJIS(text string, size int) []byte { + r := bytes.NewBuffer([]byte(text)) + encoded, err := ioutil.ReadAll(transform.NewReader(r, japanese.ShiftJIS.NewEncoder())) + if err != nil { + panic(err) + } + + out := make([]byte, size) + copy(out, encoded) + + // Null terminate it. + out[len(out)-1] = 0 + return out +} + +// TODO(Andoryuuta): Fix/move/remove me! +func stripNullTerminator(x string) string { + return strings.SplitN(x, "\x00", 2)[0] +} + +func handleMsgHead(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve01(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve02(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve03(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve04(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve05(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve06(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve07(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysAddObject(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysDelObject(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysDispObject(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysHideObject(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve0C(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve0D(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve0E(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysExtendThreshold(s *Session, p mhfpacket.MHFPacket) { + // No data aside from header, no resp required. +} + +func handleMsgSysEnd(s *Session, p mhfpacket.MHFPacket) { + // No data aside from header, no resp required. +} + +func handleMsgSysNop(s *Session, p mhfpacket.MHFPacket) { + // No data aside from header, no resp required. +} + +func handleMsgSysAck(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysTerminalLog(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysTerminalLog) + + resp := byteframe.NewByteFrame() + /* + if pkt.LogID == 0{ + fmt.Println("New log session") + } + */ + resp.WriteUint32(0) // UNK + resp.WriteUint32(0x98bd51a9) // LogID to use for requests after this. + s.QueueAck(pkt.AckHandle, resp.Data()) +} + +func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysLogin) + + s.Lock() + s.charID = pkt.CharID0 + s.Unlock() + + bf := byteframe.NewByteFrame() + bf.WriteUint32(0) // Unk + bf.WriteUint32(uint32(time.Now().Unix())) // Unix timestamp + s.QueueAck(pkt.AckHandle, bf.Data()) +} + +func handleMsgSysLogout(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysSetStatus(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysPing(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysPing) + + bf := byteframe.NewByteFrame() + bf.WriteUint32(0) // Unk + bf.WriteUint32(0) // Unk + s.QueueAck(pkt.AckHandle, bf.Data()) +} + +func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysCastBinary) + + if pkt.Type0 == 3 && pkt.Type1 == 1 { + fmt.Println("Got chat message!") + + resp := &mhfpacket.MsgSysCastedBinary{ + CharID: s.charID, + Type0: 1, + Type1: 1, + RawDataPayload: pkt.RawDataPayload, + } + s.server.BroadcastMHF(resp, s) + + /* + // Made the inside of the casted binary + payload := byteframe.NewByteFrame() + payload.WriteUint16(uint16(i)) // Chat type + + //Chat type 0 = World + //Chat type 1 = Local + //Chat type 2 = Guild + //Chat type 3 = Alliance + //Chat type 4 = Party + //Chat type 5 = Whisper + //Thanks to @Alice on discord for identifying these. + + payload.WriteUint8(0) // Unknown + msg := fmt.Sprintf("Chat type %d", i) + playername := fmt.Sprintf("Ando") + payload.WriteUint16(uint16(len(playername) + 1)) + payload.WriteUint16(uint16(len(msg) + 1)) + payload.WriteUint8(0) // Is this correct, or do I have the endianess of the prev 2 fields wrong? + payload.WriteNullTerminatedBytes([]byte(msg)) + payload.WriteNullTerminatedBytes([]byte(playername)) + payloadBytes := payload.Data() + + //Wrap it in a CASTED_BINARY packet to broadcast + bfw := byteframe.NewByteFrame() + bfw.WriteUint16(uint16(network.MSG_SYS_CASTED_BINARY)) + bfw.WriteUint32(0x23325A29) // Character ID + bfw.WriteUint8(1) // type + bfw.WriteUint8(1) // type2 + bfw.WriteUint16(uint16(len(payloadBytes))) + bfw.WriteBytes(payloadBytes) + */ + } +} + +func handleMsgSysHideClient(s *Session, p mhfpacket.MHFPacket) { + //pkt := p.(*mhfpacket.MsgSysHideClient) +} + +func handleMsgSysTime(s *Session, p mhfpacket.MHFPacket) { + //pkt := p.(*mhfpacket.MsgSysTime) + + resp := &mhfpacket.MsgSysTime{ + GetRemoteTime: false, + Timestamp: uint32(time.Now().Unix()), + } + s.QueueSendMHF(resp) +} + +func handleMsgSysCastedBinary(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysGetFile) + + // Debug print the request. + fmt.Printf("%+v\n", pkt) + if pkt.IsScenario { + fmt.Printf("%+v\n", pkt.ScenarioIdentifer) + } + + if !pkt.IsScenario { + // Get quest file. + data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", stripNullTerminator(pkt.Filename)))) + if err != nil { + panic(err) + } + + doSizedAckResp(s, pkt.AckHandle, data) + } else { + + /* + // mhf-fake-client format + filename := fmt.Sprintf( + "%d_%d_%d_%d", + pkt.ScenarioIdentifer.CategoryID, + pkt.ScenarioIdentifer.MainID, + pkt.ScenarioIdentifer.ChapterID, + pkt.ScenarioIdentifer.Flags, + ) + */ + + // Fist's format: + filename := fmt.Sprintf( + "%d_0_0_0_S%d_T%d_C%d", + pkt.ScenarioIdentifer.CategoryID, + pkt.ScenarioIdentifer.MainID, + pkt.ScenarioIdentifer.Flags, // Fist had as "type" and is the "T%d" + pkt.ScenarioIdentifer.ChapterID, + ) + + // 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) + } + + doSizedAckResp(s, pkt.AckHandle, data) + } + +} + +func handleMsgSysIssueLogkey(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysIssueLogkey) + + // Make a random log key for this session. + logKey := make([]byte, 16) + _, err := rand.Read(logKey) + if err != nil { + panic(err) + } + + // TODO(Andoryuuta): In the offical client, the log key index is off by one, + // cutting off the last byte in _most uses_. Find and document these accordingly. + s.Lock() + s.logKey = logKey + s.Unlock() + + // Issue it. + resp := byteframe.NewByteFrame() + resp.WriteBytes(logKey) + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgSysRecordLog(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysRecordLog) + resp := make([]byte, 8) // Unk resp. + s.QueueAck(pkt.AckHandle, resp) +} + +func handleMsgSysEcho(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysCreateStage) + + s.server.stagesLock.Lock() + stage := NewStage(stripNullTerminator(pkt.StageID)) + s.server.stages[stage.id] = stage + s.server.stagesLock.Unlock() + + resp := make([]byte, 8) // Unk resp. + s.QueueAck(pkt.AckHandle, resp) +} + +func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {} + +func doStageTransfer(s *Session, ackHandle uint32, stageID string) { + // Remove this session from old stage clients list and put myself in the new one. + s.server.stagesLock.Lock() + newStage, gotNewStage := s.server.stages[stripNullTerminator(stageID)] + s.server.stagesLock.Unlock() + + if s.stage != nil { + s.stage.Lock() + + // Remove client from old stage. + delete(s.stage.clients, s) + + // Delete old stage objects owned by the client. + s.logger.Info("Sending MsgSysDeleteObject to old stage clients") + for objID, stageObject := range s.stage.objects { + if stageObject.ownerCharID == s.charID { + // Broadcast the deletion to clients in the stage. + s.stage.BroadcastMHF(&mhfpacket.MsgSysDeleteObject{ + ObjID: stageObject.id, + }, s) + // TODO(Andoryuuta): Should this be sent to the owner's client as well? it currently isn't. + + // Actually delete it form the objects map. + delete(s.stage.objects, objID) + } + } + + s.stage.Unlock() + } + + // Add the new stage. + if gotNewStage { + newStage.Lock() + newStage.clients[s] = s.charID + newStage.Unlock() + } + + // Save our new stage ID and pointer to the new stage itself. + s.Lock() + s.stageID = string(stripNullTerminator(stageID)) + s.stage = newStage + s.Unlock() + + // Tell the client to cleanup its current stage objects. + s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{}) + + // Confirm the stage entry. + s.QueueAck(ackHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) + + // Notify existing stage clients that this new client has entered. + s.logger.Info("Sending MsgSysInsertUser & MsgSysNotifyUserBinary") + s.stage.BroadcastMHF(&mhfpacket.MsgSysInsertUser{ + CharID: s.charID, + }, s) + + s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{ + CharID: s.charID, + BinaryType: 1, + }, s) + s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{ + CharID: s.charID, + BinaryType: 2, + }, s) + s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{ + CharID: s.charID, + BinaryType: 3, + }, s) + + // Notify the entree client about all of the existing clients in the stage. + s.logger.Info("Notifying entree about existing stage clients") + s.stage.RLock() + clientNotif := byteframe.NewByteFrame() + for session := range s.stage.clients { + var cur mhfpacket.MHFPacket + cur = &mhfpacket.MsgSysInsertUser{ + CharID: session.charID, + } + clientNotif.WriteUint16(uint16(cur.Opcode())) + cur.Build(clientNotif) + + cur = &mhfpacket.MsgSysNotifyUserBinary{ + CharID: session.charID, + BinaryType: 1, + } + clientNotif.WriteUint16(uint16(cur.Opcode())) + cur.Build(clientNotif) + + cur = &mhfpacket.MsgSysNotifyUserBinary{ + CharID: session.charID, + BinaryType: 2, + } + clientNotif.WriteUint16(uint16(cur.Opcode())) + cur.Build(clientNotif) + + cur = &mhfpacket.MsgSysNotifyUserBinary{ + CharID: session.charID, + BinaryType: 3, + } + clientNotif.WriteUint16(uint16(cur.Opcode())) + cur.Build(clientNotif) + } + s.stage.RUnlock() + clientNotif.WriteUint16(0x0010) // End it. + s.QueueSend(clientNotif.Data()) + + // Notify the client to duplicate the existing objects. + s.logger.Info("Notifying entree about existing stage objects") + clientDupObjNotif := byteframe.NewByteFrame() + s.stage.RLock() + for _, obj := range s.stage.objects { + cur := &mhfpacket.MsgSysDuplicateObject{ + ObjID: obj.id, + X: obj.x, + Y: obj.y, + Z: obj.z, + Unk0: 0, + OwnerCharID: obj.ownerCharID, + } + clientDupObjNotif.WriteUint16(uint16(cur.Opcode())) + cur.Build(clientDupObjNotif) + } + s.stage.RUnlock() + clientDupObjNotif.WriteUint16(0x0010) // End it. + s.QueueSend(clientDupObjNotif.Data()) +} + +func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysEnterStage) + + // Push our current stage ID to the movement stack before entering another one. + s.Lock() + s.stageMoveStack.Push(s.stageID) + s.Unlock() + + doStageTransfer(s, pkt.AckHandle, pkt.StageID) +} + +func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysBackStage) + + // Transfer back to the saved stage ID before the previous move or enter. + s.Lock() + backStage, err := s.stageMoveStack.Pop() + s.Unlock() + + if err != nil { + panic(err) + } + + doStageTransfer(s, pkt.AckHandle, backStage) + +} + +func handleMsgSysMoveStage(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysMoveStage) + + // Push our current stage ID to the movement stack before entering another one. + s.Lock() + s.stageMoveStack.Push(s.stageID) + s.Unlock() + + doStageTransfer(s, pkt.AckHandle, pkt.StageID) +} + +func handleMsgSysLeaveStage(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysLockStage(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysLockStage) + // TODO(Andoryuuta): What does this packet _actually_ do? + s.QueueAck(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysReserveStage) + + fmt.Printf("Got reserve stage req, Unk0:%v, StageID:%q\n", pkt.Unk0, pkt.StageID) + + // TODO(Andoryuuta): Add proper player-slot reservations for stages. + + s.QueueAck(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgSysUnreserveStage(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysSetStagePass(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysWaitStageBinary(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysWaitStageBinary) + defer s.logger.Debug("MsgSysWaitStageBinary Done!") + + // Try to get the stage + stageID := stripNullTerminator(pkt.StageID) + s.server.stagesLock.Lock() + stage, gotStage := s.server.stages[stageID] + s.server.stagesLock.Unlock() + + // If we got the stage, lock and try to get the data. + var stageBinary []byte + var gotBinary bool + if gotStage { + for { + stage.Lock() + stageBinary, gotBinary = stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}] + stage.Unlock() + + if gotBinary { + doSizedAckResp(s, pkt.AckHandle, stageBinary) + break + } else { + // Couldn't get binary, sleep for some time and try again. + time.Sleep(2 * time.Second) + continue + } + + // TODO(Andoryuuta): Figure out what the game sends on timeout and implement it! + /* + if timeout { + s.logger.Warn("Failed to get stage binary", zap.Uint8("BinaryType0", pkt.BinaryType0), zap.Uint8("pkt.BinaryType1", pkt.BinaryType1)) + s.logger.Warn("Sending blank stage binary") + doSizedAckResp(s, pkt.AckHandle, []byte{}) + return + } + */ + } + } else { + s.logger.Warn("Failed to get stage", zap.String("StageID", stageID)) + } +} + +func handleMsgSysSetStageBinary(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysSetStageBinary) + + // Try to get the stage + stageID := stripNullTerminator(pkt.StageID) + s.server.stagesLock.Lock() + stage, gotStage := s.server.stages[stageID] + s.server.stagesLock.Unlock() + + // If we got the stage, lock and set the data. + if gotStage { + stage.Lock() + stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}] = pkt.RawDataPayload + stage.Unlock() + } else { + s.logger.Warn("Failed to get stage", zap.String("StageID", stageID)) + } + s.logger.Debug("handleMsgSysSetStageBinary Done!") +} + +func handleMsgSysGetStageBinary(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysGetStageBinary) + + // Try to get the stage + stageID := stripNullTerminator(pkt.StageID) + s.server.stagesLock.Lock() + stage, gotStage := s.server.stages[stageID] + s.server.stagesLock.Unlock() + + // If we got the stage, lock and try to get the data. + var stageBinary []byte + var gotBinary bool + if gotStage { + stage.Lock() + stageBinary, gotBinary = stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}] + stage.Unlock() + } else { + s.logger.Warn("Failed to get stage", zap.String("StageID", stageID)) + } + + if gotBinary { + doSizedAckResp(s, pkt.AckHandle, stageBinary) + } else { + s.logger.Warn("Failed to get stage binary", zap.Uint8("BinaryType0", pkt.BinaryType0), zap.Uint8("pkt.BinaryType1", pkt.BinaryType1)) + s.logger.Warn("Sending blank stage binary") + doSizedAckResp(s, pkt.AckHandle, []byte{}) + } + + s.logger.Debug("MsgSysGetStageBinary Done!") +} + +func handleMsgSysEnumerateClient(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysEnumerateClient) + + // Read-lock the stages map. + s.server.stagesLock.RLock() + + stage, ok := s.server.stages[stripNullTerminator(pkt.StageID)] + if !ok { + s.logger.Fatal("Can't enumerate clients for stage that doesn't exist!", zap.String("stageID", pkt.StageID)) + } + + // Unlock the stages map. + s.server.stagesLock.RUnlock() + + // Read-lock the stage and make the response with all of the charID's in the stage. + resp := byteframe.NewByteFrame() + stage.RLock() + + // TODO(Andoryuuta): Add proper player-slot reservations for stages. + if len(stage.clients) >= 1 { + resp.WriteUint16(uint16(len(stage.clients))) // Client count + for session := range stage.clients { + resp.WriteUint32(session.charID) // Client represented by charID + } + } else { + // Just give our client. + resp.WriteUint16(1) + resp.WriteUint32(s.charID) + } + + stage.RUnlock() + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) + s.logger.Debug("MsgSysEnumerateClient Done!") +} + +func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysEnumerateStage) + + // Read-lock the stages. + s.server.stagesLock.RLock() + defer s.server.stagesLock.RUnlock() + + // Build the response + resp := byteframe.NewByteFrame() + resp.WriteUint16(uint16(len(s.server.stages))) + for sid := range s.server.stages { + // Found parsing code, field sizes are correct, but unknown purposes still. + //resp.WriteBytes([]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04, 0x00}) + resp.WriteUint16(5) // Current players. + resp.WriteUint16(7) // Unknown value + resp.WriteUint16(0) // HasDeparted. + resp.WriteUint16(20) // Max players. + resp.WriteUint8(2) // Password protected. + resp.WriteUint8(uint8(len(sid))) + resp.WriteBytes([]byte(sid)) + } + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) + s.logger.Debug("handleMsgSysEnumerateStage Done!") +} + +func handleMsgSysCreateMutex(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysCreateOpenMutex(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysDeleteMutex(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysOpenMutex(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysCloseMutex(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReleaseSemaphore(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysLockGlobalSema(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysUnlockGlobalSema(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysLoadRegister(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysNotifyRegister(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysCreateObject(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysCreateObject) + + // Make sure we have a stage. + if s.stage == nil { + s.logger.Fatal("StageID not in the stages map!", zap.String("stageID", s.stageID)) + } + + // Lock the stage. + s.stage.Lock() + + // Make a new stage object and insert it into the stage. + objID := s.stage.gameObjectCount + s.stage.gameObjectCount++ + + newObj := &StageObject{ + id: objID, + ownerCharID: s.charID, + x: pkt.X, + y: pkt.Y, + z: pkt.Z, + } + + s.stage.objects[objID] = newObj + + // Unlock the stage. + s.stage.Unlock() + + // Response to our requesting client. + resp := byteframe.NewByteFrame() + resp.WriteUint32(0) // Unk, is this echoed back from pkt.Unk0? + resp.WriteUint32(objID) // New local obj handle. + s.QueueAck(pkt.AckHandle, resp.Data()) + + // Duplicate the object creation to all sessions in the same stage. + dupObjUpdate := &mhfpacket.MsgSysDuplicateObject{ + ObjID: objID, + X: pkt.X, + Y: pkt.Y, + Z: pkt.Z, + Unk0: 0, + OwnerCharID: s.charID, + } + s.stage.BroadcastMHF(dupObjUpdate, s) +} + +func handleMsgSysDeleteObject(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysPositionObject(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysPositionObject) + fmt.Printf("Moved object %v to (%f,%f,%f)\n", pkt.ObjID, pkt.X, pkt.Y, pkt.Z) + + // One of the few packets we can just re-broadcast directly. + s.stage.BroadcastMHF(pkt, s) +} + +func handleMsgSysRotateObject(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysDuplicateObject(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) { + +} + +func handleMsgSysGetObjectBinary(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysGetObjectOwner(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysUpdateObjectBinary(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysCleanupObject(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve4A(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve4B(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve4C(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve4D(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve4E(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve4F(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysInsertUser(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysDeleteUser(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysSetUserBinary) + s.server.userBinaryPartsLock.Lock() + s.server.userBinaryParts[userBinaryPartID{charID: s.charID, index: pkt.BinaryType}] = pkt.RawDataPayload + s.server.userBinaryPartsLock.Unlock() +} + +func handleMsgSysGetUserBinary(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysGetUserBinary) + + // Try to get the data. + s.server.userBinaryPartsLock.RLock() + defer s.server.userBinaryPartsLock.RUnlock() + data, ok := s.server.userBinaryParts[userBinaryPartID{charID: pkt.CharID, index: pkt.BinaryType}] + + resp := byteframe.NewByteFrame() + + // If we can't get the real data, use a placeholder. + if !ok { + if pkt.BinaryType == 1 { + // Stub name response with character ID + resp.WriteBytes([]byte(fmt.Sprintf("CID%d", s.charID))) + resp.WriteUint8(0) // NULL terminator. + } else if pkt.BinaryType == 2 { + data, err := base64.StdEncoding.DecodeString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBn8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAwAAAAAAAAAAAAAABAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") + if err != nil { + panic(err) + } + resp.WriteBytes(data) + } else if pkt.BinaryType == 3 { + data, err := base64.StdEncoding.DecodeString("AQAAA2ea5P8ATgEA/wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBn8AAAAAAAAAAAABAKAMAAAAAAAAAAAAACgAAAAAAAAAAAABAsQOAAAAAAAAAAABA6UMAAAAAAAAAAABBKAMAAAAAAAAAAABBToNAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAgACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") + if err != nil { + panic(err) + } + resp.WriteBytes(data) + } + } else { + resp.WriteBytes(data) + } + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgSysNotifyUserBinary(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve55(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve56(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve57(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysUpdateRight(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysAuthQuery(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysAuthData(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysAuthTerminal(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve5C(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysRightsReload(s *Session, p mhfpacket.MHFPacket) { + +} + +func handleMsgSysReserve5E(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve5F(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfSavedata) + err := ioutil.WriteFile(fmt.Sprintf("savedata\\%d.bin", time.Now().Unix()), pkt.RawDataPayload, 0644) + if err != nil { + s.logger.Fatal("Error dumping savedata", zap.Error(err)) + } + + _, err = s.server.db.Exec("UPDATE characters SET is_new_character=false, savedata=$1 WHERE id=$2", pkt.RawDataPayload, s.charID) + if err != nil { + s.logger.Fatal("Failed to update savedata in db", zap.Error(err)) + } + + s.QueueAck(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoaddata) + + var data []byte + err := s.server.db.QueryRow("SELECT savedata FROM characters WHERE id = $1", s.charID).Scan(&data) + if err != nil { + s.logger.Fatal("Failed to get savedata from db", zap.Error(err)) + } + + doSizedAckResp(s, pkt.AckHandle, data) +} + +func handleMsgMhfListMember(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfListMember) + + resp := byteframe.NewByteFrame() + resp.WriteUint32(0) // Members count. (Unsure of what kind of members these actually are, guild, party, COG subscribers, etc.) + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfOprMember(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetDistDescription(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSendMail(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadFavoriteQuest) + // TODO(Andoryuuta): Save data from MsgMhfSaveFavoriteQuest and resend it here. + doSizedAckResp(s, pkt.AckHandle, []byte{}) +} + +func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReleaseEvent(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve71(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve72(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve73(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve74(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve75(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve76(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve77(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve78(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve79(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve7A(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve7B(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve7C(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgCaExchangeItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve7E(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPresentBox(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfServerCommand(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfShutClient(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAnnounce(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSetLoginwindow(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysTransBinary(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysCollectBinary(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysGetState(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysSerialize(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysEnumlobby(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysEnumuser(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysInfokyserver(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetCaUniqueID(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSetCaAchievement(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCaravanMyScore(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCaravanRanking(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCaravanMyRank(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCreateGuild(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfOperateGuild(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfOperateGuildMember(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfInfoGuild) + + // REALLY large/complex format... stubbing it out here for simplicity. + resp := byteframe.NewByteFrame() + resp.WriteUint32(0) // Count + resp.WriteUint8(0) // Unk, read if count == 0. + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateGuild(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfArrangeGuildMember(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEnumerateGuildMember) + stubEnumerateNoResults(s, pkt.AckHandle) +} + +func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfStateCampaign(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfApplyCampaign(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfTransferItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfMercenaryHuntdata(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEntryRookieGuild(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEnumerateQuest) + stubEnumerateNoResults(s, pkt.AckHandle) + + // Update the client's rights as well: + updateRights(s) +} + +func handleMsgMhfEnumerateEvent(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEnumerateEvent) + stubEnumerateNoResults(s, pkt.AckHandle) +} + +func handleMsgMhfEnumeratePrice(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEnumeratePrice) + resp := byteframe.NewByteFrame() + resp.WriteUint16(0) // Entry type 1 count + resp.WriteUint16(0) // Entry type 2 count + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfEnumerateRanking(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEnumerateRanking) + + resp := byteframe.NewByteFrame() + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint8(0) + resp.WriteUint8(0) // Some string length following this field. + resp.WriteUint16(0) // Entry type 1 count + resp.WriteUint8(0) // Entry type 2 count + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) + + // Update the client's rights as well: + updateRights(s) +} + +func handleMsgMhfEnumerateOrder(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEnumerateOrder) + stubEnumerateNoResults(s, pkt.AckHandle) +} + +func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEnumerateShop) + stubEnumerateNoResults(s, pkt.AckHandle) +} + +func handleMsgMhfGetExtraInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateWarehouse(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateWarehouse(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateGuildItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateUnionItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateUnionItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCreateJoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateGuildIcon(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfInfoFesta) + + // REALLY large/complex format... stubbing it out here for simplicity. + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfEntryFesta(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfChargeFesta(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireFesta(s *Session, p mhfpacket.MHFPacket) {} + +// state festa (U)ser +func handleMsgMhfStateFestaU(s *Session, p mhfpacket.MHFPacket) {} + +// state festa (G)uild +func handleMsgMhfStateFestaG(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfStateFestaG) + + resp := byteframe.NewByteFrame() + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0xFFFFFFFF) + resp.WriteUint32(0) + resp.WriteBytes([]byte{0x00, 0x00, 0x00}) // Not parsed. + resp.WriteUint8(0) + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfVoteFesta(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireCafeItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateCafepoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetCogInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCheckMonthlyItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireMonthlyItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfCheckWeeklyStamp) + + resp := byteframe.NewByteFrame() + resp.WriteUint16(0x0100) + resp.WriteUint16(0x000E) + resp.WriteUint16(0x0001) + resp.WriteUint16(0x0000) + resp.WriteUint16(0x0001) + resp.WriteUint32(0) + resp.WriteUint32(0x5dddcbb3) // Timestamp + + s.QueueAck(pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCreateMercenary(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSaveMercenary(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReadMercenaryW(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfReadMercenaryW) + + // Unk format: + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfReadMercenaryM(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfContractMercenary(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateMercenaryLog(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfInfoTournament(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEntryTournament(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnterTournamentQuest(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireTournament(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetAchievement(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfResetAchievement(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAddAchievement(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPaymentAchievement(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfDisplayedAchievement(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) { + + pkt := p.(*mhfpacket.MsgMhfInfoScenarioCounter) + + scenarioCounter := []struct { + Unk0 uint32 // Main ID? + Unk1 uint8 + Unk2 uint8 + }{ + { + Unk0: 0x00000000, + Unk1: 1, + Unk2: 4, + }, + { + Unk0: 0x00000001, + Unk1: 1, + Unk2: 4, + }, + { + Unk0: 0x00000002, + Unk1: 1, + Unk2: 4, + }, + { + Unk0: 0x00000003, + Unk1: 1, + Unk2: 4, + }, + } + + resp := byteframe.NewByteFrame() + resp.WriteUint8(uint8(len(scenarioCounter))) // Entry count + for _, entry := range scenarioCounter { + resp.WriteUint32(entry.Unk0) + resp.WriteUint8(entry.Unk1) + resp.WriteUint8(entry.Unk2) + } + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) + + // DEBUG, DELETE ME! + /* + data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "debug/info_scenario_counter_resp.bin")) + if err != nil { + panic(err) + } + + doSizedAckResp(s, pkt.AckHandle, data) + */ + +} + +func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfSaveScenarioData) + s.QueueAck(pkt.AckHandle, []byte{0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40}) +} + +func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadScenarioData) + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfGetBbsSnsStatus(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfApplyBbsArticle(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetEtcPoints) + + resp := byteframe.NewByteFrame() + resp.WriteUint8(0x3) // Maybe a count of uint32(s)? + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfUpdateEtcPoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule) + + eventSchedules := []struct { + StartTime time.Time + Unk0 uint32 // Event ID? + Unk1 uint16 + }{ + { + StartTime: time.Now().Add(time.Duration(-5) * time.Minute), // Event started 5 minutes ago. + Unk0: 4, + Unk1: 0, + }, + } + + resp := byteframe.NewByteFrame() + resp.WriteUint8(uint8(len(eventSchedules))) // Entry count, client only parses the first 7 or 8. + resp.WriteUint32(uint32(time.Now().Unix())) // Current server time + for _, es := range eventSchedules { + resp.WriteUint32(uint32(es.StartTime.Unix())) + resp.WriteUint32(es.Unk0) + resp.WriteUint16(es.Unk1) + } + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfEnumerateInvGuild(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfOperationInvGuild(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfStampcardPrize(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUnreserveSrg(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadPlateData(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadPlateData) + + // TODO(Andoryuuta): Save data from MsgMhfSavePlateData and resend it here. + doSizedAckResp(s, pkt.AckHandle, []byte{}) +} + +func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadPlateBox(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadPlateBox) + // TODO(Andoryuuta): Save data from MsgMhfSavePlateBox and resend it here. + doSizedAckResp(s, pkt.AckHandle, []byte{}) +} + +func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReadGuildcard(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfReadGuildcard) + + resp := byteframe.NewByteFrame() + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfUpdateGuildcard(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReadBeatLevel(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfReadBeatLevel) + + // This response is fixed and will never change on JP, + // but I've left it dynamic for possible other client differences. + resp := byteframe.NewByteFrame() + for i := 0; i < int(pkt.ValidIDCount); i++ { + resp.WriteUint32(pkt.IDs[i]) + resp.WriteUint32(1) + resp.WriteUint32(1) + resp.WriteUint32(1) + } + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfUpdateBeatLevel(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReadBeatLevelAllRanking(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReadBeatLevelMyRanking(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReadLastWeekBeatRanking(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcceptReadReward(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetAdditionalBeatReward(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetFixedSeibatuRankingTable(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetBbsUserStatus(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfKickExportForce(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetBreakSeibatuLevelReward(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetWeeklySeibatuRankingReward(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetEarthStatus) + + // TODO(Andoryuuta): Track down format for this data, + // it can somehow be parsed as 8*uint32 chunks if the header is right. + resp := byteframe.NewByteFrame() + resp.WriteUint32(0) + resp.WriteUint32(0) + + s.QueueAck(pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfLoadPartner(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadPartner) + + // TODO(Andoryuuta): Figure out unusual double ack. One sized, one not. + + // TODO(Andoryuuta): Save data from MsgMhfSavePartner and resend it here. + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) + s.QueueAck(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfSavePartner(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfSavePartner) + s.QueueAck(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfGetGuildMissionList(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetGuildMissionRecord(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAddGuildMissionCount(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSetGuildMissionTarget(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCancelGuildMissionTarget(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadOtomoAirou(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadOtomoAirou) + + // TODO(Andoryuuta): Save data from MsgMhfSaveOtomoAirou and resend it here. + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateAiroulist(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireGuildTresure(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfOperateGuildTresureReport(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireFestaIntermediatePrize(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadDecoMyset) + + // TODO(Andoryuuta): Save data from MsgMhfSaveDecoMyset and resend it here. + doSizedAckResp(s, pkt.AckHandle, []byte{0x01, 0x00}) +} + +func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReserve010F(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadGuildAdventure(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfRegistGuildAdventure(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireGuildAdventure(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfChargeGuildAdventure(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadLegendDispatch(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadHunterNavi(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadHunterNavi) + // TODO(Andoryuuta): Save data from MsgMhfSaveHunterNavi and resend it here. + blankData := make([]byte, 0x228) + doSizedAckResp(s, pkt.AckHandle, blankData) +} + +func handleMsgMhfSaveHunterNavi(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfRegistSpabiTime(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetGuildWeeklyBonusMaster(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetGuildWeeklyBonusActiveCount(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAddGuildWeeklyBonusExceptionalUser(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetTowerInfo) + + /* + type: + 1 == TOWER_RANK_POINT, + 2 == GET_OWN_TOWER_SKILL + 3 == ? + 4 == TOWER_TOUHA_HISTORY + 5 = ? + + [] = type + req + resp + + 01 1d 01 fc 00 09 [00 00 00 01] 00 00 00 02 00 00 00 00 + 00 12 01 fc 00 09 01 00 00 18 0a 21 8e ad 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 + + 01 1d 01 fc 00 0a [00 00 00 02] 00 00 00 00 00 00 00 00 + 00 12 01 fc 00 0a 01 00 00 94 0a 21 8e ad 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + 01 1d 01 ff 00 0f [00 00 00 04] 00 00 00 00 00 00 00 00 + 00 12 01 ff 00 0f 01 00 00 24 0a 21 8e ad 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + 01 1d 01 fc 00 0b [00 00 00 05] 00 00 00 00 00 00 00 00 + 00 12 01 fc 00 0b 01 00 00 10 0a 21 8e ad 00 00 00 00 00 00 00 00 00 00 00 00 + */ + /* + switch pkt.InfoType { + case mhfpacket.TowerInfoTypeTowerRankPoint: + case mhfpacket.TowerInfoTypeGetOwnTowerSkill: + case mhfpacket.TowerInfoTypeUnk3: + panic("No known response values for TowerInfoTypeUnk3") + case mhfpacket.TowerInfoTypeTowerTouhaHistory: + case mhfpacket.TowerInfoTypeUnk5: + } + */ + + stubGetNoResults(s, pkt.AckHandle) +} + +func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetEarthValue(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetEarthValue) + + earthValues := []struct { + Unk0, Unk1, Unk2, Unk3, Unk4, Unk5 uint32 + }{ + { + Unk0: 0x03E9, + Unk1: 0x5B, + }, + { + Unk0: 0x2329, + Unk1: 0x03, + }, + { + Unk0: 0x232A, + Unk1: 0x0A, + Unk2: 0x012C, + }, + } + + resp := byteframe.NewByteFrame() + resp.WriteUint32(0x0A218EAD) // Unk shared ID. Sent in response of MSG_MHF_GET_TOWER_INFO, MSG_MHF_GET_PAPER_DATA etc. + resp.WriteUint32(0) // Unk + resp.WriteUint32(0) // Unk + resp.WriteUint32(uint32(len(earthValues))) // value count + for _, v := range earthValues { + resp.WriteUint32(v.Unk0) + resp.WriteUint32(v.Unk1) + resp.WriteUint32(v.Unk2) + resp.WriteUint32(v.Unk3) + resp.WriteUint32(v.Unk4) + resp.WriteUint32(v.Unk5) + } + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfDebugPostValue(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetPaperData(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetPaperData) + stubGetNoResults(s, pkt.AckHandle) +} + +func handleMsgMhfGetNotice(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPostNotice(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetBoostTime(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetBoostTime) + doSizedAckResp(s, pkt.AckHandle, []byte{}) + + // Update the client's rights as well: + updateRights(s) +} + +func handleMsgMhfPostBoostTime(s *Session, p mhfpacket.MHFPacket) { + //pkt := p.(*mhfpacket.MsgMhfPostBoostTime) +} + +func handleMsgMhfGetBoostTimeLimit(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetBoostTimeLimit) + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfPostBoostTimeLimit(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetRandFromTable(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetCafeDurationBonusInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReceiveCafeDurationBonus(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPostCafeDurationBonusReceived(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetGachaPoint(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetGachaPoint) + doSizedAckResp(s, pkt.AckHandle, []byte{}) +} + +func handleMsgMhfUseGachaPoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfExchangeFpoint2Item(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfExchangeItem2Fpoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetFpointExchangeList(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfReceiveGachaItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetStepupStatus(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPlayFreeGacha(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetTinyBin(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPostTinyBin(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetSenyuDailyCount(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetGuildTargetMemberNum(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetBoostRight(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetBoostRight) + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfStartBoostTime(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPostBoostTimeQuestReturn(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfPostBoostTimeQuestReturn) + s.QueueAck(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfGetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPlayBoxGacha(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfResetBoxGachaInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetSeibattle) + stubGetNoResults(s, pkt.AckHandle) +} + +func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetRyoudama(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPostRyoudama(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPostTenrouirai(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfCancelGuildScout(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAnswerGuildScout(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSetGuildManageRight(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfPlayNormalGacha(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetDailyMissionMaster(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetGachaPlayHistory(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSetRejectGuildScout(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetCaAchievementHist(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSetCaAchievementHist(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetKeepLoginBoostStatus) + + unkRespFields := [5]struct { + U0, U1, U2 uint8 + U3 uint32 + }{ + { + U0: 1, + U1: 1, + U2: 1, + U3: 0, + }, + { + U0: 2, + U1: 0, + U2: 1, + U3: 0, + }, + { + U0: 3, + U1: 0, + U2: 1, + U3: 0, + }, + { + U0: 4, + U1: 0, + U2: 1, + U3: 0, + }, + { + U0: 5, + U1: 0, + U2: 1, + U3: 0, + }, + } + + resp := byteframe.NewByteFrame() + for _, v := range unkRespFields { + resp.WriteUint8(v.U0) + resp.WriteUint8(v.U1) + resp.WriteUint8(v.U2) + resp.WriteUint32(v.U3) + } + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetUdSchedule) + + resp := byteframe.NewByteFrame() + resp.WriteUint32(0x0b5397df) // Unk + resp.WriteUint32(0x5ddde6b0) // Timestamp + resp.WriteUint32(0x5de71320) // Timestamp + resp.WriteUint32(0x5de7225c) // Timestamp + resp.WriteUint32(0x5df04da0) // Timestamp + resp.WriteUint32(0x5df05cdc) // Timestamp + resp.WriteUint32(0x5dfa30e0) // Timestamp + resp.WriteUint16(0x19) // Unk + resp.WriteUint16(0x2d) // Unk + resp.WriteUint16(0x02) // Unk + resp.WriteUint16(0x02) // Unk + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfGetUdInfo(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetUdInfo) + + udInfos := []struct { + Text string + StartTime time.Time + EndTime time.Time + }{ + { + Text: " ~C17【Erupe】 launch event!\n\n■Features\n~C18 Walk around!\n~C17 Crash your connection by doing nearly anything!", + StartTime: time.Now().Add(time.Duration(-5) * time.Minute), // Event started 5 minutes ago, + EndTime: time.Now().Add(time.Duration(5) * time.Minute), // Event ends in 5 minutes, + }, + } + + resp := byteframe.NewByteFrame() + resp.WriteUint8(uint8(len(udInfos))) + for _, udInfo := range udInfos { + resp.WriteBytes(fixedSizeShiftJIS(udInfo.Text, 1024)) + resp.WriteUint32(uint32(udInfo.StartTime.Unix())) + resp.WriteUint32(uint32(udInfo.EndTime.Unix())) + } + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfGetKijuInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSetKiju(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAddUdPoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdMyPoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdTotalPointInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdBonusQuestInfo(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetUdBonusQuestInfo) + + udBonusQuestInfos := []struct { + Unk0 uint8 + Unk1 uint8 + StartTime uint32 // Unix timestamp (seconds) + EndTime uint32 // Unix timestamp (seconds) + Unk4 uint32 + Unk5 uint8 + Unk6 uint8 + }{} // Blank stub array. + + resp := byteframe.NewByteFrame() + resp.WriteUint8(uint8(len(udBonusQuestInfos))) + for _, q := range udBonusQuestInfos { + resp.WriteUint8(q.Unk0) + resp.WriteUint8(q.Unk1) + resp.WriteUint32(q.StartTime) + resp.WriteUint32(q.EndTime) + resp.WriteUint32(q.Unk4) + resp.WriteUint8(q.Unk5) + resp.WriteUint8(q.Unk6) + } + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfGetUdSelectedColorInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdMonsterPoint(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetUdMonsterPoint) + + monsterPoints := []struct { + MID uint8 // Monster ID ? + Points uint16 + }{ + {MID: 0x01, Points: 0x3C}, + {MID: 0x02, Points: 0x5A}, + {MID: 0x06, Points: 0x14}, + {MID: 0x07, Points: 0x50}, + {MID: 0x08, Points: 0x28}, + {MID: 0x0B, Points: 0x3C}, + {MID: 0x0E, Points: 0x3C}, + {MID: 0x0F, Points: 0x46}, + {MID: 0x11, Points: 0x46}, + {MID: 0x14, Points: 0x28}, + {MID: 0x15, Points: 0x3C}, + {MID: 0x16, Points: 0x32}, + {MID: 0x1A, Points: 0x32}, + {MID: 0x1B, Points: 0x0A}, + {MID: 0x1C, Points: 0x0A}, + {MID: 0x1F, Points: 0x0A}, + {MID: 0x21, Points: 0x50}, + {MID: 0x24, Points: 0x64}, + {MID: 0x25, Points: 0x3C}, + {MID: 0x26, Points: 0x1E}, + {MID: 0x27, Points: 0x28}, + {MID: 0x28, Points: 0x50}, + {MID: 0x29, Points: 0x5A}, + {MID: 0x2A, Points: 0x50}, + {MID: 0x2B, Points: 0x3C}, + {MID: 0x2C, Points: 0x3C}, + {MID: 0x2D, Points: 0x46}, + {MID: 0x2E, Points: 0x3C}, + {MID: 0x2F, Points: 0x50}, + {MID: 0x30, Points: 0x1E}, + {MID: 0x31, Points: 0x3C}, + {MID: 0x32, Points: 0x50}, + {MID: 0x33, Points: 0x3C}, + {MID: 0x34, Points: 0x28}, + {MID: 0x35, Points: 0x50}, + {MID: 0x36, Points: 0x6E}, + {MID: 0x37, Points: 0x50}, + {MID: 0x3A, Points: 0x50}, + {MID: 0x3B, Points: 0x6E}, + {MID: 0x40, Points: 0x64}, + {MID: 0x41, Points: 0x6E}, + {MID: 0x43, Points: 0x28}, + {MID: 0x44, Points: 0x0A}, + {MID: 0x47, Points: 0x6E}, + {MID: 0x4A, Points: 0xFA}, + {MID: 0x4B, Points: 0xFA}, + {MID: 0x4C, Points: 0x46}, + {MID: 0x4D, Points: 0x64}, + {MID: 0x4E, Points: 0xFA}, + {MID: 0x4F, Points: 0xFA}, + {MID: 0x50, Points: 0xFA}, + {MID: 0x51, Points: 0xFA}, + {MID: 0x52, Points: 0xFA}, + {MID: 0x53, Points: 0xFA}, + {MID: 0x54, Points: 0xFA}, + {MID: 0x55, Points: 0xFA}, + {MID: 0x59, Points: 0xFA}, + {MID: 0x5A, Points: 0xFA}, + {MID: 0x5B, Points: 0xFA}, + {MID: 0x5C, Points: 0xFA}, + {MID: 0x5E, Points: 0xFA}, + {MID: 0x5F, Points: 0xFA}, + {MID: 0x60, Points: 0xFA}, + {MID: 0x63, Points: 0xFA}, + {MID: 0x65, Points: 0xFA}, + {MID: 0x67, Points: 0xFA}, + {MID: 0x68, Points: 0xFA}, + {MID: 0x69, Points: 0xFA}, + {MID: 0x6A, Points: 0xFA}, + {MID: 0x6B, Points: 0xFA}, + {MID: 0x6C, Points: 0xFA}, + {MID: 0x6D, Points: 0xFA}, + {MID: 0x6E, Points: 0xFA}, + {MID: 0x6F, Points: 0xFA}, + {MID: 0x70, Points: 0xFA}, + {MID: 0x72, Points: 0xFA}, + {MID: 0x73, Points: 0xFA}, + {MID: 0x74, Points: 0xFA}, + {MID: 0x77, Points: 0xFA}, + {MID: 0x78, Points: 0xFA}, + {MID: 0x79, Points: 0xFA}, + {MID: 0x7A, Points: 0xFA}, + {MID: 0x7B, Points: 0xFA}, + {MID: 0x7D, Points: 0xFA}, + {MID: 0x7E, Points: 0xFA}, + {MID: 0x7F, Points: 0xFA}, + {MID: 0x80, Points: 0xFA}, + {MID: 0x81, Points: 0xFA}, + {MID: 0x82, Points: 0xFA}, + {MID: 0x83, Points: 0xFA}, + {MID: 0x8B, Points: 0xFA}, + {MID: 0x8C, Points: 0xFA}, + {MID: 0x8D, Points: 0xFA}, + {MID: 0x8E, Points: 0xFA}, + {MID: 0x90, Points: 0xFA}, + {MID: 0x92, Points: 0x78}, + {MID: 0x93, Points: 0x78}, + {MID: 0x94, Points: 0x78}, + {MID: 0x96, Points: 0xFA}, + {MID: 0x97, Points: 0x78}, + {MID: 0x98, Points: 0x78}, + {MID: 0x99, Points: 0x78}, + {MID: 0x9A, Points: 0xFA}, + {MID: 0x9E, Points: 0xFA}, + {MID: 0x9F, Points: 0x78}, + {MID: 0xA0, Points: 0xFA}, + {MID: 0xA1, Points: 0xFA}, + {MID: 0xA2, Points: 0x78}, + {MID: 0xA4, Points: 0x78}, + {MID: 0xA5, Points: 0x78}, + {MID: 0xA6, Points: 0xFA}, + {MID: 0xA9, Points: 0x78}, + {MID: 0xAA, Points: 0xFA}, + } + + resp := byteframe.NewByteFrame() + resp.WriteUint8(uint8(len(monsterPoints))) + for _, mp := range monsterPoints { + resp.WriteUint8(mp.MID) + resp.WriteUint16(mp.Points) + } + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfGetUdDailyPresentList(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdNormaPresentList(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdRankingRewardList(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireUdItem(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetRewardSong(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUseRewardSong(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAddRewardSongCount(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdRanking(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdMyRanking(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAcquireMonthlyReward(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfAcquireMonthlyReward) + + resp := byteframe.NewByteFrame() + resp.WriteUint32(0) + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfGetUdGuildMapInfo(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGenerateUdGuildMap(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdTacticsPoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAddUdTacticsPoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdTacticsRanking(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdTacticsRewardList(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdTacticsLog(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdTacticsFollower(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetUdTacticsFollower) + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfSetUdTacticsFollower(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdShopCoin(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUseUdShopCoin(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetEnhancedMinidata) + doSizedAckResp(s, pkt.AckHandle, []byte{0x00}) +} + +func handleMsgMhfSetEnhancedMinidata(s *Session, p mhfpacket.MHFPacket) { + +} + +func handleMsgMhfSexChanger(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetLobbyCrowd(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve180(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfAddKouryouPoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetKouryouPoint(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetKouryouPoint) + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfExchangeKouryouPoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdTacticsBonusQuest(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdTacticsFirstQuestBonus(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetUdTacticsRemainingPoint(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve188(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysReserve188) + + // Left as raw bytes because I couldn't easily find the request or resp parser function in the binary. + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfLoadPlateMyset(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadPlateMyset) + // TODO(Andoryuuta): Save data from MsgMhfSavePlateMyset and resend it here. + blankData := make([]byte, 0x780) + doSizedAckResp(s, pkt.AckHandle, blankData) +} + +func handleMsgMhfSavePlateMyset(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve18B(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysReserve18B) + + // Left as raw bytes because I couldn't easily find the request or resp parser function in the binary. + doSizedAckResp(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x3C}) + +} + +func handleMsgMhfGetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve18E(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve18F(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetTrendWeapon(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateUseTrendWeaponLog(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfUpdateUseTrendWeaponLog) + s.QueueAck(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgSysReserve192(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve193(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve194(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSaveRengokuData(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfLoadRengokuData(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadRengokuData) + + resp := byteframe.NewByteFrame() + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint16(0) + resp.WriteUint32(0) + resp.WriteUint16(0) + resp.WriteUint16(0) + resp.WriteUint32(0) + + resp.WriteUint8(3) // Count of next 3 + resp.WriteUint16(0) + resp.WriteUint16(0) + resp.WriteUint16(0) + + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + + resp.WriteUint8(3) // Count of next 3 + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + + resp.WriteUint8(3) // Count of next 3 + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + resp.WriteUint32(0) + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) + +} + +func handleMsgMhfGetRengokuBinary(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfEnumerateRengokuRanking(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfGetRengokuRankingRank(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetRengokuRankingRank) + + resp := byteframe.NewByteFrame() + resp.WriteBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve19B(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfSaveMezfesData(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfSaveMezfesData) + s.QueueAck(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +} + +func handleMsgMhfLoadMezfesData(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfLoadMezfesData) + + resp := byteframe.NewByteFrame() + resp.WriteUint32(0) // Unk + + resp.WriteUint8(2) // Count of the next 2 uint32s + resp.WriteUint32(0) + resp.WriteUint32(0) + + resp.WriteUint32(0) // Unk + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgSysReserve19E(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve19F(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfUpdateForceGuildRank(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgMhfResetTitle(s *Session, p mhfpacket.MHFPacket) {} + +// "Enumrate_guild_msg_board" +func handleMsgSysReserve202(s *Session, p mhfpacket.MHFPacket) { +} + +// "Is_update_guild_msg_board" +func handleMsgSysReserve203(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysReserve203) + resp := make([]byte, 8) // Unk resp. + s.QueueAck(pkt.AckHandle, resp) +} + +func handleMsgSysReserve204(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve205(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve206(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve207(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve208(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve209(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve20A(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve20B(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve20C(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve20D(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve20E(s *Session, p mhfpacket.MHFPacket) {} + +func handleMsgSysReserve20F(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/session.go b/server/channelserver/session.go new file mode 100644 index 000000000..002d04c93 --- /dev/null +++ b/server/channelserver/session.go @@ -0,0 +1,167 @@ +package channelserver + +import ( + "encoding/hex" + "fmt" + "net" + "sync" + + "github.com/Andoryuuta/Erupe/common/stringstack" + "github.com/Andoryuuta/Erupe/network" + "github.com/Andoryuuta/Erupe/network/mhfpacket" + "github.com/Andoryuuta/byteframe" + "go.uber.org/zap" +) + +// Session holds state for the channel server connection. +type Session struct { + sync.Mutex + logger *zap.Logger + server *Server + rawConn net.Conn + cryptConn *network.CryptConn + sendPackets chan []byte + + stageID string + stage *Stage + charID uint32 + logKey []byte + + // A stack containing the stage movement history (push on enter/move, pop on back) + stageMoveStack *stringstack.StringStack +} + +// 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 []byte, 20), + stageMoveStack: stringstack.New(), + } + return s +} + +// Start starts the session packet send and recv loop(s). +func (s *Session) Start() { + go func() { + s.logger.Info("Channel server got connection!", zap.String("remoteaddr", s.rawConn.RemoteAddr().String())) + + // Unlike the sign and entrance server, + // the client DOES NOT initalize the channel connection with 8 NULL bytes. + go s.sendLoop() + s.recvLoop() + }() +} + +// QueueSend queues a packet (raw []byte) to be sent. +func (s *Session) QueueSend(data []byte) { + s.sendPackets <- data +} + +// 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. + 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") + } +} + +// QueueSendMHF queues a MHFPacket to be sent. +func (s *Session) QueueSendMHF(pkt mhfpacket.MHFPacket) { + // Make the header + bf := byteframe.NewByteFrame() + bf.WriteUint16(uint16(pkt.Opcode())) + + // Build the packet onto the byteframe. + pkt.Build(bf) + + // Queue it. + s.QueueSend(bf.Data()) +} + +// QueueAck is a helper function to queue an MSG_SYS_ACK with the given ack handle and data. +func (s *Session) QueueAck(ackHandle uint32, data []byte) { + bf := byteframe.NewByteFrame() + bf.WriteUint16(uint16(network.MSG_SYS_ACK)) + bf.WriteUint32(ackHandle) + bf.WriteBytes(data) + s.QueueSend(bf.Data()) +} + +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") + 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) + } +} + +func (s *Session) recvLoop() { + for { + pkt, err := s.cryptConn.ReadPacket() + if err != nil { + s.logger.Warn("Error on ReadPacket, exiting recv loop", zap.Error(err)) + return + } + + s.handlePacketGroup(pkt) + } +} + +func (s *Session) handlePacketGroup(pktGroup []byte) { + // This shouldn't be needed, but it's better to recover and let the connection die than to panic the server. + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovered from panic ", r) + } + }() + + bf := byteframe.NewByteFrameFromBytes(pktGroup) + opcode := network.PacketID(bf.ReadUint16()) + + // Print any (non-common spam) packet opcodes and data. + if opcode != network.MSG_SYS_END && + opcode != network.MSG_SYS_PING && + opcode != network.MSG_SYS_NOP && + opcode != network.MSG_SYS_TIME && + opcode != network.MSG_SYS_EXTEND_THRESHOLD { + fmt.Printf("Opcode: %s\n", opcode) + fmt.Printf("Data:\n%s\n", hex.Dump(pktGroup)) + } + + // Get the packet parser and handler for this opcode. + mhfPkt := mhfpacket.FromOpcode(opcode) + if mhfPkt == nil { + fmt.Println("Got opcode which we don't know how to parse, can't parse anymore for this group") + return + } + + // Parse and handle the packet + mhfPkt.Parse(bf) + handlerTable[opcode](s, mhfPkt) + + // If there is more data on the stream that the .Parse method didn't read, then read another packet off it. + remainingData := bf.DataFromCurrent() + if len(remainingData) >= 2 { + s.handlePacketGroup(remainingData) + } +} diff --git a/server/channelserver/stage.go b/server/channelserver/stage.go new file mode 100644 index 000000000..1b996b1a1 --- /dev/null +++ b/server/channelserver/stage.go @@ -0,0 +1,63 @@ +package channelserver + +import ( + "sync" + + "github.com/Andoryuuta/Erupe/network/mhfpacket" + "github.com/Andoryuuta/byteframe" +) + +// StageObject holds infomation about a specific stage object. +type StageObject struct { + sync.RWMutex + id uint32 + ownerCharID uint32 + x, y, z float32 +} + +type stageBinaryKey struct { + id0 uint8 + id1 uint8 +} + +// Stage holds stage-specific information +type Stage struct { + sync.RWMutex + id string // Stage ID string + gameObjectCount uint32 // Total count of objects ever created for this stage. Used for ObjID generation. + objects map[uint32]*StageObject // Map of ObjID -> StageObject + clients map[*Session]uint32 // Map of session -> charID + rawBinaryData map[stageBinaryKey][]byte // Raw binary data set by the client. +} + +// NewStage creates a new stage with intialized values. +func NewStage(ID string) *Stage { + s := &Stage{ + id: ID, + objects: make(map[uint32]*StageObject), + clients: make(map[*Session]uint32), + rawBinaryData: make(map[stageBinaryKey][]byte), + gameObjectCount: 1, + } + + return s +} + +// BroadcastMHF queues a MHFPacket to be sent to all sessions in the stage. +func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { + // Make the header + bf := byteframe.NewByteFrame() + bf.WriteUint16(uint16(pkt.Opcode())) + + // Build the packet onto the byteframe. + pkt.Build(bf) + + // Broadcast the data. + for session := range s.clients { + if session == ignoredSession { + continue + } + // Enqueue in a non-blocking way that drops the packet if the connections send buffer channel is full. + session.QueueSendNonBlocking(bf.Data()) + } +} diff --git a/entranceserver/crypto.go b/server/entranceserver/crypto.go similarity index 81% rename from entranceserver/crypto.go rename to server/entranceserver/crypto.go index 7fec6b7c5..20a361e7e 100644 --- a/entranceserver/crypto.go +++ b/server/entranceserver/crypto.go @@ -6,23 +6,22 @@ import ( var ( _bin8Key = []byte{0x01, 0x23, 0x34, 0x45, 0x56, 0xAB, 0xCD, 0xEF} - _sum32Table0 = []byte{0x7A, 0xAA, 0x97, 0x53, 0x66, 0x12, 0xDE, 0xDE, 0x35} - _sum32Table1 = []byte{0x35, 0x7A, 0xAA, 0x97, 0x53, 0x66, 0x12} + _sum32Table0 = []byte{0x35, 0x7A, 0xAA, 0x97, 0x53, 0x66, 0x12} + _sum32Table1 = []byte{0x7A, 0xAA, 0x97, 0x53, 0x66, 0x12, 0xDE, 0xDE, 0x35} ) // CalcSum32 calculates the custom MHF "sum32" checksum of the given data. func CalcSum32(data []byte) uint32 { - tableIdx0 := byte(len(data) & 0xFF) - tableIdx1 := byte(data[len(data)>>1]) + tableIdx0 := int(len(data) & 0xFF) + tableIdx1 := int(data[len(data)>>1] & 0xFF) out := make([]byte, 4) for i := 0; i < len(data); i++ { tableIdx0++ tableIdx1++ - tmp := byte((_sum32Table0[tableIdx1%9] ^ _sum32Table1[tableIdx0%7]) ^ data[i]) + tmp := byte((_sum32Table1[tableIdx1%9] ^ _sum32Table0[tableIdx0%7]) ^ data[i]) out[i&3] = (out[i&3] + tmp) & 0xFF - } return binary.BigEndian.Uint32(out) diff --git a/entranceserver/crypto_test.go b/server/entranceserver/crypto_test.go similarity index 100% rename from entranceserver/crypto_test.go rename to server/entranceserver/crypto_test.go diff --git a/server/entranceserver/entrance_server.go b/server/entranceserver/entrance_server.go new file mode 100644 index 000000000..3760def97 --- /dev/null +++ b/server/entranceserver/entrance_server.go @@ -0,0 +1,120 @@ +package entranceserver + +import ( + "encoding/hex" + "fmt" + "io" + "net" + "sync" + + "github.com/Andoryuuta/Erupe/config" + "github.com/Andoryuuta/Erupe/network" + "github.com/jmoiron/sqlx" + "go.uber.org/zap" +) + +// Server is a MHF entrance server. +type Server struct { + sync.Mutex + logger *zap.Logger + erupeConfig *config.Config + db *sqlx.DB + listener net.Listener + isShuttingDown bool +} + +// Config struct allows configuring the server. +type Config struct { + Logger *zap.Logger + DB *sqlx.DB + ErupeConfig *config.Config +} + +// NewServer creates a new Server type. +func NewServer(config *Config) *Server { + s := &Server{ + logger: config.Logger, + erupeConfig: config.ErupeConfig, + db: config.DB, + } + return s +} + +// Start starts the server in a new goroutine. +func (s *Server) Start() error { + + l, err := net.Listen("tcp", fmt.Sprintf(":%d", s.erupeConfig.Entrance.Port)) + if err != nil { + return err + } + + s.listener = l + + go s.acceptClients() + + return nil +} + +// Shutdown exits the server gracefully. +func (s *Server) Shutdown() { + s.logger.Debug("Shutting down") + + s.Lock() + s.isShuttingDown = true + s.Unlock() + + // This will cause the acceptor goroutine to error and exit gracefully. + s.listener.Close() +} + +//acceptClients handles accepting new clients in a loop. +func (s *Server) acceptClients() { + for { + conn, err := s.listener.Accept() + if err != nil { + // Check if we are shutting down and exit gracefully if so. + s.Lock() + shutdown := s.isShuttingDown + s.Unlock() + + if shutdown { + break + } else { + continue + } + } + + // Start a new goroutine for the connection so that we don't block other incoming connections. + go s.handleEntranceServerConnection(conn) + } +} + +func (s *Server) handleEntranceServerConnection(conn net.Conn) { + // Client initalizes the connection with a one-time buffer of 8 NULL bytes. + nullInit := make([]byte, 8) + n, err := io.ReadFull(conn, nullInit) + if err != nil { + s.logger.Warn("Failed to read 8 NULL init", zap.Error(err)) + return + } else if n != len(nullInit) { + s.logger.Warn("io.ReadFull couldn't read the full 8 byte init.") + return + } + + // Create a new encrypted connection handler and read a packet from it. + cc := network.NewCryptConn(conn) + pkt, err := cc.ReadPacket() + if err != nil { + s.logger.Warn("Error reading packet", zap.Error(err)) + return + } + + s.logger.Debug("Got entrance server command:\n", zap.String("raw", hex.Dump(pkt))) + + data := makeResp(s.erupeConfig.Entrance.Entries) + 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() +} diff --git a/entranceserver/make_resp.go b/server/entranceserver/make_resp.go similarity index 63% rename from entranceserver/make_resp.go rename to server/entranceserver/make_resp.go index bd3ff98e8..73ac12ea6 100644 --- a/entranceserver/make_resp.go +++ b/server/entranceserver/make_resp.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "net" + "github.com/Andoryuuta/Erupe/config" "github.com/Andoryuuta/byteframe" ) @@ -16,45 +17,11 @@ func paddedString(x string, size uint) []byte { return out } -// ServerInfo represents an entry in the serverlist. -type ServerInfo struct { - IP net.IP - Unk2 uint16 - Type uint8 // Server type. 0=?, 1=open, 2=cities, 3=newbie, 4=bar - Season uint8 // Server activity. 0 = green, 1 = orange, 2 = blue - Unk6 uint8 // Something to do with server recommendation on 0, 3, and 5. - Name string // Server name, 66 byte null terminated Shift-JIS. - - // 4096(PC, PS3/PS4)?, 8258(PC, PS3/PS4)?, 8192 == nothing? - // THIS ONLY EXISTS IF Binary8Header.type == "SV2", NOT "SVR"! - AllowedClientFlags uint32 - - Channels []ChannelInfo -} - -// ChannelInfo represents an entry in a server's channel list. -type ChannelInfo struct { - Port uint16 - //ChannelIndex uint16 - MaxPlayers uint16 - CurrentPlayers uint16 - Unk4 uint16 - Unk5 uint16 - Unk6 uint16 - Unk7 uint16 - Unk8 uint16 - Unk9 uint16 - Unk10 uint16 - Unk11 uint16 - Unk12 uint16 - Unk13 uint16 -} - -func encodeServerInfo(serverInfos []ServerInfo) []byte { +func encodeServerInfo(serverInfos []config.EntranceServerInfo) []byte { bf := byteframe.NewByteFrame() for serverIdx, si := range serverInfos { - bf.WriteUint32(binary.LittleEndian.Uint32(si.IP.To4())) + bf.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(si.IP).To4())) bf.WriteUint16(16 + uint16(serverIdx)) bf.WriteUint16(si.Unk2) bf.WriteUint16(uint16(len(si.Channels))) @@ -103,7 +70,7 @@ func makeHeader(data []byte, respType string, entryCount uint16, key byte) []byt return bf.Data() } -func makeResp(servers []ServerInfo) []byte { +func makeResp(servers []config.EntranceServerInfo) []byte { rawServerData := encodeServerInfo(servers) bf := byteframe.NewByteFrame() diff --git a/server/launcherserver/handler.go b/server/launcherserver/handler.go new file mode 100644 index 000000000..d1cad4f3c --- /dev/null +++ b/server/launcherserver/handler.go @@ -0,0 +1,20 @@ +package launcherserver + +import ( + "net/http" +) + +// ServerHandler is a handler function akin to http.Handler's ServeHTTP, +// but has an additional *Server argument. +type ServerHandler func(*Server, http.ResponseWriter, *http.Request) + +// ServerHandlerFunc is a small type that implements http.Handler and +// wraps a calling ServerHandler with a *Server argument. +type ServerHandlerFunc struct { + server *Server + f ServerHandler +} + +func (shf ServerHandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) { + shf.f(shf.server, w, r) +} diff --git a/server/launcherserver/launcher_server.go b/server/launcherserver/launcher_server.go new file mode 100644 index 000000000..a3297ebe9 --- /dev/null +++ b/server/launcherserver/launcher_server.go @@ -0,0 +1,98 @@ +package launcherserver + +import ( + "context" + "fmt" + "net/http" + "os" + "sync" + "time" + + "github.com/Andoryuuta/Erupe/config" + "github.com/gorilla/handlers" + "github.com/gorilla/mux" + "github.com/jmoiron/sqlx" + "go.uber.org/zap" +) + +// Config struct allows configuring the server. +type Config struct { + Logger *zap.Logger + DB *sqlx.DB + ErupeConfig *config.Config + UseOriginalLauncherFiles bool +} + +// Server is the MHF launcher HTTP server. +type Server struct { + sync.Mutex + logger *zap.Logger + erupeConfig *config.Config + db *sqlx.DB + httpServer *http.Server + useOriginalLauncherFiles bool + isShuttingDown bool +} + +// NewServer creates a new Server type. +func NewServer(config *Config) *Server { + s := &Server{ + logger: config.Logger, + erupeConfig: config.ErupeConfig, + db: config.DB, + useOriginalLauncherFiles: config.UseOriginalLauncherFiles, + httpServer: &http.Server{}, + } + return s +} + +// Start starts the server in a new goroutine. +func (s *Server) Start() error { + // Set up the routes responsible for serving the launcher HTML, serverlist, unique name check, and JP auth. + r := mux.NewRouter() + + // Universal serverlist.xml route + s.setupServerlistRoutes(r) + + // Change the launcher HTML routes if we are using the custom launcher instead of the original. + if s.useOriginalLauncherFiles { + s.setupOriginalLauncherRotues(r) + } else { + s.setupCustomLauncherRotues(r) + } + + s.httpServer.Addr = fmt.Sprintf(":%d", s.erupeConfig.Launcher.Port) + s.httpServer.Handler = handlers.LoggingHandler(os.Stdout, r) + + serveError := make(chan error, 1) + go func() { + if err := s.httpServer.ListenAndServe(); err != nil { + // Send error if any. + serveError <- err + } + }() + + // Get the error from calling ListenAndServe, otherwise assume it's good after 250 milliseconds. + select { + case err := <-serveError: + return err + case <-time.After(250 * time.Millisecond): + return nil + } +} + +// Shutdown exits the server gracefully. +func (s *Server) Shutdown() { + s.logger.Debug("Shutting down") + + s.Lock() + s.isShuttingDown = true + s.Unlock() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := s.httpServer.Shutdown(ctx); err != nil { + // Just warn because we are shutting down the server anyway. + s.logger.Warn("Got error on httpServer shutdown", zap.Error(err)) + } +} diff --git a/launcher_server.go b/server/launcherserver/routes.go similarity index 55% rename from launcher_server.go rename to server/launcherserver/routes.go index 9bc81d785..c951bf08a 100644 --- a/launcher_server.go +++ b/server/launcherserver/routes.go @@ -1,36 +1,20 @@ -package main +package launcherserver import ( "fmt" "html" - "log" - "net" "net/http" - "os" - "github.com/gorilla/handlers" "github.com/gorilla/mux" //"github.com/julienschmidt/httprouter" ) -// GetOutboundIP4 gets the preferred outbound ip4 of this machine -// From https://stackoverflow.com/a/37382208 -func GetOutboundIP4() net.IP { - conn, err := net.Dial("udp4", "8.8.8.8:80") - if err != nil { - log.Fatal(err) - } - defer conn.Close() - - localAddr := conn.LocalAddr().(*net.UDPAddr) - - return localAddr.IP.To4() -} - -func serverList(w http.ResponseWriter, r *http.Request) { - // TODO(Andoryuuta): Redo launcher server to allow configurable serverlist host and port. - fmt.Fprintf(w, ``, GetOutboundIP4().String()) - +func serverList(s *Server, w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, + ``, + s.erupeConfig.HostIP, + s.erupeConfig.Sign.Port, + ) } func serverUniqueName(w http.ResponseWriter, r *http.Request) { @@ -39,8 +23,7 @@ func serverUniqueName(w http.ResponseWriter, r *http.Request) { } func jpLogin(w http.ResponseWriter, r *http.Request) { - // HACK: Return the given password back as the `skey` to defer the login logic to the sign server. - + // HACK(Andoryuuta): Return the given password back as the `skey` to defer the login logic to the sign server. resultJSON := fmt.Sprintf(`{"result": "Ok", "skey": "%s", "code": "000", "msg": ""}`, r.FormValue("pw")) fmt.Fprintf(w, @@ -58,18 +41,18 @@ func jpLogin(w http.ResponseWriter, r *http.Request) { } -func setupServerlistRoutes(r *mux.Router) { +func (s *Server) setupServerlistRoutes(r *mux.Router) { // TW twServerList := r.Host("mhf-n.capcom.com.tw").Subrouter() twServerList.HandleFunc("/server/unique.php", serverUniqueName) // Name checking is also done on this host. - twServerList.HandleFunc("/server/serverlist.xml", serverList) + twServerList.Handle("/server/serverlist.xml", ServerHandlerFunc{s, serverList}) // JP jpServerList := r.Host("srv-mhf.capcom-networks.jp").Subrouter() - jpServerList.HandleFunc("/serverlist.xml", serverList) + jpServerList.Handle("/serverlist.xml", ServerHandlerFunc{s, serverList}) } -func setupOriginalLauncherRotues(r *mux.Router) { +func (s *Server) setupOriginalLauncherRotues(r *mux.Router) { // TW twMain := r.Host("mhfg.capcom.com.tw").Subrouter() twMain.PathPrefix("/").Handler(http.FileServer(http.Dir("./www/tw/"))) @@ -85,7 +68,7 @@ func setupOriginalLauncherRotues(r *mux.Router) { } -func setupCustomLauncherRotues(r *mux.Router) { +func (s *Server) setupCustomLauncherRotues(r *mux.Router) { // TW twMain := r.Host("mhfg.capcom.com.tw").Subrouter() twMain.PathPrefix("/g6_launcher/").Handler(http.StripPrefix("/g6_launcher/", http.FileServer(http.Dir("./www/erupe/")))) @@ -94,24 +77,3 @@ func setupCustomLauncherRotues(r *mux.Router) { jpMain := r.Host("cog-members.mhf-z.jp").Subrouter() jpMain.PathPrefix("/launcher/").Handler(http.StripPrefix("/launcher/", http.FileServer(http.Dir("./www/erupe")))) } - -// serveLauncherHTML is responsible for serving the launcher HTML, serverlist, unique name check, and JP auth. -func serveLauncherHTML(listenAddr string, useOriginalLauncher bool) { - r := mux.NewRouter() - - setupServerlistRoutes(r) - - if useOriginalLauncher { - setupOriginalLauncherRotues(r) - } else { - setupCustomLauncherRotues(r) - } - /* - http.ListenAndServe(listenAddr, handlers.CustomLoggingHandler(os.Stdout, r, func(writer io.Writer, params handlers.LogFormatterParams) { - dump, _ := httputil.DumpRequest(params.Request, true) - writer.Write(dump) - })) - */ - - http.ListenAndServe(listenAddr, handlers.LoggingHandler(os.Stdout, r)) -} diff --git a/server/signserver/dbutils.go b/server/signserver/dbutils.go new file mode 100644 index 000000000..bb5d4812d --- /dev/null +++ b/server/signserver/dbutils.go @@ -0,0 +1,56 @@ +package signserver + +import "time" + +func (s *Server) registerDBAccount(username string, password string) error { + _, err := s.db.Exec("INSERT INTO users (username, password) VALUES ($1, $2)", username, password) + if err != nil { + return err + } + + var id int + err = s.db.QueryRow("SELECT id FROM users WHERE username = $1", username).Scan(&id) + if err != nil { + return err + } + + // Create a base new character. + _, err = s.db.Exec(` + INSERT INTO characters ( + user_id, is_female, is_new_character, small_gr_level, gr_override_mode, name, unk_desc_string, + gr_override_level, gr_override_unk0, gr_override_unk1, exp, weapon, last_login) + VALUES($1, False, True, 0, True, '', '', 0, 0, 0, 0, 0, $2)`, + id, + uint32(time.Now().Unix()), + ) + if err != nil { + return err + } + + return nil +} + +type character struct { + ID uint32 `db:"id"` + IsFemale bool `db:"is_female"` + IsNewCharacter bool `db:"is_new_character"` + SmallGRLevel uint8 `db:"small_gr_level"` + GROverrideMode bool `db:"gr_override_mode"` + Name string `db:"name"` + UnkDescString string `db:"unk_desc_string"` + GROverrideLevel uint16 `db:"gr_override_level"` + GROverrideUnk0 uint8 `db:"gr_override_unk0"` + GROverrideUnk1 uint8 `db:"gr_override_unk1"` + Exp uint16 `db:"exp"` + Weapon uint16 `db:"weapon"` + LastLogin uint32 `db:"last_login"` +} + +func (s *Server) getCharactersForUser(uid int) ([]character, error) { + characters := []character{} + err := s.db.Select(&characters, "SELECT id, is_female, is_new_character, small_gr_level, gr_override_mode, name, unk_desc_string, gr_override_level, gr_override_unk0, gr_override_unk1, exp, weapon, last_login FROM characters WHERE user_id = $1", uid) + if err != nil { + return nil, err + } + return characters, nil +} diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go new file mode 100644 index 000000000..28816825f --- /dev/null +++ b/server/signserver/dsgn_resp.go @@ -0,0 +1,103 @@ +package signserver + +import ( + "fmt" + + "github.com/Andoryuuta/byteframe" + "go.uber.org/zap" +) + +func paddedString(x string, size uint) []byte { + out := make([]byte, size) + copy(out, x) + + // Null terminate it. + out[len(out)-1] = 0 + return out +} + +func uint8PascalString(bf *byteframe.ByteFrame, x string) { + bf.WriteUint8(uint8(len(x) + 1)) + bf.WriteNullTerminatedBytes([]byte(x)) +} + +func uint16PascalString(bf *byteframe.ByteFrame, x string) { + bf.WriteUint16(uint16(len(x) + 1)) + bf.WriteNullTerminatedBytes([]byte(x)) +} + +func makeSignInFailureResp(respID RespID) []byte { + bf := byteframe.NewByteFrame() + bf.WriteUint8(uint8(respID)) + return bf.Data() +} + +func (s *Session) makeSignInResp(uid int) []byte { + // Get the characters from the DB. + chars, err := s.server.getCharactersForUser(uid) + if err != nil { + s.logger.Warn("Error getting characters from DB", zap.Error(err)) + } + + bf := byteframe.NewByteFrame() + + bf.WriteUint8(1) // resp_code + bf.WriteUint8(0) // file/patch server count + bf.WriteUint8(4) // entrance server count + bf.WriteUint8(uint8(len(chars))) // character count + bf.WriteUint32(0xFFFFFFFF) // login_token_number + bf.WriteBytes(paddedString("logintokenstrng", 16)) // login_token (16 byte padded string) + bf.WriteUint32(1576761190) + uint8PascalString(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.HostIP, s.server.erupeConfig.Entrance.Port)) + uint8PascalString(bf, "") + uint8PascalString(bf, "") + uint8PascalString(bf, "mhf-n.capcom.com.tw") + + for _, char := range chars { + bf.WriteUint32(char.ID) // character ID 469153291 + + // Exp, HR[x] is split by 0, 1, 30, 50, 99, 299, 998, 999 + if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.MaxLauncherHR { + bf.WriteUint16(999) + } else { + bf.WriteUint16(char.Exp) + } + + bf.WriteUint16(char.Weapon) // Weapon, 0-13. + bf.WriteUint32(char.LastLogin) // Last login date, unix timestamp in seconds. + bf.WriteBool(char.IsFemale) // Sex, 0=male, 1=female. + bf.WriteBool(char.IsNewCharacter) // Is new character, 1 replaces character name with ?????. + bf.WriteUint8(char.SmallGRLevel) // GR level if grMode == 0 + bf.WriteBool(char.GROverrideMode) // GR mode. + bf.WriteBytes(paddedString(char.Name, 16)) // Character name + bf.WriteBytes(paddedString(char.UnkDescString, 32)) // unk str + if char.GROverrideMode { + bf.WriteUint16(char.GROverrideLevel) // GR level override. + bf.WriteUint8(char.GROverrideUnk0) // unk + bf.WriteUint8(char.GROverrideUnk1) // unk + } + } + + bf.WriteUint8(0) // friends_list_count + bf.WriteUint8(0) // guild_members_count + bf.WriteUint8(0) // notice_count + bf.WriteUint32(0xDEADBEEF) // some_last_played_character_id + bf.WriteUint32(14) // unk_flags + uint8PascalString(bf, "") // unk_data_blob PascalString + + bf.WriteUint16(51728) + bf.WriteUint16(20000) + uint16PascalString(bf, "1000672925") + + bf.WriteUint8(0) + + bf.WriteUint16(51729) + bf.WriteUint16(1) + bf.WriteUint16(20000) + uint16PascalString(bf, "203.191.249.36:8080") + + bf.WriteUint32(1578905116) + bf.WriteUint32(0) + + return bf.Data() +} diff --git a/signserver/respid.go b/server/signserver/respid.go similarity index 99% rename from signserver/respid.go rename to server/signserver/respid.go index a55aed14a..47e7683d4 100644 --- a/signserver/respid.go +++ b/server/signserver/respid.go @@ -1,6 +1,7 @@ package signserver //revive:disable + type RespID uint16 //go:generate stringer -type=RespID diff --git a/server/signserver/session.go b/server/signserver/session.go new file mode 100644 index 000000000..7c2051a4e --- /dev/null +++ b/server/signserver/session.go @@ -0,0 +1,139 @@ +package signserver + +import ( + "database/sql" + "encoding/hex" + "net" + "sync" + + "github.com/Andoryuuta/Erupe/network" + "github.com/Andoryuuta/byteframe" + "go.uber.org/zap" +) + +// Session holds state for the sign server connection. +type Session struct { + sync.Mutex + logger *zap.Logger + sid int + server *Server + 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 + } + } +} + +func (s *Session) handlePacket(pkt []byte) error { + sugar := s.logger.Sugar() + + bf := byteframe.NewByteFrameFromBytes(pkt) + reqType := string(bf.ReadNullTerminatedBytes()) + switch reqType { + case "DLTSKEYSIGN:100": + fallthrough + case "DSGN:100": + err := s.handleDSGNRequest(bf) + if err != nil { + return nil + } + case "DELETE:100": + loginTokenString := string(bf.ReadNullTerminatedBytes()) + _ = loginTokenString + characterID := bf.ReadUint32() + + sugar.Infof("Got delete request for character ID: %v\n", characterID) + sugar.Infof("remaining unknown data:\n%s\n", hex.Dump(bf.DataFromCurrent())) + default: + sugar.Infof("Got unknown request type %s, data:\n%s\n", reqType, hex.Dump(bf.DataFromCurrent())) + } + + return nil +} + +func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error { + + reqUsername := string(bf.ReadNullTerminatedBytes()) + reqPassword := string(bf.ReadNullTerminatedBytes()) + reqUnk := string(bf.ReadNullTerminatedBytes()) + + s.server.logger.Info( + "Got sign in request", + zap.String("reqUsername", reqUsername), + zap.String("reqPassword", reqPassword), + zap.String("reqUnk", reqUnk), + ) + + // TODO(Andoryuuta): remove plaintext password storage if this ever becomes more than a toy project. + var ( + id int + password string + ) + err := s.server.db.QueryRow("SELECT id, password FROM users WHERE username = $1", reqUsername).Scan(&id, &password) + var serverRespBytes []byte + switch { + case err == sql.ErrNoRows: + 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) + break + } + + var id int + err = s.server.db.QueryRow("SELECT id FROM users WHERE username = $1", reqUsername).Scan(&id) + if err != nil { + s.logger.Info("Error on querying account id", zap.Error(err)) + serverRespBytes = makeSignInFailureResp(SIGN_EABORT) + break + } + + serverRespBytes = s.makeSignInResp(id) + break + case err != nil: + serverRespBytes = makeSignInFailureResp(SIGN_EABORT) + s.logger.Warn("Got error on SQL query", zap.Error(err)) + break + default: + if reqPassword == password { + s.logger.Info("Passwords match!") + serverRespBytes = s.makeSignInResp(id) + } else { + s.logger.Info("Passwords don't match!") + serverRespBytes = makeSignInFailureResp(SIGN_EPASS) + } + + } + + err = s.cryptConn.SendPacket(serverRespBytes) + if err != nil { + return err + } + + return nil +} diff --git a/server/signserver/sign_server.go b/server/signserver/sign_server.go new file mode 100644 index 000000000..7a37189c0 --- /dev/null +++ b/server/signserver/sign_server.go @@ -0,0 +1,119 @@ +package signserver + +import ( + "fmt" + "io" + "net" + "sync" + + "github.com/Andoryuuta/Erupe/config" + "github.com/Andoryuuta/Erupe/network" + "github.com/jmoiron/sqlx" + "go.uber.org/zap" +) + +// Config struct allows configuring the server. +type Config struct { + Logger *zap.Logger + DB *sqlx.DB + ErupeConfig *config.Config +} + +// Server is a MHF sign server. +type Server struct { + sync.Mutex + logger *zap.Logger + erupeConfig *config.Config + sid int + sessions map[int]*Session + db *sqlx.DB + listener net.Listener + isShuttingDown bool +} + +// NewServer creates a new Server type. +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 +} + +// Start starts the server in a new goroutine. +func (s *Server) Start() error { + l, err := net.Listen("tcp", fmt.Sprintf(":%d", s.erupeConfig.Sign.Port)) + if err != nil { + return err + } + s.listener = l + + go s.acceptClients() + + return nil +} + +// Shutdown exits the server gracefully. +func (s *Server) Shutdown() { + s.logger.Debug("Shutting down") + + s.Lock() + s.isShuttingDown = true + s.Unlock() + + // This will cause the acceptor goroutine to error and exit gracefully. + s.listener.Close() +} + +func (s *Server) acceptClients() { + for { + conn, err := s.listener.Accept() + if err != nil { + // Check if we are shutting down and exit gracefully if so. + s.Lock() + shutdown := s.isShuttingDown + s.Unlock() + + if shutdown { + break + } else { + panic(err) + } + } + + go s.handleConnection(s.sid, conn) + s.sid++ + } +} + +func (s *Server) handleConnection(sid int, conn net.Conn) { + s.logger.Info("Got connection to sign server", zap.String("remoteaddr", conn.RemoteAddr().String())) + + // 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() + return + } + + // Create a new session. + session := &Session{ + logger: s.logger, + server: s, + 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() +} diff --git a/signserver/dsgn_resp.go b/signserver/dsgn_resp.go deleted file mode 100644 index 000d68c91..000000000 --- a/signserver/dsgn_resp.go +++ /dev/null @@ -1,137 +0,0 @@ -package signserver - -import "github.com/Andoryuuta/byteframe" - -func paddedString(x string, size uint) []byte { - out := make([]byte, size) - copy(out, x) - - // Null terminate it. - out[len(out)-1] = 0 - return out -} - -func uint8PascalString(bf *byteframe.ByteFrame, x string) { - bf.WriteUint8(uint8(len(x) + 1)) - bf.WriteNullTerminatedBytes([]byte(x)) -} - -func uint16PascalString(bf *byteframe.ByteFrame, x string) { - bf.WriteUint16(uint16(len(x) + 1)) - bf.WriteNullTerminatedBytes([]byte(x)) -} - -func makeSignInFailureResp(respID RespID) []byte { - bf := byteframe.NewByteFrame() - bf.WriteUint8(uint8(respID)) - return bf.Data() -} - -func makeSignInResp(username string) []byte { - bf := byteframe.NewByteFrame() - - // delete me: - //bf.WriteUint8(8) - //return bf.Data() - - bf.WriteUint8(1) // resp_code - bf.WriteUint8(0) // file/patch server count - bf.WriteUint8(4) // entrance server count - bf.WriteUint8(1) // character count - bf.WriteUint32(0xFFFFFFFF) // login_token_number - bf.WriteBytes(paddedString("logintokenstrng", 16)) // login_token (16 byte padded string) - bf.WriteUint32(1576761190) - - // file patch server PascalStrings here - - // Array(this.entrance_server_count, PascalString(Byte, "utf8")), - uint8PascalString(bf, "localhost:53310") - uint8PascalString(bf, "") - uint8PascalString(bf, "") - uint8PascalString(bf, "mhf-n.capcom.com.tw") - - /////////////////////////// - // Characters: - - /* - tab = '123456789ABCDEFGHJKLMNPQRTUVWXYZ' - def make_uid_str(cid): - out = '' - for i in range(6): - v = (cid>>5*i) - out += tab[v&0x1f] - return out - - def make_cid_int(uid): - v = 0 - for c in uid[::-1]: - idx = tab.find(c) - if idx == -1: - raise Exception("not in tab") - v |= idx - v = v<<5 - return v>>5 - */ - bf.WriteUint32(469153291) // character ID 469153291 - bf.WriteUint16(999) // Exp, HR[x] is split by 0, 1, 30, 50, 99, 299, 998, 999 - - //44.204 - - /* - 0=大劍/Big sword - 1=重弩/Heavy crossbow - 2=大錘/Sledgehammer - 3=長槍/Spear - 4=單手劍/One-handed sword - 5=輕弩/Light crossbow - 6=雙劍/Double sword - 7=太刀/Tadao - 8=狩獵笛/Hunting flute - 9=銃槍/Shotgun - 10=弓/bow - 11=穿龍棍/Wear a dragon stick - 12=斬擊斧F/Chopping Axe F - 13=--- - default=不明/unknown - */ - bf.WriteUint16(7) // Weapon, 0-13. - - bf.WriteUint32(1576761172) // Last login date, unix timestamp in seconds. - bf.WriteUint8(1) // Sex, 0=male, 1=female. - bf.WriteUint8(0) // Is new character, 1 replaces character name with ?????. - grMode := uint8(0) - bf.WriteUint8(1) // GR level if grMode == 0 - bf.WriteUint8(grMode) // GR mode. - bf.WriteBytes(paddedString(username, 16)) // Character name - bf.WriteBytes(paddedString("0", 32)) // unk str - if grMode == 1 { - bf.WriteUint16(55) // GR level override. - bf.WriteUint8(0) // unk - bf.WriteUint8(0) // unk - } - - ////////////////////////// - - bf.WriteUint8(0) // friends_list_count - bf.WriteUint8(0) // guild_members_count - bf.WriteUint8(0) // notice_count - bf.WriteUint32(0xDEADBEEF) // some_last_played_character_id - bf.WriteUint32(14) // unk_flags - uint8PascalString(bf, "") // unk_data_blob PascalString - - bf.WriteUint16(51728) - bf.WriteUint16(20000) - uint16PascalString(bf, "1000672925") - - bf.WriteUint8(0) - - bf.WriteUint16(51729) - bf.WriteUint16(1) - bf.WriteUint16(20000) - uint16PascalString(bf, "203.191.249.36:8080") - - bf.WriteUint32(1578905116) - bf.WriteUint32(0) - - return bf.Data() -} diff --git a/signserver/session.go b/signserver/session.go deleted file mode 100644 index 3eebeac9a..000000000 --- a/signserver/session.go +++ /dev/null @@ -1,109 +0,0 @@ -package signserver - -import ( - "database/sql" - "encoding/hex" - "fmt" - "net" - "sync" - - "github.com/Andoryuuta/Erupe/network" - "github.com/Andoryuuta/byteframe" -) - -// Session holds state for the sign server connection. -type Session struct { - sync.Mutex - sid int - server *Server - rawConn *net.Conn - cryptConn *network.CryptConn -} - -func (session *Session) fail() { - session.server.Lock() - delete(session.server.sessions, session.sid) - session.server.Unlock() - -} - -func (session *Session) work() { - for { - pkt, err := session.cryptConn.ReadPacket() - if err != nil { - session.fail() - return - } - - err = session.handlePacket(pkt) - if err != nil { - session.fail() - return - } - } -} - -func (session *Session) handlePacket(pkt []byte) error { - bf := byteframe.NewByteFrameFromBytes(pkt) - reqType := string(bf.ReadNullTerminatedBytes()) - switch reqType { - case "DLTSKEYSIGN:100": - fallthrough - case "DSGN:100": - session.handleDSGNRequest(bf) - break - case "DELETE:100": - loginTokenString := string(bf.ReadNullTerminatedBytes()) - _ = loginTokenString - characterID := bf.ReadUint32() - - fmt.Printf("Got delete request for character ID: %v\n", characterID) - fmt.Printf("remaining unknown data:\n%s\n", hex.Dump(bf.DataFromCurrent())) - default: - fmt.Printf("Got unknown request type %s, data:\n%s\n", reqType, hex.Dump(bf.DataFromCurrent())) - } - - return nil -} - -func (session *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error { - reqUsername := string(bf.ReadNullTerminatedBytes()) - reqPassword := string(bf.ReadNullTerminatedBytes()) - reqUnk := string(bf.ReadNullTerminatedBytes()) - fmt.Printf("Got sign in request:\n\tUsername: %s\n\tPassword %s\n\tUnk: %s\n", reqUsername, reqPassword, reqUnk) - - // TODO(Andoryuuta): remove plaintext password storage if this ever becomes more than a toy project. - var ( - id int - password string - ) - err := session.server.db.QueryRow("SELECT id, password FROM users WHERE username = $1", reqUsername).Scan(&id, &password) - var serverRespBytes []byte - switch { - case err == sql.ErrNoRows: - fmt.Printf("No rows for username %s\n", reqUsername) - serverRespBytes = makeSignInFailureResp(SIGN_EAUTH) - break - case err != nil: - serverRespBytes = makeSignInFailureResp(SIGN_EABORT) - fmt.Println("Got error on SQL query!") - fmt.Println(err) - break - default: - if reqPassword == password { - fmt.Println("Passwords match!") - serverRespBytes = makeSignInResp(reqUsername) - } else { - fmt.Println("Passwords don't match!") - serverRespBytes = makeSignInFailureResp(SIGN_EPASS) - } - - } - - err = session.cryptConn.SendPacket(serverRespBytes) - if err != nil { - return err - } - - return nil -} diff --git a/signserver/sign_server.go b/signserver/sign_server.go deleted file mode 100644 index 6654f16da..000000000 --- a/signserver/sign_server.go +++ /dev/null @@ -1,89 +0,0 @@ -package signserver - -import ( - "database/sql" - "fmt" - "io" - "net" - "sync" - - "github.com/Andoryuuta/Erupe/network" -) - -// Config struct allows configuring the server. -type Config struct { - DB *sql.DB - ListenAddr string -} - -// Server is a MHF sign server. -type Server struct { - sync.Mutex - sid int - sessions map[int]*Session - db *sql.DB - listenAddr string - listener net.Listener -} - -// NewServer creates a new Server type. -func NewServer(config *Config) *Server { - s := &Server{ - sid: 0, - sessions: make(map[int]*Session), - db: config.DB, - listenAddr: config.ListenAddr, - } - return s -} - -// Start starts the server in a new goroutine. -func (s *Server) Start() error { - l, err := net.Listen("tcp", s.listenAddr) - if err != nil { - return err - } - s.listener = l - //defer l.Close() - - go s.acceptClients() - - return nil -} - -func (s *Server) acceptClients() { - for { - conn, err := s.listener.Accept() - if err != nil { - panic(err) - } - - go s.handleConnection(s.sid, conn) - s.sid++ - } -} - -func (s *Server) handleConnection(sid int, conn net.Conn) { - fmt.Println("Got connection to sign server") - - // 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() - return - } - - session := &Session{ - server: s, - rawConn: &conn, - cryptConn: network.NewCryptConn(conn), - } - - s.Lock() - s.sessions[sid] = session - s.Unlock() - - session.work() -}