mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 07:32:32 +01:00
fix: validate quest file existence in seasonConversion fallbacks
The final fallback in seasonConversion blindly constructed a filename without checking if it existed on disk. When the file was missing, handleMsgSysGetFile would send doAckBufFail, but the original Frontier client does not gracefully handle this during quest loading — causing a softlock instead of showing the built-in error dialog. Now every fallback path validates file existence before returning, and also tries the opposite time-of-day variant as a last resort. If no file variant exists at all, the original filename is returned with a warning log so the failure ack is still sent.
This commit is contained in:
@@ -139,31 +139,57 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func questFileExists(s *Session, filename string) bool {
|
||||||
|
_, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", filename)))
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
func seasonConversion(s *Session, questFile string) string {
|
func seasonConversion(s *Session, questFile string) string {
|
||||||
|
// Try the seasonal override file (e.g., 00001d2 for season 2)
|
||||||
filename := fmt.Sprintf("%s%d", questFile[:6], s.server.Season())
|
filename := fmt.Sprintf("%s%d", questFile[:6], s.server.Season())
|
||||||
|
if questFileExists(s, filename) {
|
||||||
// Return the seasonal file
|
|
||||||
if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", filename))); err == nil {
|
|
||||||
return filename
|
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try the originally requested file as-is
|
||||||
|
if questFileExists(s, questFile) {
|
||||||
|
return questFile
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try constructing a day/night base file (e.g., 00001d0 or 00001n0).
|
||||||
|
// Quest filenames are formatted as [5-digit ID][d/n][season]: e.g., "00001d0".
|
||||||
|
var currentTime, oppositeTime string
|
||||||
|
if TimeGameAbsolute() > 2880 {
|
||||||
|
currentTime = "d"
|
||||||
|
oppositeTime = "n"
|
||||||
|
} else {
|
||||||
|
currentTime = "n"
|
||||||
|
oppositeTime = "d"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try current time-of-day base variant
|
||||||
|
dayNightFile := fmt.Sprintf("%s%s%d", questFile[:5], currentTime, 0)
|
||||||
|
if questFileExists(s, dayNightFile) {
|
||||||
|
return dayNightFile
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try opposite time-of-day base variant as last resort
|
||||||
|
oppositeFile := fmt.Sprintf("%s%s%d", questFile[:5], oppositeTime, 0)
|
||||||
|
if questFileExists(s, oppositeFile) {
|
||||||
|
s.logger.Warn("Quest file not found for current time, using opposite variant",
|
||||||
|
zap.String("requested", questFile),
|
||||||
|
zap.String("using", oppositeFile),
|
||||||
|
)
|
||||||
|
return oppositeFile
|
||||||
|
}
|
||||||
|
|
||||||
|
// No valid file found. Return the original request so handleMsgSysGetFile
|
||||||
|
// sends doAckBufFail, which triggers the client's error dialog
|
||||||
|
// (snj_questd_matching_fail → SetDialogData) instead of a softlock.
|
||||||
|
s.logger.Warn("No quest file variant found for any season or time-of-day",
|
||||||
|
zap.String("requested", questFile),
|
||||||
|
)
|
||||||
|
return questFile
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
|||||||
Reference in New Issue
Block a user