package channelserver import ( "math" "math/rand" "time" "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" ) func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfRegisterEvent) bf := byteframe.NewByteFrame() bf.WriteUint8(pkt.Unk2) bf.WriteUint8(pkt.Unk4) bf.WriteUint16(0x1142) doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfReleaseEvent(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfReleaseEvent) // Do this ack manually because it uses a non-(0|1) error code /* _ACK_SUCCESS = 0 _ACK_ERROR = 1 _ACK_EINPROGRESS = 16 _ACK_ENOENT = 17 _ACK_ENOSPC = 18 _ACK_ETIMEOUT = 19 _ACK_EINVALID = 64 _ACK_EFAILED = 65 _ACK_ENOMEM = 66 _ACK_ENOTEXIT = 67 _ACK_ENOTREADY = 68 _ACK_EALREADY = 69 _ACK_DISABLE_WORK = 71 */ s.QueueSendMHF(&mhfpacket.MsgSysAck{ AckHandle: pkt.AckHandle, IsBufferResponse: false, ErrorCode: 0x41, AckData: []byte{0x00, 0x00, 0x00, 0x00}, }) } func handleMsgMhfEnumerateEvent(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateEvent) stubEnumerateNoResults(s, pkt.AckHandle) } type activeFeature struct { StartTime time.Time ActiveFeatures uint32 Unk1 uint16 } func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule) persistentEventSchedule := make([]activeFeature, 8) // generate day after weekly restart for x := -1; x < 7; x++ { feat := generateActiveWeapons(14) // number of active weapons // TODO: only generate this once per restart (server should be restarted weekly) // then load data from db instead of regenerating persistentEventSchedule[x+1] = activeFeature{ StartTime: Time_Current_Midnight().Add(time.Duration(24*x) * time.Hour), ActiveFeatures: uint32(feat), Unk1: 0, } } resp := byteframe.NewByteFrame() resp.WriteUint8(uint8(len(persistentEventSchedule))) // Entry count, client only parses the first 7 or 8. resp.WriteUint32(uint32(Time_Current_Adjusted().Add(-5 * time.Minute).Unix())) // 5 minutes ago server time for _, es := range persistentEventSchedule { resp.WriteUint32(uint32(es.StartTime.Unix())) resp.WriteUint32(es.ActiveFeatures) resp.WriteUint16(es.Unk1) } doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } func generateActiveWeapons(count int) int { nums := make([]int, 0) var result int r := rand.New(rand.NewSource(time.Now().UnixNano())) for len(nums) < count { num := r.Intn(14) exist := false for _, v := range nums { if v == num { exist = true break } } if !exist { nums = append(nums, num) } } for _, num := range nums { result += int(math.Pow(2, float64(num))) } return result } type loginBoost struct { WeekReq, WeekCount uint8 Available bool Expiration uint32 } func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetKeepLoginBoostStatus) var loginBoostStatus []loginBoost insert := false boostState, err := s.server.db.Query("SELECT week_req, week_count, available, end_time FROM login_boost_state WHERE char_id=$1 ORDER BY week_req ASC", s.charID) if err != nil { panic(err) } for boostState.Next() { var boost loginBoost err = boostState.Scan(&boost.WeekReq, &boost.WeekCount, &boost.Available, &boost.Expiration) if err != nil { panic(err) } loginBoostStatus = append(loginBoostStatus, boost) } if len(loginBoostStatus) == 0 { // create default Entries (should only been week 1 with ) insert = true loginBoostStatus = []loginBoost{ { WeekReq: 1, // weeks needed WeekCount: 0, // weeks passed Available: true, // available Expiration: 0, //uint32(t.Add(120 * time.Minute).Unix()), // uncomment to enable permanently }, { WeekReq: 2, WeekCount: 0, Available: true, Expiration: 0, }, { WeekReq: 3, WeekCount: 0, Available: true, Expiration: 0, }, { WeekReq: 4, WeekCount: 0, Available: true, Expiration: 0, }, { WeekReq: 5, WeekCount: 0, Available: true, Expiration: 0, }, } } resp := byteframe.NewByteFrame() CurrentWeek := Time_Current_Week_uint8() for d := range loginBoostStatus { if CurrentWeek == 1 && loginBoostStatus[d].WeekCount <= 5 { loginBoostStatus[d].WeekCount = 0 } if loginBoostStatus[d].WeekReq == CurrentWeek || loginBoostStatus[d].WeekCount != 0 { loginBoostStatus[d].WeekCount = CurrentWeek } if !loginBoostStatus[d].Available && loginBoostStatus[d].WeekCount >= loginBoostStatus[d].WeekReq && uint32(time.Now().In(time.FixedZone("UTC+1", 1*60*60)).Unix()) >= loginBoostStatus[d].Expiration { loginBoostStatus[d].Expiration = 1 } if !insert { _, err := s.server.db.Exec(`UPDATE login_boost_state SET week_count=$1, end_time=$2 WHERE char_id=$3 AND week_req=$4`, loginBoostStatus[d].WeekCount, loginBoostStatus[d].Expiration, s.charID, loginBoostStatus[d].WeekReq) if err != nil { panic(err) } } } for _, v := range loginBoostStatus { if insert { _, err := s.server.db.Exec(`INSERT INTO login_boost_state (char_id, week_req, week_count, available, end_time) VALUES ($1,$2,$3,$4,$5)`, s.charID, v.WeekReq, v.WeekCount, v.Available, v.Expiration) if err != nil { panic(err) } } resp.WriteUint8(v.WeekReq) resp.WriteUint8(v.WeekCount) resp.WriteBool(v.Available) resp.WriteUint32(v.Expiration) } doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) { // Directly interacts with MhfGetKeepLoginBoostStatus // TODO: make these states persistent on a per character basis pkt := p.(*mhfpacket.MsgMhfUseKeepLoginBoost) var t = time.Now().In(time.FixedZone("UTC+1", 1*60*60)) resp := byteframe.NewByteFrame() resp.WriteUint8(0) // response is end timestamp based on input switch pkt.BoostWeekUsed { case 1: t = t.Add(120 * time.Minute) resp.WriteUint32(uint32(t.Unix())) case 2: t = t.Add(240 * time.Minute) resp.WriteUint32(uint32(t.Unix())) case 3: t = t.Add(120 * time.Minute) resp.WriteUint32(uint32(t.Unix())) case 4: t = t.Add(180 * time.Minute) resp.WriteUint32(uint32(t.Unix())) case 5: t = t.Add(240 * time.Minute) resp.WriteUint32(uint32(t.Unix())) } _, err := s.server.db.Exec(`UPDATE login_boost_state SET available='false', end_time=$1 WHERE char_id=$2 AND week_req=$3`, uint32(t.Unix()), s.charID, pkt.BoostWeekUsed) if err != nil { panic(err) } doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } func handleMsgMhfGetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfSetRestrictionEvent(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSetRestrictionEvent) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) }