Merge branch 'ZeruLight:main' into feature/discord-login

This commit is contained in:
Matthew
2023-11-26 09:18:54 -08:00
committed by GitHub
18 changed files with 126 additions and 122 deletions

View File

@@ -13,6 +13,7 @@
"DeleteOnSaveCorruption": false,
"ClientMode": "ZZ",
"QuestCacheExpiry": 300,
"ProxyPort": 0,
"DevMode": true,
"DevModeOptions": {
"AutoCreateAccount": true,
@@ -25,8 +26,6 @@
"DivaEvent": 0,
"FestaEvent": -1,
"TournamentEvent": 0,
"MezFesEvent": true,
"MezFesAlt": false,
"DisableTokenCheck": false,
"QuestDebugTools": false,
"EarthStatusOverride": 0,
@@ -45,8 +44,8 @@
"TreasureHuntExpiry": 604800,
"DisableLoginBoost": false,
"DisableBoostTime": false,
"BoostTimeDuration": 120,
"GuildMealDuration": 60,
"BoostTimeDuration": 7200,
"GuildMealDuration": 3600,
"BonusQuestAllowance": 3,
"DailyQuestAllowance": 1,
"MezfesSoloTickets": 10,
@@ -65,6 +64,8 @@
"MaterialMultiplier": 1.00,
"ExtraCarves": 0,
"DisableHunterNavi": false,
"MezFesDuration": 172800,
"MezFesSwitchMinigame": false,
"EnableKaijiEvent": false,
"EnableHiganjimaEvent": false,
"EnableNierEvent": false,

View File

@@ -79,7 +79,8 @@ type Config struct {
DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion
ClientMode string
RealClientMode Mode
QuestCacheExpiry int // Number of seconds to keep quest data cached
QuestCacheExpiry int // Number of seconds to keep quest data cached
ProxyPort uint16 // Forces the game to connect to a channel server proxy
DevMode bool
DevModeOptions DevModeOptions
@@ -106,8 +107,6 @@ type DevModeOptions struct {
DivaEvent int // Diva Defense event status
FestaEvent int // Hunter's Festa event status
TournamentEvent int // VS Tournament event status
MezFesEvent bool // MezFes status
MezFesAlt bool // Swaps out Volpakkun for Tokotoko
DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!)
QuestDebugTools bool // Enable various quest debug logs
EarthStatusOverride int32
@@ -131,8 +130,8 @@ type GameplayOptions struct {
TreasureHuntPartnyaCooldown uint32 // Seconds until a Partnya can be assigned to another Clan Treasure Hunt
DisableLoginBoost bool // Disables the Login Boost system
DisableBoostTime bool // Disables the daily NetCafe Boost Time
BoostTimeDuration int // The number of minutes NetCafe Boost Time lasts for
GuildMealDuration int // The number of minutes a Guild Meal can be activated for after cooking
BoostTimeDuration int // Second that the NetCafe Boost Time lasts
GuildMealDuration int // Second that a Guild Meal can be activated for after cooking
BonusQuestAllowance uint32 // Number of Bonus Point Quests to allow daily
DailyQuestAllowance uint32 // Number of Daily Quests to allow daily
MezfesSoloTickets uint32 // Number of solo tickets given weekly
@@ -151,6 +150,8 @@ type GameplayOptions struct {
MaterialMultiplier float32 // Adjusts the multiplier of Monster Materials rewarded for quest completion
ExtraCarves uint16 // Grant n extra chances to carve ALL carcasses
DisableHunterNavi bool // Disables the Hunter Navi
MezFesDuration int // Seconds that MezFes will last for weekly (from 12AM Mon backwards)
MezFesSwitchMinigame bool // Swaps out Volpakkun Together for Tokotoko Partnya
EnableKaijiEvent bool // Enables the Kaiji event in the Rasta Bar
EnableHiganjimaEvent bool // Enables the Higanjima event in the Rasta Bar
EnableNierEvent bool // Enables the Nier event in the Rasta Bar

12
main.go
View File

@@ -22,11 +22,13 @@ import (
)
// Temporary DB auto clean on startup for quick development & testing.
func cleanDB(db *sqlx.DB) {
func cleanDB(db *sqlx.DB, config *_config.Config) {
_ = db.MustExec("DELETE FROM guild_characters")
_ = db.MustExec("DELETE FROM guilds")
_ = db.MustExec("DELETE FROM characters")
_ = db.MustExec("DELETE FROM sign_sessions")
if config.ProxyPort == 0 {
_ = db.MustExec("DELETE FROM sign_sessions")
}
_ = db.MustExec("DELETE FROM users")
}
@@ -124,14 +126,16 @@ func main() {
logger.Info("Database: Started successfully")
// Clear stale data
_ = db.MustExec("DELETE FROM sign_sessions")
if config.ProxyPort == 0 {
_ = db.MustExec("DELETE FROM sign_sessions")
}
_ = db.MustExec("DELETE FROM servers")
_ = db.MustExec(`UPDATE guild_characters SET treasure_hunt=NULL`)
// Clean the DB if the option is on.
if config.DevMode && config.DevModeOptions.CleanDB {
logger.Info("Database: Started clearing...")
cleanDB(db)
cleanDB(db, config)
logger.Info("Database: Finished clearing")
}

View File

@@ -3,7 +3,6 @@ package mhfpacket
import (
"errors"
"erupe-ce/common/byteframe"
"erupe-ce/common/bfutil"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
@@ -13,7 +12,7 @@ type MsgSysCreateStage struct {
AckHandle uint32
Unk0 uint8 // Likely only has 1 and 2 as values.
PlayerCount uint8
StageID string // NULL terminated string.
StageID string
}
// Opcode returns the ID associated with this packet type.
@@ -26,8 +25,8 @@ func (m *MsgSysCreateStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8()
m.PlayerCount = bf.ReadUint8()
stageIDLength := bf.ReadUint8()
m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength))))
bf.ReadUint8() // Length StageID
m.StageID = string(bf.ReadNullTerminatedBytes())
return nil
}

View File

@@ -11,7 +11,7 @@ import (
// MsgSysEnterStage represents the MSG_SYS_ENTER_STAGE
type MsgSysEnterStage struct {
AckHandle uint32
UnkBool uint8
Unk bool
StageID string
}
@@ -23,8 +23,8 @@ func (m *MsgSysEnterStage) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgSysEnterStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.UnkBool = bf.ReadUint8()
bf.ReadUint8()
m.Unk = bf.ReadBool() // IsQuest?
bf.ReadUint8() // Length StageID
m.StageID = string(bf.ReadNullTerminatedBytes())
return nil
}

View File

@@ -2,8 +2,6 @@ package mhfpacket
import (
"errors"
"erupe-ce/common/stringsupport"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
@@ -12,8 +10,7 @@ import (
// MsgSysEnumerateStage represents the MSG_SYS_ENUMERATE_STAGE
type MsgSysEnumerateStage struct {
AckHandle uint32
Unk0 uint8 // Hardcoded 1 in the binary
StagePrefix string // NULL terminated string.
StagePrefix string
}
// Opcode returns the ID associated with this packet type.
@@ -24,9 +21,9 @@ func (m *MsgSysEnumerateStage) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgSysEnumerateStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8()
bf.ReadUint8()
m.StagePrefix = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
bf.ReadUint8() // Always 1
bf.ReadUint8() // Length StagePrefix
m.StagePrefix = string(bf.ReadNullTerminatedBytes())
return nil
}

View File

@@ -1,20 +1,17 @@
package mhfpacket
import (
"errors"
import (
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
// MsgSysLockStage represents the MSG_SYS_LOCK_STAGE
type MsgSysLockStage struct {
AckHandle uint32
Unk0 uint8 // Hardcoded 1 in the binary
Unk1 uint8 // Hardcoded 1 in the binary
StageIDLength uint8
StageID string
AckHandle uint32
StageID string
}
// Opcode returns the ID associated with this packet type.
@@ -25,10 +22,10 @@ func (m *MsgSysLockStage) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgSysLockStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8()
m.Unk1 = bf.ReadUint8()
m.StageIDLength = bf.ReadUint8()
m.StageID = string(bf.ReadBytes(uint(m.StageIDLength)))
bf.ReadUint8() // Always 1
bf.ReadUint8() // Always 1
bf.ReadUint8() // Length StageID
m.StageID = string(bf.ReadNullTerminatedBytes())
return nil
}

View File

@@ -1,15 +1,14 @@
package mhfpacket
import (
"errors"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
"erupe-ce/common/byteframe"
)
// MsgSysUnlockStage represents the MSG_SYS_UNLOCK_STAGE
type MsgSysUnlockStage struct {
Unk0 uint16 // Hardcoded 0 in the binary.
}
type MsgSysUnlockStage struct{}
// Opcode returns the ID associated with this packet type.
func (m *MsgSysUnlockStage) Opcode() network.PacketID {
@@ -18,12 +17,11 @@ func (m *MsgSysUnlockStage) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgSysUnlockStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.Unk0 = bf.ReadUint16()
bf.ReadUint16() // Zeroed
return nil
}
// Build builds a binary packet from the current data.
func (m *MsgSysUnlockStage) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
bf.WriteUint16(m.Unk0)
return nil
return errors.New("NOT IMPLEMENTED")
}

View File

@@ -378,7 +378,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
if session.charID == CharID {
count++
sessionName := stringsupport.UTF8ToSJIS(session.Name)
sessionStage := stringsupport.UTF8ToSJIS(session.stageID)
sessionStage := stringsupport.UTF8ToSJIS(session.stage.id)
resp.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4()))
resp.WriteUint16(c.Port)
resp.WriteUint32(session.charID)
@@ -408,7 +408,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
if strings.Contains(session.Name, searchTerm) {
count++
sessionName := stringsupport.UTF8ToSJIS(session.Name)
sessionStage := stringsupport.UTF8ToSJIS(session.stageID)
sessionStage := stringsupport.UTF8ToSJIS(session.stage.id)
resp.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4()))
resp.WriteUint16(c.Port)
resp.WriteUint32(session.charID)
@@ -445,7 +445,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
hrp := uint16(1)
gr := uint16(0)
s.server.db.QueryRow("SELECT hrp, gr FROM characters WHERE id=$1", session.charID).Scan(&hrp, &gr)
sessionStage := stringsupport.UTF8ToSJIS(session.stageID)
sessionStage := stringsupport.UTF8ToSJIS(session.stage.id)
sessionName := stringsupport.UTF8ToSJIS(session.Name)
resp.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4()))
resp.WriteUint16(c.Port)
@@ -988,8 +988,8 @@ func handleMsgMhfKickExportForce(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetEarthStatus)
bf := byteframe.NewByteFrame()
bf.WriteUint32(uint32(TimeWeekStart().Add(time.Hour * -24).Unix())) // Start
bf.WriteUint32(uint32(TimeWeekNext().Add(time.Hour * 24).Unix())) // End
bf.WriteUint32(uint32(TimeWeekStart().Unix())) // Start
bf.WriteUint32(uint32(TimeWeekNext().Unix())) // End
bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthStatusOverride)
bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthIDOverride)
bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthMonsterOverride)

View File

@@ -220,7 +220,7 @@ func addPointNetcafe(s *Session, p int) error {
func handleMsgMhfStartBoostTime(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfStartBoostTime)
bf := byteframe.NewByteFrame()
boostLimit := TimeAdjusted().Add(time.Duration(s.server.erupeConfig.GameplayOptions.BoostTimeDuration) * time.Minute)
boostLimit := TimeAdjusted().Add(time.Duration(s.server.erupeConfig.GameplayOptions.BoostTimeDuration) * time.Second)
if s.server.erupeConfig.GameplayOptions.DisableBoostTime {
bf.WriteUint32(0)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())

View File

@@ -1831,18 +1831,18 @@ func handleMsgMhfLoadGuildCooking(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfRegistGuildCooking(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfRegistGuildCooking)
guild, _ := GetGuildInfoByCharacterId(s, s.charID)
currentTime := TimeAdjusted().Add(time.Duration(s.server.erupeConfig.GameplayOptions.GuildMealDuration-60) * time.Minute)
startTime := TimeAdjusted().Add(time.Duration(s.server.erupeConfig.GameplayOptions.GuildMealDuration-3600) * time.Second)
if pkt.OverwriteID != 0 {
s.server.db.Exec("UPDATE guild_meals SET meal_id = $1, level = $2, created_at = $3 WHERE id = $4", pkt.MealID, pkt.Success, currentTime, pkt.OverwriteID)
s.server.db.Exec("UPDATE guild_meals SET meal_id = $1, level = $2, created_at = $3 WHERE id = $4", pkt.MealID, pkt.Success, startTime, pkt.OverwriteID)
} else {
s.server.db.QueryRow("INSERT INTO guild_meals (guild_id, meal_id, level, created_at) VALUES ($1, $2, $3, $4) RETURNING id", guild.ID, pkt.MealID, pkt.Success, currentTime).Scan(&pkt.OverwriteID)
s.server.db.QueryRow("INSERT INTO guild_meals (guild_id, meal_id, level, created_at) VALUES ($1, $2, $3, $4) RETURNING id", guild.ID, pkt.MealID, pkt.Success, startTime).Scan(&pkt.OverwriteID)
}
bf := byteframe.NewByteFrame()
bf.WriteUint16(1)
bf.WriteUint32(pkt.OverwriteID)
bf.WriteUint32(uint32(pkt.MealID))
bf.WriteUint32(uint32(pkt.Success))
bf.WriteUint32(uint32(currentTime.Unix()))
bf.WriteUint32(uint32(startTime.Unix()))
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}

View File

@@ -55,7 +55,6 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
// Save our new stage ID and pointer to the new stage itself.
s.Lock()
s.stageID = stageID
s.stage = s.server.stages[stageID]
s.Unlock()
@@ -153,13 +152,13 @@ func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysEnterStage)
// Push our current stage ID to the movement stack before entering another one.
if s.stageID == "" {
if s.stage.id == "" {
s.stageMoveStack.Set(pkt.StageID)
} else {
s.stage.Lock()
s.stage.reservedClientSlots[s.charID] = false
s.stage.Unlock()
s.stageMoveStack.Push(s.stageID)
s.stageMoveStack.Push(s.stage.id)
s.stageMoveStack.Lock()
}
@@ -206,9 +205,12 @@ func handleMsgSysLeaveStage(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysLockStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysLockStage)
// TODO(Andoryuuta): What does this packet _actually_ do?
// I think this is supposed to mark a stage as no longer able to accept client reservations
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
if stage, exists := s.server.stages[pkt.StageID]; exists {
stage.Lock()
stage.locked = true
stage.Unlock()
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}
func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {
@@ -218,7 +220,9 @@ func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {
for charID := range s.reservationStage.reservedClientSlots {
session := s.server.FindSessionByCharID(charID)
session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
if session != nil {
session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
}
}
delete(s.server.stages, s.reservationStage.id)
@@ -241,6 +245,10 @@ func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) {
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} else if uint16(len(stage.reservedClientSlots)) < stage.maxPlayers {
if stage.locked {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
if len(stage.password) > 0 {
if stage.password != s.stagePass {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
@@ -383,20 +391,17 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
joinable++
bf.WriteUint16(uint16(len(stage.reservedClientSlots)))
bf.WriteUint16(0) // Unk
if len(stage.clients) > 0 {
bf.WriteUint16(1)
} else {
bf.WriteUint16(0)
}
bf.WriteUint16(uint16(len(stage.clients)))
bf.WriteUint16(uint16(len(stage.clients)))
bf.WriteUint16(stage.maxPlayers)
if len(stage.password) > 0 {
// This byte has also been seen as 1
// The quest is also recognised as locked when this is 2
bf.WriteUint8(2)
} else {
bf.WriteUint8(0)
var flags uint8
if stage.locked {
flags |= 1
}
if len(stage.password) > 0 {
flags |= 2
}
bf.WriteUint8(flags)
ps.Uint8(bf, sid, false)
stage.RUnlock()
}

View File

@@ -36,7 +36,6 @@ type Session struct {
objectIndex uint16
userEnteredStage bool // If the user has entered a stage before
stageID string
stage *Stage
reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet.
stagePass string // Temporary storage

View File

@@ -47,6 +47,7 @@ type Stage struct {
host *Session
maxPlayers uint16
password string
locked bool
}
// NewStage creates a new stage with intialized values.

View File

@@ -16,8 +16,11 @@ func TimeMidnight() time.Time {
func TimeWeekStart() time.Time {
midnight := TimeMidnight()
offset := (int(midnight.Weekday()) - 1) * -24
return midnight.Add(time.Hour * time.Duration(offset))
offset := int(midnight.Weekday()) - int(time.Monday)
if offset < 0 {
offset += 7
}
return midnight.Add(-time.Duration(offset) * 24 * time.Hour)
}
func TimeWeekNext() time.Time {

View File

@@ -69,7 +69,11 @@ func encodeServerInfo(config *_config.Config, s *Server, local bool) []byte {
for channelIdx, ci := range si.Channels {
sid = (4096 + serverIdx*256) + (16 + channelIdx)
bf.WriteUint16(ci.Port)
if _config.ErupeConfig.DevMode && _config.ErupeConfig.ProxyPort != 0 {
bf.WriteUint16(_config.ErupeConfig.ProxyPort)
} else {
bf.WriteUint16(ci.Port)
}
bf.WriteUint16(16 + uint16(channelIdx))
bf.WriteUint16(ci.MaxPlayers)
var currentPlayers uint16

View File

@@ -9,6 +9,7 @@ import (
"fmt"
"go.uber.org/zap"
"strings"
"time"
)
func (s *Session) makeSignResponse(uid uint32) []byte {
@@ -154,35 +155,30 @@ func (s *Session) makeSignResponse(uid uint32) []byte {
bf.WriteUint32(uint32(s.server.getReturnExpiry(uid).Unix()))
bf.WriteUint32(0)
mezfes := s.server.erupeConfig.DevModeOptions.MezFesEvent
alt := s.server.erupeConfig.DevModeOptions.MezFesAlt
if mezfes {
// We can just use the start timestamp as the event ID
bf.WriteUint32(uint32(channelserver.TimeWeekStart().Unix()))
// Start time
bf.WriteUint32(uint32(channelserver.TimeWeekStart().Unix()))
// End time
bf.WriteUint32(uint32(channelserver.TimeWeekNext().Unix()))
bf.WriteUint8(2) // Unk
bf.WriteUint32(s.server.erupeConfig.GameplayOptions.MezfesSoloTickets)
bf.WriteUint32(s.server.erupeConfig.GameplayOptions.MezfesGroupTickets)
bf.WriteUint8(8) // Stalls open
bf.WriteUint8(10) // Stall Map
bf.WriteUint8(3) // Pachinko
bf.WriteUint8(6) // Nyanrendo
bf.WriteUint8(9) // Point stall
if alt {
bf.WriteUint8(2) // Tokotoko Partnya
} else {
bf.WriteUint8(4) // Volpakkun Together
}
bf.WriteUint8(8) // Dokkan Battle Cats
bf.WriteUint8(5) // Goocoo Scoop
bf.WriteUint8(7) // Honey Panic
} else {
bf.WriteUint32(0)
bf.WriteUint32(0)
bf.WriteUint32(0)
tickets := []uint32{
s.server.erupeConfig.GameplayOptions.MezfesSoloTickets,
s.server.erupeConfig.GameplayOptions.MezfesGroupTickets,
}
stalls := []uint8{
10, 3, 6, 9, 4, 8, 5, 7,
}
if s.server.erupeConfig.GameplayOptions.MezFesSwitchMinigame {
stalls[4] = 2
}
// We can just use the start timestamp as the event ID
bf.WriteUint32(uint32(channelserver.TimeWeekStart().Unix()))
// Start time
bf.WriteUint32(uint32(channelserver.TimeWeekNext().Add(-time.Duration(s.server.erupeConfig.GameplayOptions.MezFesDuration) * time.Second).Unix()))
// End time
bf.WriteUint32(uint32(channelserver.TimeWeekNext().Unix()))
bf.WriteUint8(uint8(len(tickets)))
for i := range tickets {
bf.WriteUint32(tickets[i])
}
bf.WriteUint8(uint8(len(stalls)))
for i := range stalls {
bf.WriteUint8(stalls[i])
}
return bf.Data()
}

View File

@@ -8,6 +8,7 @@ import (
"erupe-ce/server/channelserver"
"net/http"
"strings"
"time"
"github.com/lib/pq"
"go.uber.org/zap"
@@ -82,19 +83,17 @@ func (s *Server) newAuthData(userID uint32, userRights uint32, userToken string,
resp.Characters[i].HR = 7
}
}
if s.erupeConfig.DevModeOptions.MezFesEvent {
stalls := []uint32{10, 3, 6, 9, 4, 8, 5, 7}
if s.erupeConfig.DevModeOptions.MezFesAlt {
stalls[4] = 2
}
resp.MezFes = &MezFes{
ID: uint32(channelserver.TimeWeekStart().Unix()),
Start: uint32(channelserver.TimeWeekStart().Unix()),
End: uint32(channelserver.TimeWeekNext().Unix()),
SoloTickets: s.erupeConfig.GameplayOptions.MezfesSoloTickets,
GroupTickets: s.erupeConfig.GameplayOptions.MezfesGroupTickets,
Stalls: stalls,
}
stalls := []uint32{10, 3, 6, 9, 4, 8, 5, 7}
if s.erupeConfig.GameplayOptions.MezFesSwitchMinigame {
stalls[4] = 2
}
resp.MezFes = &MezFes{
ID: uint32(channelserver.TimeWeekStart().Unix()),
Start: uint32(channelserver.TimeWeekStart().Add(-time.Duration(s.erupeConfig.GameplayOptions.MezFesDuration) * time.Second).Unix()),
End: uint32(channelserver.TimeWeekNext().Unix()),
SoloTickets: s.erupeConfig.GameplayOptions.MezfesSoloTickets,
GroupTickets: s.erupeConfig.GameplayOptions.MezfesGroupTickets,
Stalls: stalls,
}
if !s.erupeConfig.HideLoginNotice {
resp.Notices = append(resp.Notices, strings.Join(s.erupeConfig.LoginNotices[:], "<PAGE>"))