Merge branch 'main' of https://github.com/ZeruLight/Erupe into feautre/event-tent

This commit is contained in:
straticspaff
2023-11-18 05:36:28 +00:00
5 changed files with 64 additions and 18 deletions

View File

@@ -12,6 +12,7 @@
"ScreenshotAPIURL": "", "ScreenshotAPIURL": "",
"DeleteOnSaveCorruption": false, "DeleteOnSaveCorruption": false,
"ClientMode": "ZZ", "ClientMode": "ZZ",
"QuestCacheExpiry": 300,
"DevMode": true, "DevMode": true,
"DevModeOptions": { "DevModeOptions": {
"AutoCreateAccount": true, "AutoCreateAccount": true,

View File

@@ -79,6 +79,7 @@ type Config struct {
DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion
ClientMode string ClientMode string
RealClientMode Mode RealClientMode Mode
QuestCacheExpiry int // Number of seconds to keep quest data cached
DevMode bool DevMode bool
DevModeOptions DevModeOptions DevModeOptions DevModeOptions

View File

@@ -0,0 +1,5 @@
BEGIN;
ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS flags integer;
END;

View File

@@ -47,6 +47,10 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
) )
} }
if s.server.erupeConfig.GameplayOptions.SeasonOverride {
pkt.Filename = seasonConversion(s, pkt.Filename)
}
data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))) data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename)))
if err != nil { if err != nil {
s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename)) s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename))
@@ -58,6 +62,33 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
} }
} }
func seasonConversion(s *Session, questFile string) string {
filename := fmt.Sprintf("%s%d", questFile[:6], s.server.Season())
// Return the seasonal file
if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", filename))); err == nil {
return filename
} else {
// Attempt to return the requested quest file if the seasonal file doesn't exist
if _, err = os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", questFile))); err == nil {
return questFile
}
// If the code reaches this point, it's most likely a custom quest with no seasonal variations in the files.
// Since event quests when seasonal pick day or night and the client requests either one, we need to differentiate between the two to prevent issues.
var _time string
if TimeGameAbsolute() > 2880 {
_time = "d"
} else {
_time = "n"
}
// Request a d0 or n0 file depending on the time of day. The time of day matters and issues will occur if it's different to the one it requests.
return fmt.Sprintf("%s%s%d", questFile[:5], _time, 0)
}
}
func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadFavoriteQuest) pkt := p.(*mhfpacket.MsgMhfLoadFavoriteQuest)
var data []byte var data []byte
@@ -77,6 +108,11 @@ func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
} }
func loadQuestFile(s *Session, questId int) []byte { func loadQuestFile(s *Session, questId int) []byte {
data, exists := s.server.questCacheData[questId]
if exists && s.server.questCacheTime[questId].Add(time.Duration(s.server.erupeConfig.QuestCacheExpiry)*time.Second).After(time.Now()) {
return data
}
file, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%05dd0.bin", questId))) file, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%05dd0.bin", questId)))
if err != nil { if err != nil {
return nil return nil
@@ -113,14 +149,16 @@ func loadQuestFile(s *Session, questId int) []byte {
} }
questBody.WriteBytes(newStrings.Data()) questBody.WriteBytes(newStrings.Data())
s.server.questCacheData[questId] = questBody.Data()
s.server.questCacheTime[questId] = time.Now()
return questBody.Data() return questBody.Data()
} }
func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) {
var id, mark uint32 var id, mark uint32
var questId int var questId, flags int
var maxPlayers, questType uint8 var maxPlayers, questType uint8
rows.Scan(&id, &maxPlayers, &questType, &questId, &mark) rows.Scan(&id, &maxPlayers, &questType, &questId, &mark, &flags)
data := loadQuestFile(s, questId) data := loadQuestFile(s, questId)
if data == nil { if data == nil {
@@ -168,7 +206,12 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) {
if s.server.erupeConfig.GameplayOptions.SeasonOverride { if s.server.erupeConfig.GameplayOptions.SeasonOverride {
bf.WriteUint8(flagByte & 0b11100000) bf.WriteUint8(flagByte & 0b11100000)
} else { } else {
bf.WriteUint8(flagByte) // Allow for seasons to be specified in database, otherwise use the one in the file.
if flags < 0 {
bf.WriteUint8(flagByte)
} else {
bf.WriteUint8(uint8(flags))
}
} }
// Bitset Structure Quest Variant 1: b8 UL Fixed, b7 UNK, b6 UNK, b5 UNK, b4 G Rank, b3 HC to UL, b2 Fix HC, b1 Hiden // Bitset Structure Quest Variant 1: b8 UL Fixed, b7 UNK, b6 UNK, b5 UNK, b4 G Rank, b3 HC to UL, b2 Fix HC, b1 Hiden
@@ -192,7 +235,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
bf.WriteUint16(0) bf.WriteUint16(0)
rows, _ := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark FROM event_quests ORDER BY quest_id") rows, _ := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark, COALESCE(flags, -1) FROM event_quests ORDER BY quest_id")
for rows.Next() { for rows.Next() {
data, err := makeEventQuest(s, rows) data, err := makeEventQuest(s, rows)
if err != nil { if err != nil {
@@ -202,18 +245,10 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
continue continue
} else { } else {
totalCount++ totalCount++
if _config.ErupeConfig.RealClientMode == _config.F5 { if totalCount > pkt.Offset && len(bf.Data()) < 60000 {
if totalCount > pkt.Offset && len(bf.Data()) < 21550 { returnedCount++
returnedCount++ bf.WriteBytes(data)
bf.WriteBytes(data) continue
continue
}
} else {
if totalCount > pkt.Offset && len(bf.Data()) < 60000 {
returnedCount++
bf.WriteBytes(data)
continue
}
} }
} }
} }

View File

@@ -5,6 +5,7 @@ import (
"net" "net"
"strings" "strings"
"sync" "sync"
"time"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring" ps "erupe-ce/common/pascalstring"
@@ -73,6 +74,9 @@ type Server struct {
name string name string
raviente *Raviente raviente *Raviente
questCacheData map[int][]byte
questCacheTime map[int]time.Time
} }
type Raviente struct { type Raviente struct {
@@ -163,6 +167,8 @@ func NewServer(config *Config) *Server {
state: make([]uint32, 30), state: make([]uint32, 30),
support: make([]uint32, 30), support: make([]uint32, 30),
}, },
questCacheData: make(map[int][]byte),
questCacheTime: make(map[int]time.Time),
} }
// Mezeporta // Mezeporta
@@ -316,7 +322,6 @@ func (s *Server) BroadcastChatMessage(message string) {
msgBinChat.Build(bf) msgBinChat.Build(bf)
s.BroadcastMHF(&mhfpacket.MsgSysCastedBinary{ s.BroadcastMHF(&mhfpacket.MsgSysCastedBinary{
CharID: 0xFFFFFFFF,
MessageType: BinaryMessageTypeChat, MessageType: BinaryMessageTypeChat,
RawDataPayload: bf.Data(), RawDataPayload: bf.Data(),
}, nil) }, nil)
@@ -348,7 +353,6 @@ func (s *Server) BroadcastRaviente(ip uint32, port uint16, stage []byte, _type u
bf.WriteUint16(0) // Unk bf.WriteUint16(0) // Unk
bf.WriteBytes(stage) bf.WriteBytes(stage)
s.WorldcastMHF(&mhfpacket.MsgSysCastedBinary{ s.WorldcastMHF(&mhfpacket.MsgSysCastedBinary{
CharID: 0x00000000,
BroadcastType: BroadcastTypeServer, BroadcastType: BroadcastTypeServer,
MessageType: BinaryMessageTypeChat, MessageType: BinaryMessageTypeChat,
RawDataPayload: bf.Data(), RawDataPayload: bf.Data(),