diff --git a/network/mhfpacket/msg_mhf_register_event.go b/network/mhfpacket/msg_mhf_register_event.go index aaa5b51a8..956c4a399 100644 --- a/network/mhfpacket/msg_mhf_register_event.go +++ b/network/mhfpacket/msg_mhf_register_event.go @@ -1,20 +1,19 @@ package mhfpacket import ( + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfRegisterEvent represents the MSG_MHF_REGISTER_EVENT type MsgMhfRegisterEvent struct { AckHandle uint32 Unk0 uint16 - Unk1 uint8 - Unk2 uint8 + WorldID uint16 + LandID uint16 Unk3 uint8 Unk4 uint8 - Unk5 uint16 } // Opcode returns the ID associated with this packet type. @@ -26,11 +25,10 @@ func (m *MsgMhfRegisterEvent) Opcode() network.PacketID { func (m *MsgMhfRegisterEvent) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint8() + m.WorldID = bf.ReadUint16() + m.LandID = bf.ReadUint16() m.Unk3 = bf.ReadUint8() m.Unk4 = bf.ReadUint8() - m.Unk5 = bf.ReadUint16() return nil } diff --git a/network/mhfpacket/msg_mhf_release_event.go b/network/mhfpacket/msg_mhf_release_event.go index 08e507c81..52178279b 100644 --- a/network/mhfpacket/msg_mhf_release_event.go +++ b/network/mhfpacket/msg_mhf_release_event.go @@ -11,7 +11,7 @@ import ( // MsgMhfReleaseEvent represents the MSG_MHF_RELEASE_EVENT type MsgMhfReleaseEvent struct { AckHandle uint32 - Unk0 uint32 + RaviID uint32 Unk1 uint32 } @@ -23,7 +23,7 @@ func (m *MsgMhfReleaseEvent) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfReleaseEvent) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint32() + m.RaviID = bf.ReadUint32() m.Unk1 = bf.ReadUint32() return nil } diff --git a/network/mhfpacket/msg_sys_load_register.go b/network/mhfpacket/msg_sys_load_register.go index 730616d65..7e1ac5950 100644 --- a/network/mhfpacket/msg_sys_load_register.go +++ b/network/mhfpacket/msg_sys_load_register.go @@ -11,7 +11,7 @@ import ( type MsgSysLoadRegister struct { AckHandle uint32 RegisterID uint32 - Unk1 uint8 + Values uint8 } // Opcode returns the ID associated with this packet type. @@ -23,7 +23,7 @@ func (m *MsgSysLoadRegister) Opcode() network.PacketID { func (m *MsgSysLoadRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.RegisterID = bf.ReadUint32() - m.Unk1 = bf.ReadUint8() + m.Values = bf.ReadUint8() _ = bf.ReadUint8() _ = bf.ReadUint16() return nil diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index a0b8b6ca9..30a377b82 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -246,35 +246,42 @@ func parseChatCommand(s *Session, command string) { case commands["Raviente"].Prefix: if commands["Raviente"].Enabled { if len(args) > 1 { - if getRaviSemaphore(s.server) != nil { + if s.server.getRaviSemaphore() != nil { switch args[1] { case "start": - if s.server.raviente.register.startTime == 0 { - s.server.raviente.register.startTime = s.server.raviente.register.postTime + if s.server.raviente.register[1] == 0 { + s.server.raviente.register[1] = s.server.raviente.register[3] sendServerChatMessage(s, s.server.dict["commandRaviStartSuccess"]) s.notifyRavi() } else { sendServerChatMessage(s, s.server.dict["commandRaviStartError"]) } case "cm", "check", "checkmultiplier", "multiplier": - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRaviMultiplier"], s.server.raviente.GetRaviMultiplier(s.server))) - case "sr", "sendres", "resurrection": - if s.server.raviente.state.stateData[28] > 0 { - sendServerChatMessage(s, s.server.dict["commandRaviResSuccess"]) - s.server.raviente.state.stateData[28] = 0 + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRaviMultiplier"], s.server.GetRaviMultiplier())) + case "sr", "sendres", "resurrection", "ss", "sendsed", "rs", "reqsed": + if s.server.erupeConfig.RealClientMode == _config.ZZ { + switch args[1] { + case "sr", "sendres", "resurrection": + if s.server.raviente.state[28] > 0 { + sendServerChatMessage(s, s.server.dict["commandRaviResSuccess"]) + s.server.raviente.state[28] = 0 + } else { + sendServerChatMessage(s, s.server.dict["commandRaviResError"]) + } + case "ss", "sendsed": + sendServerChatMessage(s, s.server.dict["commandRaviSedSuccess"]) + // Total BerRavi HP + HP := s.server.raviente.state[0] + s.server.raviente.state[1] + s.server.raviente.state[2] + s.server.raviente.state[3] + s.server.raviente.state[4] + s.server.raviente.support[1] = HP + case "rs", "reqsed": + sendServerChatMessage(s, s.server.dict["commandRaviRequest"]) + // Total BerRavi HP + HP := s.server.raviente.state[0] + s.server.raviente.state[1] + s.server.raviente.state[2] + s.server.raviente.state[3] + s.server.raviente.state[4] + s.server.raviente.support[1] = HP + 1 + } } else { - sendServerChatMessage(s, s.server.dict["commandRaviResError"]) + sendServerChatMessage(s, s.server.dict["commandRaviVersion"]) } - case "ss", "sendsed": - sendServerChatMessage(s, s.server.dict["commandRaviSedSuccess"]) - // Total BerRavi HP - HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4] - s.server.raviente.support.supportData[1] = HP - case "rs", "reqsed": - sendServerChatMessage(s, s.server.dict["commandRaviRequest"]) - // Total BerRavi HP - HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4] - s.server.raviente.support.supportData[1] = HP + 12 default: sendServerChatMessage(s, s.server.dict["commandRaviError"]) } @@ -413,8 +420,9 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { } case BroadcastTypeServer: if pkt.MessageType == 1 { - if getRaviSemaphore(s.server) != nil { - s.server.BroadcastMHF(resp, s) + raviSema := s.server.getRaviSemaphore() + if raviSema != nil { + raviSema.BroadcastMHF(resp, s) } } else { s.server.BroadcastMHF(resp, s) diff --git a/server/channelserver/handlers_event.go b/server/channelserver/handlers_event.go index 74d0cef13..d01f92a3d 100644 --- a/server/channelserver/handlers_event.go +++ b/server/channelserver/handlers_event.go @@ -10,44 +10,6 @@ import ( "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}, - }) -} - type Event struct { EventType uint16 Unk1 uint16 diff --git a/server/channelserver/handlers_register.go b/server/channelserver/handlers_register.go index 33261a94e..6a74358aa 100644 --- a/server/channelserver/handlers_register.go +++ b/server/channelserver/handlers_register.go @@ -6,256 +6,124 @@ import ( "strings" ) +func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfRegisterEvent) + bf := byteframe.NewByteFrame() + // Some kind of check if there's already a session + if pkt.Unk3 > 0 && s.server.getRaviSemaphore() == nil { + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + return + } + bf.WriteUint8(uint8(pkt.WorldID)) + bf.WriteUint8(uint8(pkt.LandID)) + bf.WriteUint16(s.server.raviente.id) + 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}, + }) +} + +type RaviUpdate struct { + Op uint8 + Dest uint8 + Data uint32 +} + func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysOperateRegister) - bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) - s.server.raviente.Lock() - switch pkt.SemaphoreID { - case 4: - resp := byteframe.NewByteFrame() - size := 6 - for i := 0; i < len(bf.Data())-1; i += size { - op := bf.ReadUint8() - dest := bf.ReadUint8() - data := bf.ReadUint32() - resp.WriteUint8(1) - resp.WriteUint8(dest) - ref := &s.server.raviente.state.stateData[dest] - damageMultiplier := s.server.raviente.GetRaviMultiplier(s.server) - switch op { - case 2: - resp.WriteUint32(*ref) - if dest == 28 { // Berserk resurrection tracker - resp.WriteUint32(*ref + data) - *ref += data - } else if dest == 17 { // Berserk poison tracker - if damageMultiplier == 1 { - resp.WriteUint32(*ref + data) - *ref += data - } else { - resp.WriteUint32(*ref) - } - } else { - data = uint32(float64(data) * damageMultiplier) - resp.WriteUint32(*ref + data) - *ref += data - } - case 13: - fallthrough - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - } - } - resp.WriteUint8(0) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - case 5: - resp := byteframe.NewByteFrame() - size := 6 - for i := 0; i < len(bf.Data())-1; i += size { - op := bf.ReadUint8() - dest := bf.ReadUint8() - data := bf.ReadUint32() - resp.WriteUint8(1) - resp.WriteUint8(dest) - ref := &s.server.raviente.support.supportData[dest] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - fallthrough - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - } - } - resp.WriteUint8(0) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - case 6: - resp := byteframe.NewByteFrame() - size := 6 - for i := 0; i < len(bf.Data())-1; i += size { - op := bf.ReadUint8() - dest := bf.ReadUint8() - data := bf.ReadUint32() - resp.WriteUint8(1) - resp.WriteUint8(dest) - switch dest { - case 0: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.nextTime = data - case 1: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.startTime = data - case 2: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.killedTime = data - case 3: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.postTime = data - case 4: - ref := &s.server.raviente.register.register[0] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 5: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.carveQuest = data - case 6: - ref := &s.server.raviente.register.register[1] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 7: - ref := &s.server.raviente.register.register[2] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 8: - ref := &s.server.raviente.register.register[3] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 9: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.maxPlayers = data - case 10: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.ravienteType = data - case 11: - ref := &s.server.raviente.register.register[4] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - default: - resp.WriteUint32(0) - resp.WriteUint32(0) - } - } - resp.WriteUint8(0) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + + var raviUpdates []RaviUpdate + var raviUpdate RaviUpdate + // Strip null terminator + bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload[:len(pkt.RawDataPayload)-1]) + for i := len(pkt.RawDataPayload) / 6; i > 0; i-- { + raviUpdate.Op = bf.ReadUint8() + raviUpdate.Dest = bf.ReadUint8() + raviUpdate.Data = bf.ReadUint32() + raviUpdates = append(raviUpdates, raviUpdate) } + bf = byteframe.NewByteFrame() + + var _old, _new uint32 + s.server.raviente.Lock() + for _, update := range raviUpdates { + switch update.Op { + case 2: + _old, _new = s.server.UpdateRavi(pkt.SemaphoreID, update.Dest, update.Data, true) + case 13, 14: + _old, _new = s.server.UpdateRavi(pkt.SemaphoreID, update.Dest, update.Data, false) + } + bf.WriteUint8(1) + bf.WriteUint8(update.Dest) + bf.WriteUint32(_old) + bf.WriteUint32(_new) + } + s.server.raviente.Unlock() + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) + if s.server.erupeConfig.GameplayOptions.LowLatencyRaviente { s.notifyRavi() } - s.server.raviente.Unlock() } func handleMsgSysLoadRegister(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysLoadRegister) - r := pkt.Unk1 - switch r { - case 12: - resp := byteframe.NewByteFrame() - resp.WriteUint8(0) - resp.WriteUint8(12) - resp.WriteUint32(s.server.raviente.register.nextTime) - resp.WriteUint32(s.server.raviente.register.startTime) - resp.WriteUint32(s.server.raviente.register.killedTime) - resp.WriteUint32(s.server.raviente.register.postTime) - resp.WriteUint32(s.server.raviente.register.register[0]) - resp.WriteUint32(s.server.raviente.register.carveQuest) - resp.WriteUint32(s.server.raviente.register.register[1]) - resp.WriteUint32(s.server.raviente.register.register[2]) - resp.WriteUint32(s.server.raviente.register.register[3]) - resp.WriteUint32(s.server.raviente.register.maxPlayers) - resp.WriteUint32(s.server.raviente.register.ravienteType) - resp.WriteUint32(s.server.raviente.register.register[4]) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - case 29: - resp := byteframe.NewByteFrame() - resp.WriteUint8(0) - resp.WriteUint8(29) - for _, v := range s.server.raviente.state.stateData { - resp.WriteUint32(v) + bf := byteframe.NewByteFrame() + bf.WriteUint8(0) + bf.WriteUint8(pkt.Values) + for i := uint8(0); i < pkt.Values; i++ { + switch pkt.RegisterID { + case 0x40000: + bf.WriteUint32(s.server.raviente.state[i]) + case 0x50000: + bf.WriteUint32(s.server.raviente.support[i]) + case 0x60000: + bf.WriteUint32(s.server.raviente.register[i]) } - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - case 25: - resp := byteframe.NewByteFrame() - resp.WriteUint8(0) - resp.WriteUint8(25) - for _, v := range s.server.raviente.support.supportData { - resp.WriteUint32(v) - } - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func (s *Session) notifyRavi() { - sema := getRaviSemaphore(s.server) + sema := s.server.getRaviSemaphore() if sema == nil { return } var temp mhfpacket.MHFPacket raviNotif := byteframe.NewByteFrame() - temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 4} + temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 0x40000} raviNotif.WriteUint16(uint16(temp.Opcode())) temp.Build(raviNotif, s.clientContext) - temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 5} + temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 0x50000} raviNotif.WriteUint16(uint16(temp.Opcode())) temp.Build(raviNotif, s.clientContext) - temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 6} + temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 0x60000} raviNotif.WriteUint16(uint16(temp.Opcode())) temp.Build(raviNotif, s.clientContext) raviNotif.WriteUint16(0x0010) // End it. @@ -272,28 +140,13 @@ func (s *Session) notifyRavi() { } } -func getRaviSemaphore(s *Server) *Semaphore { +func (s *Server) getRaviSemaphore() *Semaphore { for _, semaphore := range s.semaphore { - if strings.HasPrefix(semaphore.id_semaphore, "hs_l0u3B5") && strings.HasSuffix(semaphore.id_semaphore, "3") { + if strings.HasPrefix(semaphore.name, "hs_l0") && strings.HasSuffix(semaphore.name, "3") { return semaphore } } return nil } -func resetRavi(s *Session) { - s.server.raviente.Lock() - s.server.raviente.register.nextTime = 0 - s.server.raviente.register.startTime = 0 - s.server.raviente.register.killedTime = 0 - s.server.raviente.register.postTime = 0 - s.server.raviente.register.ravienteType = 0 - s.server.raviente.register.maxPlayers = 0 - s.server.raviente.register.carveQuest = 0 - s.server.raviente.register.register = []uint32{0, 0, 0, 0, 0} - s.server.raviente.state.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - s.server.raviente.support.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - s.server.raviente.Unlock() -} - func handleMsgSysNotifyRegister(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/handlers_semaphore.go b/server/channelserver/handlers_semaphore.go index 503df5110..19925c6d6 100644 --- a/server/channelserver/handlers_semaphore.go +++ b/server/channelserver/handlers_semaphore.go @@ -2,7 +2,6 @@ package channelserver import ( "erupe-ce/common/byteframe" - "fmt" "go.uber.org/zap" "strconv" "strings" @@ -13,9 +12,6 @@ import ( func removeSessionFromSemaphore(s *Session) { s.server.semaphoreLock.Lock() for _, semaphore := range s.server.semaphore { - if _, exists := semaphore.reservedClientSlots[s.charID]; exists { - delete(semaphore.reservedClientSlots, s.charID) - } if _, exists := semaphore.clients[s]; exists { delete(semaphore.clients, s) } @@ -31,48 +27,38 @@ func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) { func destructEmptySemaphores(s *Session) { s.server.semaphoreLock.Lock() for id, sema := range s.server.semaphore { - if len(sema.reservedClientSlots) == 0 && len(sema.clients) == 0 { - s.server.semaphoreLock.Unlock() + if len(sema.clients) == 0 { delete(s.server.semaphore, id) - s.server.semaphoreLock.Lock() - if strings.HasPrefix(id, "hs_l0u3B5") { - releaseRaviSemaphore(s, sema) + if strings.HasPrefix(id, "hs_l0") { + s.server.resetRaviente() } - s.logger.Debug("Destructed semaphore", zap.String("sema.id_semaphore", id)) + s.logger.Debug("Destructed semaphore", zap.String("sema.name", id)) } } s.server.semaphoreLock.Unlock() } -func releaseRaviSemaphore(s *Session, sema *Semaphore) { - delete(sema.reservedClientSlots, s.charID) - delete(sema.clients, s) - if strings.HasSuffix(sema.id_semaphore, "2") && len(sema.clients) == 0 { - s.logger.Debug("Main raviente semaphore is empty, resetting") - resetRavi(s) - } -} - func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysDeleteSemaphore) - if s.server.semaphore != nil { - destructEmptySemaphores(s) - s.server.semaphoreLock.Lock() - for id, sema := range s.server.semaphore { - if sema.id == pkt.SemaphoreID { - if strings.HasPrefix(id, "hs_l0u3B5") { - releaseRaviSemaphore(s, sema) - s.server.semaphoreLock.Unlock() - return + destructEmptySemaphores(s) + s.server.semaphoreLock.Lock() + for id, sema := range s.server.semaphore { + if sema.id == pkt.SemaphoreID { + for session := range sema.clients { + if s == session { + delete(sema.clients, s) } - s.server.semaphoreLock.Unlock() + } + if len(sema.clients) == 0 { delete(s.server.semaphore, id) - s.logger.Debug("Destructed semaphore", zap.String("sema.id_semaphore", id)) - return + if strings.HasPrefix(id, "hs_l0") { + s.server.resetRaviente() + } + s.logger.Debug("Destructed semaphore", zap.String("sema.name", id)) } } - s.server.semaphoreLock.Unlock() } + s.server.semaphoreLock.Unlock() } func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { @@ -80,18 +66,15 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { SemaphoreID := pkt.SemaphoreID newSemaphore, exists := s.server.semaphore[SemaphoreID] - - fmt.Printf("Got reserve stage req, StageID: %v\n\n", SemaphoreID) if !exists { s.server.semaphoreLock.Lock() - if strings.HasPrefix(SemaphoreID, "hs_l0u3B5") { + if strings.HasPrefix(SemaphoreID, "hs_l0") { suffix, _ := strconv.Atoi(pkt.SemaphoreID[len(pkt.SemaphoreID)-1:]) s.server.semaphore[SemaphoreID] = &Semaphore{ - id_semaphore: pkt.SemaphoreID, - id: uint32(suffix + 1), - clients: make(map[*Session]uint32), - reservedClientSlots: make(map[uint32]interface{}), - maxPlayers: 127, + name: pkt.SemaphoreID, + id: uint32((suffix + 1) * 0x10000), + clients: make(map[*Session]uint32), + maxPlayers: 127, } } else { s.server.semaphore[SemaphoreID] = NewSemaphore(s.server, SemaphoreID, 1) @@ -102,22 +85,19 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { newSemaphore.Lock() defer newSemaphore.Unlock() - if _, exists := newSemaphore.reservedClientSlots[s.charID]; exists { - bf := byteframe.NewByteFrame() + bf := byteframe.NewByteFrame() + if _, exists := newSemaphore.clients[s]; exists { bf.WriteUint32(newSemaphore.id) - doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) - } else if uint16(len(newSemaphore.reservedClientSlots)) < newSemaphore.maxPlayers { - newSemaphore.reservedClientSlots[s.charID] = nil + } else if uint16(len(newSemaphore.clients)) < newSemaphore.maxPlayers { newSemaphore.clients[s] = s.charID s.Lock() s.semaphore = newSemaphore s.Unlock() - bf := byteframe.NewByteFrame() bf.WriteUint32(newSemaphore.id) - doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } else { - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + bf.WriteUint32(0) } + doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { @@ -130,7 +110,6 @@ func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { } else { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) } - } func handleMsgSysReleaseSemaphore(s *Session, p mhfpacket.MHFPacket) { diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index cad64bbe4..5a4b29fe9 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -3,6 +3,7 @@ package channelserver import ( "fmt" "net" + "strings" "sync" "erupe-ce/common/byteframe" @@ -76,61 +77,30 @@ type Server struct { type Raviente struct { sync.Mutex - - register *RavienteRegister - state *RavienteState - support *RavienteSupport + id uint16 + register []uint32 + state []uint32 + support []uint32 } -type RavienteRegister struct { - nextTime uint32 - startTime uint32 - postTime uint32 - killedTime uint32 - ravienteType uint32 - maxPlayers uint32 - carveQuest uint32 - register []uint32 -} - -type RavienteState struct { - stateData []uint32 -} - -type RavienteSupport struct { - supportData []uint32 -} - -// Set up the Raviente variables for the server -func NewRaviente() *Raviente { - ravienteRegister := &RavienteRegister{ - nextTime: 0, - startTime: 0, - killedTime: 0, - postTime: 0, - ravienteType: 0, - maxPlayers: 0, - carveQuest: 0, +func (s *Server) resetRaviente() { + for _, semaphore := range s.semaphore { + if strings.HasPrefix(semaphore.name, "hs_l0") { + return + } } - ravienteState := &RavienteState{} - ravienteSupport := &RavienteSupport{} - ravienteRegister.register = []uint32{0, 0, 0, 0, 0} - ravienteState.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - ravienteSupport.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - - raviente := &Raviente{ - register: ravienteRegister, - state: ravienteState, - support: ravienteSupport, - } - return raviente + s.logger.Debug("All Raviente Semaphores empty, resetting") + s.raviente.id = s.raviente.id + 1 + s.raviente.register = make([]uint32, 30) + s.raviente.state = make([]uint32, 30) + s.raviente.support = make([]uint32, 30) } -func (r *Raviente) GetRaviMultiplier(s *Server) float64 { - raviSema := getRaviSemaphore(s) +func (s *Server) GetRaviMultiplier() float64 { + raviSema := s.getRaviSemaphore() if raviSema != nil { var minPlayers int - if r.register.maxPlayers > 8 { + if s.raviente.register[9] > 8 { minPlayers = 24 } else { minPlayers = 4 @@ -143,6 +113,40 @@ func (r *Raviente) GetRaviMultiplier(s *Server) float64 { return 0 } +func (s *Server) UpdateRavi(semaID uint32, index uint8, value uint32, update bool) (uint32, uint32) { + var prev uint32 + switch semaID { + case 0x40000: + switch index { + case 17, 28: // Ignore res and poison + break + default: + value = uint32(float64(value) * s.GetRaviMultiplier()) + } + prev = s.raviente.state[index] + if prev != 0 && !update { + return prev, prev + } + s.raviente.state[index] += value + return prev, s.raviente.state[index] + case 0x50000: + prev = s.raviente.support[index] + if prev != 0 && !update { + return prev, prev + } + s.raviente.support[index] += value + return prev, s.raviente.support[index] + case 0x60000: + prev = s.raviente.register[index] + if prev != 0 && !update { + return prev, prev + } + s.raviente.register[index] += value + return prev, s.raviente.register[index] + } + return 0, 0 +} + // NewServer creates a new Server type. func NewServer(config *Config) *Server { s := &Server{ @@ -160,7 +164,12 @@ func NewServer(config *Config) *Server { semaphoreIndex: 7, discordBot: config.DiscordBot, name: config.Name, - raviente: NewRaviente(), + raviente: &Raviente{ + id: 1, + register: make([]uint32, 30), + state: make([]uint32, 30), + support: make([]uint32, 30), + }, } // Mezeporta @@ -393,15 +402,16 @@ func (s *Server) NextSemaphoreID() uint32 { for { exists := false s.semaphoreIndex = s.semaphoreIndex + 1 - if s.semaphoreIndex == 0 { - s.semaphoreIndex = 7 // Skip reserved indexes + if s.semaphoreIndex > 0xFFFF { + s.semaphoreIndex = 1 } for _, semaphore := range s.semaphore { if semaphore.id == s.semaphoreIndex { exists = true + break } } - if exists == false { + if !exists { break } } diff --git a/server/channelserver/sys_language.go b/server/channelserver/sys_language.go index 418e1cecb..dbd48cfb8 100644 --- a/server/channelserver/sys_language.go +++ b/server/channelserver/sys_language.go @@ -34,6 +34,7 @@ func getLangStrings(s *Server) map[string]string { strings["commandRaviRequest"] = "鎮静支援を要請します" strings["commandRaviError"] = "ラヴィコマンドが認識されません" strings["commandRaviNoPlayers"] = "誰も大討伐に参加していません" + strings["commandRaviVersion"] = "This command is disabled outside of MHFZZ" strings["ravienteBerserk"] = "<大討伐:猛狂期>が開催されました!" strings["ravienteExtreme"] = "<大討伐:猛狂期【極】>が開催されました!" @@ -85,6 +86,7 @@ func getLangStrings(s *Server) map[string]string { strings["commandRaviRequest"] = "Requesting sedation support!" strings["commandRaviError"] = "Raviente command not recognised!" strings["commandRaviNoPlayers"] = "No one has joined the Great Slaying!" + strings["commandRaviVersion"] = "This command is disabled outside of MHFZZ" strings["ravienteBerserk"] = " is being held!" strings["ravienteExtreme"] = " is being held!" diff --git a/server/channelserver/sys_semaphore.go b/server/channelserver/sys_semaphore.go index 369e481b6..78ff963b5 100644 --- a/server/channelserver/sys_semaphore.go +++ b/server/channelserver/sys_semaphore.go @@ -7,55 +7,35 @@ import ( "sync" ) -// Stage holds stage-specific information +// Semaphore holds Semaphore-specific information type Semaphore struct { sync.RWMutex - // Stage ID string - id_semaphore string + // Semaphore ID string + name string id uint32 // Map of session -> charID. - // These are clients that are CURRENTLY in the stage + // These are clients that are registered to the Semaphore clients map[*Session]uint32 - // Map of charID -> interface{}, only the key is used, value is always nil. - reservedClientSlots map[uint32]interface{} - // Max Players for Semaphore maxPlayers uint16 } -// NewStage creates a new stage with intialized values. +// NewSemaphore creates a new Semaphore with intialized values func NewSemaphore(s *Server, ID string, MaxPlayers uint16) *Semaphore { sema := &Semaphore{ - id_semaphore: ID, - id: s.NextSemaphoreID(), - clients: make(map[*Session]uint32), - reservedClientSlots: make(map[uint32]interface{}), - maxPlayers: MaxPlayers, + name: ID, + id: s.NextSemaphoreID(), + clients: make(map[*Session]uint32), + maxPlayers: MaxPlayers, } return sema } -func (s *Semaphore) BroadcastRavi(pkt mhfpacket.MHFPacket) { - // Broadcast the data. - for session := range s.clients { - - // Make the header - bf := byteframe.NewByteFrame() - bf.WriteUint16(uint16(pkt.Opcode())) - - // Build the packet onto the byteframe. - pkt.Build(bf, session.clientContext) - - // Enqueue in a non-blocking way that drops the packet if the connections send buffer channel is full. - session.QueueSendNonBlocking(bf.Data()) - } -} - -// BroadcastMHF queues a MHFPacket to be sent to all sessions in the stage. +// BroadcastMHF queues a MHFPacket to be sent to all sessions in the Semaphore func (s *Semaphore) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { // Broadcast the data. for session := range s.clients {