Merge branch 'main' of github.com:ZeruLight/Erupe

This commit is contained in:
wish
2023-07-29 17:21:58 +10:00
12 changed files with 2688 additions and 73 deletions

View File

@@ -4,6 +4,7 @@ import (
"erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring"
"erupe-ce/network/mhfpacket"
"go.uber.org/zap"
)

View File

@@ -1,14 +1,18 @@
package channelserver
import (
"database/sql"
"erupe-ce/common/byteframe"
"erupe-ce/common/decryption"
ps "erupe-ce/common/pascalstring"
"erupe-ce/network/mhfpacket"
"fmt"
"go.uber.org/zap"
"io"
"os"
"path/filepath"
"time"
"go.uber.org/zap"
)
func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
@@ -35,29 +39,47 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
}
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, "quest_override.bin")); err == nil {
data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "quest_override.bin"))
if err != nil {
panic(err)
}
doAckBufSucceed(s, pkt.AckHandle, data)
} else {
if s.server.erupeConfig.DevModeOptions.QuestDebugTools && s.server.erupeConfig.DevMode {
s.logger.Debug(
"Quest",
zap.String("Filename", pkt.Filename),
)
}
// Get quest file.
data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename)))
if err != nil {
s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename))
// This will crash the game.
doAckBufSucceed(s, pkt.AckHandle, data)
return
}
doAckBufSucceed(s, pkt.AckHandle, data)
if s.server.erupeConfig.DevModeOptions.QuestDebugTools && s.server.erupeConfig.DevMode {
s.logger.Debug(
"Quest",
zap.String("Filename", pkt.Filename),
)
}
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)))
if err != nil {
s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename))
// This will crash the game.
doAckBufSucceed(s, pkt.AckHandle, data)
return
}
doAckBufSucceed(s, pkt.AckHandle, data)
}
}
func questSuffix(s *Session) string {
// Determine the letter to append for day / night
var timeSet string
if TimeGameAbsolute() > 2880 {
timeSet = "d"
} else {
timeSet = "n"
}
return fmt.Sprintf("%s%d", timeSet, s.server.Season())
}
func seasonConversion(s *Session, questFile string) string {
filename := fmt.Sprintf("%s%s", questFile[:5], questSuffix(s))
// Return original file if file doesn't exist
if _, err := os.Stat(filename); err == nil {
return filename
} else {
return questFile
}
}
@@ -79,34 +101,111 @@ func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
func loadQuestFile(s *Session, questId int) []byte {
file, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%05dd0.bin", questId)))
if err != nil {
return nil
}
decrypted := decryption.UnpackSimple(file)
fileBytes := byteframe.NewByteFrameFromBytes(decrypted)
fileBytes.SetLE()
fileBytes.Seek(int64(fileBytes.ReadUint32()), 0)
// The 320 bytes directly following the data pointer must go directly into the event's body, after the header and before the string pointers.
questBody := byteframe.NewByteFrameFromBytes(fileBytes.ReadBytes(320))
questBody.SetLE()
// Find the master quest string pointer
questBody.Seek(40, 0)
fileBytes.Seek(int64(questBody.ReadUint32()), 0)
questBody.Seek(40, 0)
// Overwrite it
questBody.WriteUint32(320)
questBody.Seek(0, 2)
// Rewrite the quest strings and their pointers
var tempString []byte
newStrings := byteframe.NewByteFrame()
tempPointer := 352
for i := 0; i < 8; i++ {
questBody.WriteUint32(uint32(tempPointer))
temp := int64(fileBytes.Index())
fileBytes.Seek(int64(fileBytes.ReadUint32()), 0)
tempString = fileBytes.ReadNullTerminatedBytes()
fileBytes.Seek(temp+4, 0)
tempPointer += len(tempString) + 1
newStrings.WriteNullTerminatedBytes(tempString)
}
questBody.WriteBytes(newStrings.Data())
return questBody.Data()
}
func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) {
var id, mark uint32
var questId int
var maxPlayers, questType uint8
rows.Scan(&id, &maxPlayers, &questType, &questId, &mark)
data := loadQuestFile(s, questId)
if data == nil {
return nil, fmt.Errorf("failed to load quest file")
}
bf := byteframe.NewByteFrame()
bf.WriteUint32(id)
bf.WriteUint32(0)
bf.WriteUint8(0) // Indexer
switch questType {
case 16:
bf.WriteUint8(s.server.erupeConfig.GameplayOptions.RegularRavienteMaxPlayers)
case 22:
bf.WriteUint8(s.server.erupeConfig.GameplayOptions.ViolentRavienteMaxPlayers)
case 40:
bf.WriteUint8(s.server.erupeConfig.GameplayOptions.BerserkRavienteMaxPlayers)
case 50:
bf.WriteUint8(s.server.erupeConfig.GameplayOptions.ExtremeRavienteMaxPlayers)
case 51:
bf.WriteUint8(s.server.erupeConfig.GameplayOptions.SmallBerserkRavienteMaxPlayers)
default:
bf.WriteUint8(maxPlayers)
}
bf.WriteUint8(questType)
bf.WriteUint8(0)
bf.WriteUint16(0)
bf.WriteUint32(mark)
bf.WriteUint16(0)
bf.WriteUint16(uint16(len(data)))
bf.WriteBytes(data)
ps.Uint8(bf, "", true) // What is this string for?
return bf.Data(), nil
}
func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateQuest)
var totalCount, returnedCount uint16
bf := byteframe.NewByteFrame()
bf.WriteUint16(0)
filepath.Walk(fmt.Sprintf("%s/events/", s.server.erupeConfig.BinPath), func(path string, info os.FileInfo, err error) error {
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")
for rows.Next() {
data, err := makeEventQuest(s, rows)
if err != nil {
return err
} else if info.IsDir() {
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return err
continue
} else {
if len(data) > 850 || len(data) < 400 {
return nil // Could be more or less strict with size limits
if len(data) > 896 || len(data) < 352 {
continue
} else {
totalCount++
if totalCount > pkt.Offset && len(bf.Data()) < 60000 {
returnedCount++
bf.WriteBytes(data)
return nil
continue
}
}
}
return nil
})
}
type tuneValue struct {
ID uint16
@@ -554,6 +653,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(pkt.Offset)
bf.Seek(0, io.SeekStart)
bf.WriteUint16(returnedCount)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}

View File

@@ -405,3 +405,8 @@ func (s *Server) NextSemaphoreID() uint32 {
}
return s.semaphoreIndex
}
func (s *Server) Season() uint8 {
sid := int64(((s.ID & 0xFF00) - 4096) / 256)
return uint8(((TimeAdjusted().Unix() / 86400) + sid) % 3)
}

View File

@@ -23,3 +23,7 @@ func TimeWeekStart() time.Time {
func TimeWeekNext() time.Time {
return TimeWeekStart().Add(time.Hour * 24 * 7)
}
func TimeGameAbsolute() uint32 {
return uint32((TimeAdjusted().Unix() - 2160) % 5760)
}

View File

@@ -12,9 +12,6 @@ import (
"erupe-ce/server/channelserver"
)
// Server Entries
var season uint8
// Server Channels
var currentplayers uint16
@@ -34,11 +31,8 @@ func encodeServerInfo(config *_config.Config, s *Server, local bool) []byte {
continue
}
}
sid := (4096 + serverIdx*256) + 16
err := s.db.QueryRow("SELECT season FROM servers WHERE server_id=$1", sid).Scan(&season)
if err != nil {
season = 0
}
sid := (4096 + serverIdx*256) * 6000
if si.IP == "" {
si.IP = config.Host
}
@@ -51,7 +45,7 @@ func encodeServerInfo(config *_config.Config, s *Server, local bool) []byte {
bf.WriteUint16(0x0000)
bf.WriteUint16(uint16(len(si.Channels)))
bf.WriteUint8(si.Type)
bf.WriteUint8(season)
bf.WriteUint8(uint8(((channelserver.TimeAdjusted().Unix() / 86400) + int64(serverIdx)) % 3))
if s.erupeConfig.RealClientMode >= _config.G1 {
bf.WriteUint8(si.Recommended)
}