refactor(config): eliminate ErupeConfig global variable

Replace the mutable global `_config.ErupeConfig` with dependency
injection across 79 files. Config is now threaded through existing
paths: `ClientContext.RealClientMode` for packet encoding, `s.server.
erupeConfig` for channel handlers, and explicit parameters for utility
functions. This removes hidden coupling, enables test parallelism
without global save/restore, and prevents low-level packages from
reaching up to the config layer.

Key changes:
- Enrich ClientContext with RealClientMode for packet files
- Add mode parameter to CryptConn, mhfitem, mhfcourse functions
- Convert handlers_commands init() to lazy sync.Once initialization
- Delete global var, init(), and helper functions from config.go
- Update all tests to pass config explicitly
This commit is contained in:
Houmgaor
2026-02-20 17:07:42 +01:00
parent 8c7e95ce18
commit 5f3c843082
79 changed files with 509 additions and 723 deletions

View File

@@ -118,12 +118,12 @@ func (gi *GuildIcon) Value() (valuer driver.Value, err error) {
return json.Marshal(gi)
}
func (g *Guild) Rank() uint16 {
func (g *Guild) Rank(mode _config.Mode) uint16 {
rpMap := []uint32{
24, 48, 96, 144, 192, 240, 288, 360, 432,
504, 600, 696, 792, 888, 984, 1080, 1200,
}
if _config.ErupeConfig.RealClientMode <= _config.Z2 {
if mode <= _config.Z2 {
rpMap = []uint32{
3500, 6000, 8500, 11000, 13500, 16000, 20000, 24000, 28000,
33000, 38000, 43000, 48000, 55000, 70000, 90000, 120000,
@@ -131,21 +131,21 @@ func (g *Guild) Rank() uint16 {
}
for i, u := range rpMap {
if g.RankRP < u {
if _config.ErupeConfig.RealClientMode <= _config.S6 && i >= 12 {
if mode <= _config.S6 && i >= 12 {
return 12
} else if _config.ErupeConfig.RealClientMode <= _config.F5 && i >= 13 {
} else if mode <= _config.F5 && i >= 13 {
return 13
} else if _config.ErupeConfig.RealClientMode <= _config.G32 && i >= 14 {
} else if mode <= _config.G32 && i >= 14 {
return 14
}
return uint16(i)
}
}
if _config.ErupeConfig.RealClientMode <= _config.S6 {
if mode <= _config.S6 {
return 12
} else if _config.ErupeConfig.RealClientMode <= _config.F5 {
} else if mode <= _config.F5 {
return 13
} else if _config.ErupeConfig.RealClientMode <= _config.G32 {
} else if mode <= _config.G32 {
return 14
}
return 17

View File

@@ -102,7 +102,7 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
cafeTime = uint32(TimeAdjusted().Unix()) - uint32(s.sessionStart) + cafeTime
}
bf.WriteUint32(cafeTime)
if _config.ErupeConfig.RealClientMode >= _config.ZZ {
if s.server.erupeConfig.RealClientMode >= _config.ZZ {
bf.WriteUint16(0)
ps.Uint16(bf, fmt.Sprintf(s.server.i18n.cafe.reset, int(cafeReset.Month()), cafeReset.Day()), true)
}

View File

@@ -71,7 +71,7 @@ func handleMsgMhfEnumerateCampaign(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt16(event.MaxHR)
bf.WriteInt16(event.MinSR)
bf.WriteInt16(event.MaxSR)
if _config.ErupeConfig.RealClientMode >= _config.G3 {
if s.server.erupeConfig.RealClientMode >= _config.G3 {
bf.WriteInt16(event.MinGR)
bf.WriteInt16(event.MaxGR)
}

View File

@@ -24,7 +24,8 @@ func GetCharacterSaveData(s *Session, charID uint32) (*CharacterSaveData, error)
}
saveData := &CharacterSaveData{
Pointers: getPointers(),
Mode: s.server.erupeConfig.RealClientMode,
Pointers: getPointers(s.server.erupeConfig.RealClientMode),
}
err = result.Scan(&saveData.CharID, &saveData.compSave, &saveData.IsNewCharacter, &saveData.Name)
if err != nil {
@@ -63,7 +64,7 @@ func (save *CharacterSaveData) Save(s *Session) {
save.updateSaveDataWithStruct()
if _config.ErupeConfig.RealClientMode >= _config.G1 {
if s.server.erupeConfig.RealClientMode >= _config.G1 {
err := save.Compress()
if err != nil {
s.logger.Error("Failed to compress savedata", zap.Error(err))

View File

@@ -52,12 +52,7 @@ func TestGetPointers(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Save and restore original config
originalMode := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = originalMode }()
_config.ErupeConfig.RealClientMode = tt.clientMode
pointers := getPointers()
pointers := getPointers(tt.clientMode)
if pointers[pGender] != tt.wantGender {
t.Errorf("pGender = %d, want %d", pointers[pGender], tt.wantGender)
@@ -216,10 +211,6 @@ func TestCharacterSaveData_RoundTrip(t *testing.T) {
// TestCharacterSaveData_updateStructWithSaveData tests parsing save data
func TestCharacterSaveData_updateStructWithSaveData(t *testing.T) {
originalMode := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = originalMode }()
_config.ErupeConfig.RealClientMode = _config.Z2
tests := []struct {
name string
isNewCharacter bool
@@ -267,7 +258,8 @@ func TestCharacterSaveData_updateStructWithSaveData(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
save := &CharacterSaveData{
Pointers: getPointers(),
Mode: _config.Z2,
Pointers: getPointers(_config.Z2),
decompSave: tt.setupSaveData(),
IsNewCharacter: tt.isNewCharacter,
}
@@ -287,10 +279,6 @@ func TestCharacterSaveData_updateStructWithSaveData(t *testing.T) {
// TestCharacterSaveData_updateSaveDataWithStruct tests writing struct to save data
func TestCharacterSaveData_updateSaveDataWithStruct(t *testing.T) {
originalMode := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = originalMode }()
_config.ErupeConfig.RealClientMode = _config.G10
tests := []struct {
name string
rp uint16
@@ -320,7 +308,8 @@ func TestCharacterSaveData_updateSaveDataWithStruct(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
save := &CharacterSaveData{
Pointers: getPointers(),
Mode: _config.G10,
Pointers: getPointers(_config.G10),
decompSave: make([]byte, 150000),
RP: tt.rp,
KQF: tt.kqf,
@@ -388,11 +377,6 @@ func TestGetCharacterSaveData_Integration(t *testing.T) {
db := SetupTestDB(t)
defer TeardownTestDB(t, db)
// Save original config mode
originalMode := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = originalMode }()
_config.ErupeConfig.RealClientMode = _config.Z2
tests := []struct {
name string
charName string
@@ -430,6 +414,7 @@ func TestGetCharacterSaveData_Integration(t *testing.T) {
s := createTestSession(mock)
s.charID = charID
s.server.db = db
s.server.erupeConfig.RealClientMode = _config.Z2
// Get character save data
saveData, err := GetCharacterSaveData(s, charID)
@@ -464,11 +449,6 @@ func TestCharacterSaveData_Save_Integration(t *testing.T) {
db := SetupTestDB(t)
defer TeardownTestDB(t, db)
// Save original config mode
originalMode := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = originalMode }()
_config.ErupeConfig.RealClientMode = _config.Z2
// Create test user and character
userID := CreateTestUser(t, db, "savetest")
charID := CreateTestCharacter(t, db, userID, "SaveChar")
@@ -478,6 +458,7 @@ func TestCharacterSaveData_Save_Integration(t *testing.T) {
s := createTestSession(mock)
s.charID = charID
s.server.db = db
s.server.erupeConfig.RealClientMode = _config.Z2
// Load character save data
saveData, err := GetCharacterSaveData(s, charID)

View File

@@ -15,29 +15,29 @@ import (
"slices"
"strconv"
"strings"
"sync"
"time"
"go.uber.org/zap"
)
var commands map[string]_config.Command
var (
commands map[string]_config.Command
commandsOnce sync.Once
)
func init() {
commands = make(map[string]_config.Command)
zapConfig := zap.NewDevelopmentConfig()
zapConfig.DisableCaller = true
zapLogger, _ := zapConfig.Build()
defer func() { _ = zapLogger.Sync() }()
logger := zapLogger.Named("commands")
cmds := _config.ErupeConfig.Commands
for _, cmd := range cmds {
commands[cmd.Name] = cmd
if cmd.Enabled {
logger.Info(fmt.Sprintf("Command %s: Enabled, prefix: %s", cmd.Name, cmd.Prefix))
} else {
logger.Info(fmt.Sprintf("Command %s: Disabled", cmd.Name))
func initCommands(cmds []_config.Command, logger *zap.Logger) {
commandsOnce.Do(func() {
commands = make(map[string]_config.Command)
for _, cmd := range cmds {
commands[cmd.Name] = cmd
if cmd.Enabled {
logger.Info(fmt.Sprintf("Command %s: Enabled, prefix: %s", cmd.Name, cmd.Prefix))
} else {
logger.Info(fmt.Sprintf("Command %s: Disabled", cmd.Name))
}
}
}
})
}
func sendDisabledCommandMessage(s *Session, cmd _config.Command) {

View File

@@ -12,46 +12,30 @@ import (
// =============================================================================
func TestEquipSkinHistSize_Default(t *testing.T) {
orig := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = orig }()
_config.ErupeConfig.RealClientMode = _config.ZZ
got := equipSkinHistSize()
got := equipSkinHistSize(_config.ZZ)
if got != 3200 {
t.Errorf("equipSkinHistSize() with ZZ = %d, want 3200", got)
t.Errorf("equipSkinHistSize(ZZ) = %d, want 3200", got)
}
}
func TestEquipSkinHistSize_Z2(t *testing.T) {
orig := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = orig }()
_config.ErupeConfig.RealClientMode = _config.Z2
got := equipSkinHistSize()
got := equipSkinHistSize(_config.Z2)
if got != 2560 {
t.Errorf("equipSkinHistSize() with Z2 = %d, want 2560", got)
t.Errorf("equipSkinHistSize(Z2) = %d, want 2560", got)
}
}
func TestEquipSkinHistSize_Z1(t *testing.T) {
orig := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = orig }()
_config.ErupeConfig.RealClientMode = _config.Z1
got := equipSkinHistSize()
got := equipSkinHistSize(_config.Z1)
if got != 1280 {
t.Errorf("equipSkinHistSize() with Z1 = %d, want 1280", got)
t.Errorf("equipSkinHistSize(Z1) = %d, want 1280", got)
}
}
func TestEquipSkinHistSize_OlderMode(t *testing.T) {
orig := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = orig }()
_config.ErupeConfig.RealClientMode = _config.G1
got := equipSkinHistSize()
got := equipSkinHistSize(_config.G1)
if got != 1280 {
t.Errorf("equipSkinHistSize() with G1 = %d, want 1280", got)
t.Errorf("equipSkinHistSize(G1) = %d, want 1280", got)
}
}

View File

@@ -70,7 +70,7 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) {
characterSaveData.updateSaveDataWithStruct()
}
if characterSaveData.Name == s.Name || _config.ErupeConfig.RealClientMode <= _config.S10 {
if characterSaveData.Name == s.Name || s.server.erupeConfig.RealClientMode <= _config.S10 {
characterSaveData.Save(s)
s.logger.Info("Wrote recompressed savedata back to DB.")
} else {

View File

@@ -65,7 +65,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(dist.Rights)
bf.WriteUint16(dist.TimesAcceptable)
bf.WriteUint16(dist.TimesAccepted)
if _config.ErupeConfig.RealClientMode >= _config.G9 {
if s.server.erupeConfig.RealClientMode >= _config.G9 {
bf.WriteUint16(0) // Unk
}
bf.WriteInt16(dist.MinHR)
@@ -74,29 +74,29 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt16(dist.MaxSR)
bf.WriteInt16(dist.MinGR)
bf.WriteInt16(dist.MaxGR)
if _config.ErupeConfig.RealClientMode >= _config.G7 {
if s.server.erupeConfig.RealClientMode >= _config.G7 {
bf.WriteUint8(0) // Unk
}
if _config.ErupeConfig.RealClientMode >= _config.G6 {
if s.server.erupeConfig.RealClientMode >= _config.G6 {
bf.WriteUint16(0) // Unk
}
if _config.ErupeConfig.RealClientMode >= _config.G8 {
if s.server.erupeConfig.RealClientMode >= _config.G8 {
if dist.Selection {
bf.WriteUint8(2) // Selection
} else {
bf.WriteUint8(0)
}
}
if _config.ErupeConfig.RealClientMode >= _config.G7 {
if s.server.erupeConfig.RealClientMode >= _config.G7 {
bf.WriteUint16(0) // Unk
bf.WriteUint16(0) // Unk
}
if _config.ErupeConfig.RealClientMode >= _config.G10 {
if s.server.erupeConfig.RealClientMode >= _config.G10 {
bf.WriteUint8(0) // Unk
}
ps.Uint8(bf, dist.EventName, true)
k := 6
if _config.ErupeConfig.RealClientMode >= _config.G8 {
if s.server.erupeConfig.RealClientMode >= _config.G8 {
k = 13
}
for i := 0; i < 6; i++ {
@@ -105,7 +105,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(0)
}
}
if _config.ErupeConfig.RealClientMode >= _config.Z2 {
if s.server.erupeConfig.RealClientMode >= _config.Z2 {
i := uint8(0)
bf.WriteUint8(i)
if i <= 10 {
@@ -154,7 +154,7 @@ func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint8(item.ItemType)
bf.WriteUint32(item.ItemID)
bf.WriteUint32(item.Quantity)
if _config.ErupeConfig.RealClientMode >= _config.G8 {
if s.server.erupeConfig.RealClientMode >= _config.G8 {
bf.WriteUint32(item.ID)
}
}

View File

@@ -69,7 +69,7 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
err := s.server.db.QueryRowx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1`, t).StructScan(&temp)
if err != nil || temp.StartTime.IsZero() {
weapons := token.RNG.Intn(s.server.erupeConfig.GameplayOptions.MaxFeatureWeapons-s.server.erupeConfig.GameplayOptions.MinFeatureWeapons+1) + s.server.erupeConfig.GameplayOptions.MinFeatureWeapons
temp = generateFeatureWeapons(weapons)
temp = generateFeatureWeapons(weapons, s.server.erupeConfig.RealClientMode)
temp.StartTime = t
if _, err := s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, temp.StartTime, temp.ActiveFeatures); err != nil {
s.logger.Error("Failed to insert feature weapon", zap.Error(err))
@@ -89,15 +89,15 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
func generateFeatureWeapons(count int) activeFeature {
func generateFeatureWeapons(count int, mode _config.Mode) activeFeature {
_max := 14
if _config.ErupeConfig.RealClientMode < _config.ZZ {
if mode < _config.ZZ {
_max = 13
}
if _config.ErupeConfig.RealClientMode < _config.G10 {
if mode < _config.G10 {
_max = 12
}
if _config.ErupeConfig.RealClientMode < _config.GG {
if mode < _config.GG {
_max = 11
}
if count > _max {

View File

@@ -4,6 +4,7 @@ import (
"math/bits"
"testing"
_config "erupe-ce/config"
"erupe-ce/network/mhfpacket"
)
@@ -121,7 +122,7 @@ func TestGenerateFeatureWeapons(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := generateFeatureWeapons(tt.count)
result := generateFeatureWeapons(tt.count, _config.ZZ)
// Result should be non-zero for positive counts
if tt.count > 0 && result.ActiveFeatures == 0 {
@@ -142,7 +143,7 @@ func TestGenerateFeatureWeapons_Randomness(t *testing.T) {
iterations := 100
for i := 0; i < iterations; i++ {
result := generateFeatureWeapons(5)
result := generateFeatureWeapons(5, _config.ZZ)
results[result.ActiveFeatures]++
}
@@ -153,7 +154,7 @@ func TestGenerateFeatureWeapons_Randomness(t *testing.T) {
}
func TestGenerateFeatureWeapons_ZeroCount(t *testing.T) {
result := generateFeatureWeapons(0)
result := generateFeatureWeapons(0, _config.ZZ)
// Should return 0 for no weapons
if result.ActiveFeatures != 0 {
@@ -180,7 +181,7 @@ func TestGenerateFeatureWeapons_BitCount(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := generateFeatureWeapons(tt.count)
result := generateFeatureWeapons(tt.count, _config.ZZ)
setBits := bits.OnesCount32(result.ActiveFeatures)
if setBits != tt.wantBits {
t.Errorf("Set bits = %d, want %d (ActiveFeatures=0b%032b)",
@@ -194,7 +195,7 @@ func TestGenerateFeatureWeapons_BitCount(t *testing.T) {
// bits 0-13 (no bits above bit 13 should be set).
func TestGenerateFeatureWeapons_BitsInRange(t *testing.T) {
for i := 0; i < 50; i++ {
result := generateFeatureWeapons(7)
result := generateFeatureWeapons(7, _config.ZZ)
// Bits 14+ should never be set
if result.ActiveFeatures&^uint32(0x3FFF) != 0 {
t.Errorf("Bits above 13 are set: 0x%08X", result.ActiveFeatures)
@@ -205,7 +206,7 @@ func TestGenerateFeatureWeapons_BitsInRange(t *testing.T) {
// TestGenerateFeatureWeapons_MaxYieldsAllBits verifies that requesting 14
// weapons sets exactly bits 0-13 (the value 16383 = 0x3FFF).
func TestGenerateFeatureWeapons_MaxYieldsAllBits(t *testing.T) {
result := generateFeatureWeapons(14)
result := generateFeatureWeapons(14, _config.ZZ)
if result.ActiveFeatures != 0x3FFF {
t.Errorf("ActiveFeatures = 0x%04X, want 0x3FFF (all 14 bits set)", result.ActiveFeatures)
}
@@ -214,7 +215,7 @@ func TestGenerateFeatureWeapons_MaxYieldsAllBits(t *testing.T) {
// TestGenerateFeatureWeapons_StartTimeZero verifies that the returned
// activeFeature has a zero StartTime (not set by generateFeatureWeapons).
func TestGenerateFeatureWeapons_StartTimeZero(t *testing.T) {
result := generateFeatureWeapons(5)
result := generateFeatureWeapons(5, _config.ZZ)
if !result.StartTime.IsZero() {
t.Errorf("StartTime should be zero, got %v", result.StartTime)
}

View File

@@ -276,7 +276,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(trial.Locale)
bf.WriteUint16(trial.Reward)
bf.WriteInt16(FestivalColorCodes[trial.Monopoly])
if _config.ErupeConfig.RealClientMode >= _config.F4 { // Not in S6.0
if s.server.erupeConfig.RealClientMode >= _config.F4 { // Not in S6.0
bf.WriteUint16(trial.Unk)
}
}
@@ -320,13 +320,13 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(reward.Quantity)
bf.WriteUint16(reward.ItemID)
// Confirmed present in G3 via Wii U disassembly of import_festa_info
if _config.ErupeConfig.RealClientMode >= _config.G3 {
if s.server.erupeConfig.RealClientMode >= _config.G3 {
bf.WriteUint16(reward.MinHR)
bf.WriteUint16(reward.MinSR)
bf.WriteUint8(reward.MinGR)
}
}
if _config.ErupeConfig.RealClientMode <= _config.G61 {
if s.server.erupeConfig.RealClientMode <= _config.G61 {
if s.server.erupeConfig.GameplayOptions.MaximumFP > 0xFFFF {
s.server.erupeConfig.GameplayOptions.MaximumFP = 0xFFFF
}
@@ -393,7 +393,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(100) // Normal rate
bf.WriteUint16(50) // 50% penalty
if _config.ErupeConfig.RealClientMode >= _config.G52 {
if s.server.erupeConfig.RealClientMode >= _config.G52 {
ps.Uint16(bf, "", false)
}
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
@@ -480,7 +480,7 @@ func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(0) // Unk
for _, member := range validMembers {
bf.WriteUint32(member.CharID)
if _config.ErupeConfig.RealClientMode <= _config.Z1 {
if s.server.erupeConfig.RealClientMode <= _config.Z1 {
bf.WriteUint16(uint16(member.Souls))
bf.WriteUint16(0)
} else {

View File

@@ -223,14 +223,14 @@ func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {
}
bf.WriteUint32(alliance.ParentGuildID)
bf.WriteUint32(alliance.ParentGuild.LeaderCharID)
bf.WriteUint16(alliance.ParentGuild.Rank())
bf.WriteUint16(alliance.ParentGuild.Rank(s.server.erupeConfig.RealClientMode))
bf.WriteUint16(alliance.ParentGuild.MemberCount)
ps.Uint16(bf, alliance.ParentGuild.Name, true)
ps.Uint16(bf, alliance.ParentGuild.LeaderName, true)
if alliance.SubGuild1ID > 0 {
bf.WriteUint32(alliance.SubGuild1ID)
bf.WriteUint32(alliance.SubGuild1.LeaderCharID)
bf.WriteUint16(alliance.SubGuild1.Rank())
bf.WriteUint16(alliance.SubGuild1.Rank(s.server.erupeConfig.RealClientMode))
bf.WriteUint16(alliance.SubGuild1.MemberCount)
ps.Uint16(bf, alliance.SubGuild1.Name, true)
ps.Uint16(bf, alliance.SubGuild1.LeaderName, true)
@@ -238,7 +238,7 @@ func handleMsgMhfInfoJoint(s *Session, p mhfpacket.MHFPacket) {
if alliance.SubGuild2ID > 0 {
bf.WriteUint32(alliance.SubGuild2ID)
bf.WriteUint32(alliance.SubGuild2.LeaderCharID)
bf.WriteUint16(alliance.SubGuild2.Rank())
bf.WriteUint16(alliance.SubGuild2.Rank(s.server.erupeConfig.RealClientMode))
bf.WriteUint16(alliance.SubGuild2.MemberCount)
ps.Uint16(bf, alliance.SubGuild2.Name, true)
ps.Uint16(bf, alliance.SubGuild2.LeaderName, true)

View File

@@ -51,7 +51,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(guild.ID)
bf.WriteUint32(guild.LeaderCharID)
bf.WriteUint16(guild.Rank())
bf.WriteUint16(guild.Rank(s.server.erupeConfig.RealClientMode))
bf.WriteUint16(guild.MemberCount)
bf.WriteUint8(guild.MainMotto)
@@ -114,7 +114,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
limit := s.server.erupeConfig.GameplayOptions.ClanMemberLimits[0][1]
for _, j := range s.server.erupeConfig.GameplayOptions.ClanMemberLimits {
if guild.Rank() >= uint16(j[0]) {
if guild.Rank(s.server.erupeConfig.RealClientMode) >= uint16(j[0]) {
limit = j[1]
}
}
@@ -155,7 +155,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
} else {
bf.WriteUint16(0)
}
bf.WriteUint16(alliance.ParentGuild.Rank())
bf.WriteUint16(alliance.ParentGuild.Rank(s.server.erupeConfig.RealClientMode))
bf.WriteUint16(alliance.ParentGuild.MemberCount)
ps.Uint16(bf, alliance.ParentGuild.Name, true)
ps.Uint16(bf, alliance.ParentGuild.LeaderName, true)
@@ -167,7 +167,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
} else {
bf.WriteUint16(0)
}
bf.WriteUint16(alliance.SubGuild1.Rank())
bf.WriteUint16(alliance.SubGuild1.Rank(s.server.erupeConfig.RealClientMode))
bf.WriteUint16(alliance.SubGuild1.MemberCount)
ps.Uint16(bf, alliance.SubGuild1.Name, true)
ps.Uint16(bf, alliance.SubGuild1.LeaderName, true)
@@ -180,7 +180,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
} else {
bf.WriteUint16(0)
}
bf.WriteUint16(alliance.SubGuild2.Rank())
bf.WriteUint16(alliance.SubGuild2.Rank(s.server.erupeConfig.RealClientMode))
bf.WriteUint16(alliance.SubGuild2.MemberCount)
ps.Uint16(bf, alliance.SubGuild2.Name, true)
ps.Uint16(bf, alliance.SubGuild2.LeaderName, true)
@@ -460,7 +460,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(guild.LeaderCharID)
bf.WriteUint16(guild.MemberCount)
bf.WriteUint16(0x0000) // Unk
bf.WriteUint16(guild.Rank())
bf.WriteUint16(guild.Rank(s.server.erupeConfig.RealClientMode))
bf.WriteUint32(uint32(guild.CreatedAt.Unix()))
ps.Uint8(bf, guild.Name, true)
ps.Uint8(bf, guild.LeaderName, true)

View File

@@ -117,16 +117,11 @@ func TestGuildRankCalculation(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
originalConfig := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = originalConfig }()
_config.ErupeConfig.RealClientMode = tt.config
guild := &Guild{
RankRP: tt.rankRP,
}
rank := guild.Rank()
rank := guild.Rank(tt.config)
if rank != tt.wantRank {
t.Errorf("guild rank calculation: got %d, want %d for RP %d", rank, tt.wantRank, tt.rankRP)
}

View File

@@ -65,7 +65,7 @@ func doAckSimpleFail(s *Session, ackHandle uint32, data []byte) {
func updateRights(s *Session) {
rightsInt := uint32(2)
_ = s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt)
s.courses, rightsInt = mhfcourse.GetCourseStruct(rightsInt)
s.courses, rightsInt = mhfcourse.GetCourseStruct(rightsInt, s.server.erupeConfig.DefaultCourses)
update := &mhfpacket.MsgSysUpdateRight{
ClientRespAckHandle: 0,
Bitfield: rightsInt,

View File

@@ -133,7 +133,7 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint8(0)
}
bf.WriteUint16(house.HR)
if _config.ErupeConfig.RealClientMode >= _config.G10 {
if s.server.erupeConfig.RealClientMode >= _config.G10 {
bf.WriteUint16(house.GR)
}
ps.Uint8(bf, house.Name, true)
@@ -516,7 +516,7 @@ func warehouseGetEquipment(s *Session, index uint8) []mhfitem.MHFEquipment {
numStacks := box.ReadUint16()
box.ReadUint16() // Unused
for i := 0; i < int(numStacks); i++ {
equipment = append(equipment, mhfitem.ReadWarehouseEquipment(box))
equipment = append(equipment, mhfitem.ReadWarehouseEquipment(box, s.server.erupeConfig.RealClientMode))
}
}
return equipment
@@ -531,7 +531,7 @@ func handleMsgMhfEnumerateWarehouse(s *Session, p mhfpacket.MHFPacket) {
bf.WriteBytes(mhfitem.SerializeWarehouseItems(items))
case 1:
equipment := warehouseGetEquipment(s, pkt.BoxIndex)
bf.WriteBytes(mhfitem.SerializeWarehouseEquipment(equipment))
bf.WriteBytes(mhfitem.SerializeWarehouseEquipment(equipment, s.server.erupeConfig.RealClientMode))
}
if bf.Index() > 0 {
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
@@ -602,7 +602,7 @@ func handleMsgMhfUpdateWarehouse(s *Session, p mhfpacket.MHFPacket) {
}
}
serialized := mhfitem.SerializeWarehouseEquipment(fEquip)
serialized := mhfitem.SerializeWarehouseEquipment(fEquip, s.server.erupeConfig.RealClientMode)
dataSize = len(serialized)
s.logger.Debug("Warehouse save request",

View File

@@ -1,6 +1,7 @@
package channelserver
import (
_config "erupe-ce/config"
"erupe-ce/common/mhfitem"
"erupe-ce/common/token"
"testing"
@@ -92,7 +93,7 @@ func TestWarehouseEquipmentSerialization(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Serialize
serialized := mhfitem.SerializeWarehouseEquipment(tt.equipment)
serialized := mhfitem.SerializeWarehouseEquipment(tt.equipment, _config.ZZ)
// Basic validation
if serialized == nil {

View File

@@ -307,7 +307,7 @@ func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {
{300, 5392, 1, 5392, 3},
{999, 5392, 1, 5392, 4},
}
if _config.ErupeConfig.RealClientMode <= _config.Z1 {
if s.server.erupeConfig.RealClientMode <= _config.Z1 {
for _, reward := range rewards {
if pkt.HR >= reward.HR {
pkt.Item1 = reward.Item1
@@ -320,7 +320,7 @@ func handleMsgMhfStampcardStamp(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame()
bf.WriteUint16(pkt.HR)
if _config.ErupeConfig.RealClientMode >= _config.G1 {
if s.server.erupeConfig.RealClientMode >= _config.G1 {
bf.WriteUint16(pkt.GR)
}
var stamps, rewardTier, rewardUnk uint16

View File

@@ -79,7 +79,7 @@ func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) {
bf.WriteInt32(s.server.erupeConfig.EarthStatus)
bf.WriteInt32(s.server.erupeConfig.EarthID)
for i, m := range s.server.erupeConfig.EarthMonsters {
if _config.ErupeConfig.RealClientMode <= _config.G9 {
if s.server.erupeConfig.RealClientMode <= _config.G9 {
if i == 3 {
break
}
@@ -156,12 +156,12 @@ func handleMsgMhfGetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfSetDailyMissionPersonal(s *Session, p mhfpacket.MHFPacket) {}
func equipSkinHistSize() int {
func equipSkinHistSize(mode _config.Mode) int {
size := 3200
if _config.ErupeConfig.RealClientMode <= _config.Z2 {
if mode <= _config.Z2 {
size = 2560
}
if _config.ErupeConfig.RealClientMode <= _config.Z1 {
if mode <= _config.Z1 {
size = 1280
}
return size
@@ -169,7 +169,7 @@ func equipSkinHistSize() int {
func handleMsgMhfGetEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetEquipSkinHist)
size := equipSkinHistSize()
size := equipSkinHistSize(s.server.erupeConfig.RealClientMode)
var data []byte
err := s.server.db.QueryRow("SELECT COALESCE(skin_hist::bytea, $2::bytea) FROM characters WHERE id = $1", s.charID, make([]byte, size)).Scan(&data)
if err != nil {
@@ -181,7 +181,7 @@ func handleMsgMhfGetEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateEquipSkinHist)
size := equipSkinHistSize()
size := equipSkinHistSize(s.server.erupeConfig.RealClientMode)
var data []byte
err := s.server.db.QueryRow("SELECT COALESCE(skin_hist, $2) FROM characters WHERE id = $1", s.charID, make([]byte, size)).Scan(&data)
if err != nil {

View File

@@ -49,7 +49,7 @@ func equal(a, b []byte) bool {
}
// BackportQuest converts a quest binary to an older format.
func BackportQuest(data []byte) []byte {
func BackportQuest(data []byte, mode _config.Mode) []byte {
wp := binary.LittleEndian.Uint32(data[0:4]) + 96
rp := wp + 4
for i := uint32(0); i < 6; i++ {
@@ -61,16 +61,16 @@ func BackportQuest(data []byte) []byte {
}
fillLength := uint32(108)
if _config.ErupeConfig.RealClientMode <= _config.S6 {
if mode <= _config.S6 {
fillLength = 44
} else if _config.ErupeConfig.RealClientMode <= _config.F5 {
} else if mode <= _config.F5 {
fillLength = 52
} else if _config.ErupeConfig.RealClientMode <= _config.G101 {
} else if mode <= _config.G101 {
fillLength = 76
}
copy(data[wp:wp+fillLength], data[rp:rp+fillLength])
if _config.ErupeConfig.RealClientMode <= _config.G91 {
if mode <= _config.G91 {
patterns := [][]byte{
{0x0A, 0x00, 0x01, 0x33, 0xD7, 0x00}, // 10% Armor Sphere -> Stone
{0x06, 0x00, 0x02, 0x33, 0xD8, 0x00}, // 6% Armor Sphere+ -> Iron Ore
@@ -87,7 +87,7 @@ func BackportQuest(data []byte) []byte {
}
}
if _config.ErupeConfig.RealClientMode <= _config.S6 {
if mode <= _config.S6 {
binary.LittleEndian.PutUint32(data[16:20], binary.LittleEndian.Uint32(data[8:12]))
}
return data
@@ -133,8 +133,8 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) {
doAckBufFail(s, pkt.AckHandle, nil)
return
}
if _config.ErupeConfig.RealClientMode <= _config.Z1 && s.server.erupeConfig.DebugOptions.AutoQuestBackport {
data = BackportQuest(decryption.UnpackSimple(data))
if s.server.erupeConfig.RealClientMode <= _config.Z1 && s.server.erupeConfig.DebugOptions.AutoQuestBackport {
data = BackportQuest(decryption.UnpackSimple(data), s.server.erupeConfig.RealClientMode)
}
doAckBufSucceed(s, pkt.AckHandle, data)
}
@@ -230,21 +230,21 @@ func loadQuestFile(s *Session, questId int) []byte {
}
decrypted := decryption.UnpackSimple(file)
if _config.ErupeConfig.RealClientMode <= _config.Z1 && s.server.erupeConfig.DebugOptions.AutoQuestBackport {
decrypted = BackportQuest(decrypted)
if s.server.erupeConfig.RealClientMode <= _config.Z1 && s.server.erupeConfig.DebugOptions.AutoQuestBackport {
decrypted = BackportQuest(decrypted, s.server.erupeConfig.RealClientMode)
}
fileBytes := byteframe.NewByteFrameFromBytes(decrypted)
fileBytes.SetLE()
_, _ = fileBytes.Seek(int64(fileBytes.ReadUint32()), 0)
bodyLength := 320
if _config.ErupeConfig.RealClientMode <= _config.S6 {
if s.server.erupeConfig.RealClientMode <= _config.S6 {
bodyLength = 160
} else if _config.ErupeConfig.RealClientMode <= _config.F5 {
} else if s.server.erupeConfig.RealClientMode <= _config.F5 {
bodyLength = 168
} else if _config.ErupeConfig.RealClientMode <= _config.G101 {
} else if s.server.erupeConfig.RealClientMode <= _config.G101 {
bodyLength = 192
} else if _config.ErupeConfig.RealClientMode <= _config.Z1 {
} else if s.server.erupeConfig.RealClientMode <= _config.Z1 {
bodyLength = 224
}
@@ -318,7 +318,7 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) {
bf.WriteBool(true)
}
bf.WriteUint16(0) // Unk
if _config.ErupeConfig.RealClientMode >= _config.G2 {
if s.server.erupeConfig.RealClientMode >= _config.G2 {
bf.WriteUint32(mark)
}
bf.WriteUint16(0) // Unk
@@ -616,23 +616,23 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) {
tuneValues = temp
tuneLimit := 770
if _config.ErupeConfig.RealClientMode <= _config.G1 {
if s.server.erupeConfig.RealClientMode <= _config.G1 {
tuneLimit = 256
} else if _config.ErupeConfig.RealClientMode <= _config.G3 {
} else if s.server.erupeConfig.RealClientMode <= _config.G3 {
tuneLimit = 283
} else if _config.ErupeConfig.RealClientMode <= _config.GG {
} else if s.server.erupeConfig.RealClientMode <= _config.GG {
tuneLimit = 315
} else if _config.ErupeConfig.RealClientMode <= _config.G61 {
} else if s.server.erupeConfig.RealClientMode <= _config.G61 {
tuneLimit = 332
} else if _config.ErupeConfig.RealClientMode <= _config.G7 {
} else if s.server.erupeConfig.RealClientMode <= _config.G7 {
tuneLimit = 339
} else if _config.ErupeConfig.RealClientMode <= _config.G81 {
} else if s.server.erupeConfig.RealClientMode <= _config.G81 {
tuneLimit = 396
} else if _config.ErupeConfig.RealClientMode <= _config.G91 {
} else if s.server.erupeConfig.RealClientMode <= _config.G91 {
tuneLimit = 694
} else if _config.ErupeConfig.RealClientMode <= _config.G101 {
} else if s.server.erupeConfig.RealClientMode <= _config.G101 {
tuneLimit = 704
} else if _config.ErupeConfig.RealClientMode <= _config.Z2 {
} else if s.server.erupeConfig.RealClientMode <= _config.Z2 {
tuneLimit = 750
}
if len(tuneValues) > tuneLimit {

View File

@@ -8,13 +8,6 @@ import (
)
func TestBackportQuest_Basic(t *testing.T) {
// Set up config for the test
oldConfig := _config.ErupeConfig
defer func() { _config.ErupeConfig = oldConfig }()
_config.ErupeConfig = &_config.Config{}
_config.ErupeConfig.RealClientMode = _config.ZZ
// Create a quest data buffer large enough for BackportQuest to work with.
// The function reads a uint32 from data[0:4] as offset, then works at offset+96.
// We need at least offset + 96 + 108 + 6*8 bytes.
@@ -27,7 +20,7 @@ func TestBackportQuest_Basic(t *testing.T) {
data[i] = byte(i & 0xFF)
}
result := BackportQuest(data)
result := BackportQuest(data, _config.ZZ)
if result == nil {
t.Fatal("BackportQuest returned nil")
}
@@ -37,12 +30,6 @@ func TestBackportQuest_Basic(t *testing.T) {
}
func TestBackportQuest_S6Mode(t *testing.T) {
oldConfig := _config.ErupeConfig
defer func() { _config.ErupeConfig = oldConfig }()
_config.ErupeConfig = &_config.Config{}
_config.ErupeConfig.RealClientMode = _config.S6
data := make([]byte, 512)
binary.LittleEndian.PutUint32(data[0:4], 0)
@@ -56,7 +43,7 @@ func TestBackportQuest_S6Mode(t *testing.T) {
// Set some values at data[8:12] so we can check they get copied to data[16:20]
binary.LittleEndian.PutUint32(data[8:12], 0xDEADBEEF)
result := BackportQuest(data)
result := BackportQuest(data, _config.S6)
if result == nil {
t.Fatal("BackportQuest returned nil")
}
@@ -69,12 +56,6 @@ func TestBackportQuest_S6Mode(t *testing.T) {
}
func TestBackportQuest_G91Mode_PatternReplacement(t *testing.T) {
oldConfig := _config.ErupeConfig
defer func() { _config.ErupeConfig = oldConfig }()
_config.ErupeConfig = &_config.Config{}
_config.ErupeConfig.RealClientMode = _config.G91
data := make([]byte, 512)
binary.LittleEndian.PutUint32(data[0:4], 0)
@@ -86,7 +67,7 @@ func TestBackportQuest_G91Mode_PatternReplacement(t *testing.T) {
data[offset+2] = 0x01
data[offset+3] = 0x33
result := BackportQuest(data)
result := BackportQuest(data, _config.G91)
// After BackportQuest, the pattern's last 2 bytes should be replaced
if result[offset+2] != 0xD7 || result[offset+3] != 0x00 {
@@ -96,32 +77,20 @@ func TestBackportQuest_G91Mode_PatternReplacement(t *testing.T) {
}
func TestBackportQuest_F5Mode(t *testing.T) {
oldConfig := _config.ErupeConfig
defer func() { _config.ErupeConfig = oldConfig }()
_config.ErupeConfig = &_config.Config{}
_config.ErupeConfig.RealClientMode = _config.F5
data := make([]byte, 512)
binary.LittleEndian.PutUint32(data[0:4], 0)
result := BackportQuest(data)
result := BackportQuest(data, _config.F5)
if result == nil {
t.Fatal("BackportQuest returned nil")
}
}
func TestBackportQuest_G101Mode(t *testing.T) {
oldConfig := _config.ErupeConfig
defer func() { _config.ErupeConfig = oldConfig }()
_config.ErupeConfig = &_config.Config{}
_config.ErupeConfig.RealClientMode = _config.G101
data := make([]byte, 512)
binary.LittleEndian.PutUint32(data[0:4], 0)
result := BackportQuest(data)
result := BackportQuest(data, _config.G101)
if result == nil {
t.Fatal("BackportQuest returned nil")
}

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/binary"
"erupe-ce/common/byteframe"
_config "erupe-ce/config"
"erupe-ce/network/mhfpacket"
"os"
"path/filepath"
@@ -61,7 +62,7 @@ func TestBackportQuestBasic(t *testing.T) {
}
}()
result := BackportQuest(data)
result := BackportQuest(data, _config.ZZ)
if result != nil && !tc.verify(result) {
t.Errorf("BackportQuest verification failed for result: %d bytes", len(result))
}
@@ -685,7 +686,7 @@ func BenchmarkBackportQuest(b *testing.B) {
binary.LittleEndian.PutUint32(data[0:4], 100)
for i := 0; i < b.N; i++ {
_ = BackportQuest(data)
_ = BackportQuest(data, _config.ZZ)
}
}

View File

@@ -5,6 +5,7 @@ import (
"testing"
"time"
_config "erupe-ce/config"
"erupe-ce/common/mhfitem"
"erupe-ce/network/mhfpacket"
"erupe-ce/server/channelserver/compression/nullcomp"
@@ -214,7 +215,7 @@ func TestSaveLoad_Warehouse(t *testing.T) {
}
// Serialize and save to warehouse
serializedEquip := mhfitem.SerializeWarehouseEquipment(equipment)
serializedEquip := mhfitem.SerializeWarehouseEquipment(equipment, _config.ZZ)
// Initialize warehouse row then update
_, _ = db.Exec("INSERT INTO warehouse (character_id) VALUES ($1) ON CONFLICT DO NOTHING", charID)
@@ -425,7 +426,7 @@ func TestSaveLoad_CraftedEquipment(t *testing.T) {
}
equipment := []mhfitem.MHFEquipment{equip}
serialized := mhfitem.SerializeWarehouseEquipment(equipment)
serialized := mhfitem.SerializeWarehouseEquipment(equipment, _config.ZZ)
// Save to warehouse
_, _ = db.Exec("INSERT INTO warehouse (character_id) VALUES ($1) ON CONFLICT DO NOTHING", charID)

View File

@@ -378,7 +378,7 @@ func handleMsgSysIssueLogkey(s *Session, p mhfpacket.MHFPacket) {
func handleMsgSysRecordLog(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysRecordLog)
if _config.ErupeConfig.RealClientMode == _config.ZZ {
if s.server.erupeConfig.RealClientMode == _config.ZZ {
bf := byteframe.NewByteFrameFromBytes(pkt.Data)
_, _ = bf.Seek(32, 0)
var val uint8
@@ -536,7 +536,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint16(uint16(len(r.userBin3)))
// TODO: This case might be <=G2
if _config.ErupeConfig.RealClientMode <= _config.G1 {
if s.server.erupeConfig.RealClientMode <= _config.G1 {
resp.WriteBytes(make([]byte, 8))
} else {
resp.WriteBytes(make([]byte, 40))
@@ -566,7 +566,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
case 0:
values := bf.ReadUint8()
for i := uint8(0); i < values; i++ {
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
if s.server.erupeConfig.RealClientMode >= _config.Z1 {
findPartyParams.RankRestriction = bf.ReadInt16()
} else {
findPartyParams.RankRestriction = int16(bf.ReadInt8())
@@ -575,7 +575,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
case 1:
values := bf.ReadUint8()
for i := uint8(0); i < values; i++ {
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
if s.server.erupeConfig.RealClientMode >= _config.Z1 {
findPartyParams.Targets = append(findPartyParams.Targets, bf.ReadInt16())
} else {
findPartyParams.Targets = append(findPartyParams.Targets, int16(bf.ReadInt8()))
@@ -585,7 +585,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
values := bf.ReadUint8()
for i := uint8(0); i < values; i++ {
var value int16
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
if s.server.erupeConfig.RealClientMode >= _config.Z1 {
value = bf.ReadInt16()
} else {
value = int16(bf.ReadInt8())
@@ -606,7 +606,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
case 3: // Unknown
values := bf.ReadUint8()
for i := uint8(0); i < values; i++ {
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
if s.server.erupeConfig.RealClientMode >= _config.Z1 {
findPartyParams.Unk0 = append(findPartyParams.Unk0, bf.ReadInt16())
} else {
findPartyParams.Unk0 = append(findPartyParams.Unk0, int16(bf.ReadInt8()))
@@ -615,7 +615,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
case 4: // Looking for n or already have n
values := bf.ReadUint8()
for i := uint8(0); i < values; i++ {
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
if s.server.erupeConfig.RealClientMode >= _config.Z1 {
findPartyParams.Unk1 = append(findPartyParams.Unk1, bf.ReadInt16())
} else {
findPartyParams.Unk1 = append(findPartyParams.Unk1, int16(bf.ReadInt8()))
@@ -624,7 +624,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
case 5:
values := bf.ReadUint8()
for i := uint8(0); i < values; i++ {
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
if s.server.erupeConfig.RealClientMode >= _config.Z1 {
findPartyParams.QuestID = append(findPartyParams.QuestID, bf.ReadInt16())
} else {
findPartyParams.QuestID = append(findPartyParams.QuestID, int16(bf.ReadInt8()))
@@ -661,15 +661,15 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
_, _ = sb3.Seek(4, 0)
stageDataParams := 7
if _config.ErupeConfig.RealClientMode <= _config.G10 {
if s.server.erupeConfig.RealClientMode <= _config.G10 {
stageDataParams = 4
} else if _config.ErupeConfig.RealClientMode <= _config.Z1 {
} else if s.server.erupeConfig.RealClientMode <= _config.Z1 {
stageDataParams = 6
}
var stageData []int16
for i := 0; i < stageDataParams; i++ {
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
if s.server.erupeConfig.RealClientMode >= _config.Z1 {
stageData = append(stageData, sb3.ReadInt16())
} else {
stageData = append(stageData, int16(sb3.ReadInt8()))
@@ -746,7 +746,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
resp.WriteUint8(uint8(len(sr.rawBinData1)))
for i := range sr.stageData {
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
if s.server.erupeConfig.RealClientMode >= _config.Z1 {
resp.WriteInt16(sr.stageData[i])
} else {
resp.WriteInt8(int8(sr.stageData[i]))

View File

@@ -25,11 +25,11 @@ type ShopItem struct {
RoadFatalis uint16 `db:"road_fatalis"`
}
func writeShopItems(bf *byteframe.ByteFrame, items []ShopItem) {
func writeShopItems(bf *byteframe.ByteFrame, items []ShopItem, mode _config.Mode) {
bf.WriteUint16(uint16(len(items)))
bf.WriteUint16(uint16(len(items)))
for _, item := range items {
if _config.ErupeConfig.RealClientMode >= _config.Z2 {
if mode >= _config.Z2 {
bf.WriteUint32(item.ID)
}
bf.WriteUint32(item.ItemID)
@@ -37,19 +37,19 @@ func writeShopItems(bf *byteframe.ByteFrame, items []ShopItem) {
bf.WriteUint16(item.Quantity)
bf.WriteUint16(item.MinHR)
bf.WriteUint16(item.MinSR)
if _config.ErupeConfig.RealClientMode >= _config.Z2 {
if mode >= _config.Z2 {
bf.WriteUint16(item.MinGR)
}
bf.WriteUint8(0) // Unk
bf.WriteUint8(item.StoreLevel)
if _config.ErupeConfig.RealClientMode >= _config.Z2 {
if mode >= _config.Z2 {
bf.WriteUint16(item.MaxQuantity)
bf.WriteUint16(item.UsedQuantity)
}
if _config.ErupeConfig.RealClientMode == _config.Z1 {
if mode == _config.Z1 {
bf.WriteUint8(uint8(item.RoadFloors))
bf.WriteUint8(uint8(item.RoadFatalis))
} else if _config.ErupeConfig.RealClientMode >= _config.Z2 {
} else if mode >= _config.Z2 {
bf.WriteUint16(item.RoadFloors)
bf.WriteUint16(item.RoadFatalis)
}
@@ -90,7 +90,7 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
switch pkt.ShopType {
case 1: // Running gachas
// Fundamentally, gacha works completely differently, just hide it for now.
if _config.ErupeConfig.RealClientMode <= _config.G7 {
if s.server.erupeConfig.RealClientMode <= _config.G7 {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
return
}
@@ -123,7 +123,7 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
ps.Uint8(bf, g.Name, true)
ps.Uint8(bf, g.URLBanner, false)
ps.Uint8(bf, g.URLFeature, false)
if _config.ErupeConfig.RealClientMode >= _config.G10 {
if s.server.erupeConfig.RealClientMode >= _config.G10 {
bf.WriteBool(g.Wide)
ps.Uint8(bf, g.URLThumbnail, false)
}
@@ -133,7 +133,7 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(0)
}
bf.WriteUint8(g.GachaType)
if _config.ErupeConfig.RealClientMode >= _config.G10 {
if s.server.erupeConfig.RealClientMode >= _config.G10 {
bf.WriteBool(g.Hidden)
}
}
@@ -223,7 +223,7 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
if len(items) > int(pkt.Limit) {
items = items[:pkt.Limit]
}
writeShopItems(bf, items)
writeShopItems(bf, items, s.server.erupeConfig.RealClientMode)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
}
@@ -303,7 +303,7 @@ func handleMsgMhfGetFpointExchangeList(s *Session, p mhfpacket.MHFPacket) {
exchanges = append(exchanges, exchange)
}
}
if _config.ErupeConfig.RealClientMode <= _config.Z2 {
if s.server.erupeConfig.RealClientMode <= _config.Z2 {
bf.WriteUint8(uint8(len(exchanges)))
bf.WriteUint8(uint8(buyables))
} else {

View File

@@ -4,13 +4,14 @@ import (
"testing"
"erupe-ce/common/byteframe"
_config "erupe-ce/config"
)
func TestWriteShopItems_Empty(t *testing.T) {
bf := byteframe.NewByteFrame()
items := []ShopItem{}
writeShopItems(bf, items)
writeShopItems(bf, items, _config.ZZ)
result := byteframe.NewByteFrameFromBytes(bf.Data())
count1 := result.ReadUint16()
@@ -43,7 +44,7 @@ func TestWriteShopItems_SingleItem(t *testing.T) {
},
}
writeShopItems(bf, items)
writeShopItems(bf, items, _config.ZZ)
result := byteframe.NewByteFrameFromBytes(bf.Data())
count1 := result.ReadUint16()
@@ -117,7 +118,7 @@ func TestWriteShopItems_MultipleItems(t *testing.T) {
{ID: 3, ItemID: 300, Cost: 2000, Quantity: 1},
}
writeShopItems(bf, items)
writeShopItems(bf, items, _config.ZZ)
result := byteframe.NewByteFrameFromBytes(bf.Data())
count1 := result.ReadUint16()

View File

@@ -75,7 +75,7 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) {
}
}
if _config.ErupeConfig.RealClientMode <= _config.G7 {
if s.server.erupeConfig.RealClientMode <= _config.G7 {
towerInfo.Level = towerInfo.Level[:1]
}

View File

@@ -621,16 +621,13 @@ func IntegrationTest_ClientVersionCompatibility(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
originalVersion := _config.ErupeConfig.RealClientMode
defer func() { _config.ErupeConfig.RealClientMode = originalVersion }()
_config.ErupeConfig.RealClientMode = tt.clientVersion
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
s := &Session{
sendPackets: make(chan packet, 100),
server: &Server{
erupeConfig: _config.ErupeConfig,
server: &Server{
erupeConfig: &_config.Config{
RealClientMode: tt.clientVersion,
},
},
}
s.cryptConn = mock

View File

@@ -35,6 +35,7 @@ type CharacterSaveData struct {
CharID uint32
Name string
IsNewCharacter bool
Mode _config.Mode
Pointers map[SavePointer]int
Gender bool
@@ -56,9 +57,9 @@ type CharacterSaveData struct {
decompSave []byte
}
func getPointers() map[SavePointer]int {
func getPointers(mode _config.Mode) map[SavePointer]int {
pointers := map[SavePointer]int{pGender: 81, lBookshelfData: 5576}
switch _config.ErupeConfig.RealClientMode {
switch mode {
case _config.ZZ:
pointers[pPlaytime] = 128356
pointers[pWeaponID] = 128522
@@ -114,9 +115,9 @@ func getPointers() map[SavePointer]int {
pointers[pGardenData] = 26424
pointers[pRP] = 26614
}
if _config.ErupeConfig.RealClientMode == _config.G5 {
if mode == _config.G5 {
pointers[lBookshelfData] = 5548
} else if _config.ErupeConfig.RealClientMode <= _config.GG {
} else if mode <= _config.GG {
pointers[lBookshelfData] = 4520
}
return pointers
@@ -144,10 +145,10 @@ func (save *CharacterSaveData) Decompress() error {
func (save *CharacterSaveData) updateSaveDataWithStruct() {
rpBytes := make([]byte, 2)
binary.LittleEndian.PutUint16(rpBytes, save.RP)
if _config.ErupeConfig.RealClientMode >= _config.F4 {
if save.Mode >= _config.F4 {
copy(save.decompSave[save.Pointers[pRP]:save.Pointers[pRP]+2], rpBytes)
}
if _config.ErupeConfig.RealClientMode >= _config.G10 {
if save.Mode >= _config.G10 {
copy(save.decompSave[save.Pointers[pKQF]:save.Pointers[pKQF]+8], save.KQF)
}
}
@@ -161,7 +162,7 @@ func (save *CharacterSaveData) updateStructWithSaveData() {
save.Gender = false
}
if !save.IsNewCharacter {
if _config.ErupeConfig.RealClientMode >= _config.S6 {
if save.Mode >= _config.S6 {
save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2])
save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5]
save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195]
@@ -173,12 +174,12 @@ func (save *CharacterSaveData) updateStructWithSaveData() {
save.WeaponType = save.decompSave[save.Pointers[pWeaponType]]
save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pWeaponID] : save.Pointers[pWeaponID]+2])
save.HR = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pHR] : save.Pointers[pHR]+2])
if _config.ErupeConfig.RealClientMode >= _config.G1 {
if save.Mode >= _config.G1 {
if save.HR == uint16(999) {
save.GR = grpToGR(int(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4])))
}
}
if _config.ErupeConfig.RealClientMode >= _config.G10 {
if save.Mode >= _config.G10 {
save.KQF = save.decompSave[save.Pointers[pKQF] : save.Pointers[pKQF]+8]
}
}

View File

@@ -176,7 +176,7 @@ func TestSessionLifecycle_WarehouseDataPersistence(t *testing.T) {
createTestEquipmentItem(102, 3),
}
serializedEquip := mhfitem.SerializeWarehouseEquipment(equipment)
serializedEquip := mhfitem.SerializeWarehouseEquipment(equipment, _config.ZZ)
// Save to warehouse directly (simulating a save handler)
_, _ = db.Exec("INSERT INTO warehouse (character_id) VALUES ($1) ON CONFLICT DO NOTHING", charID)
@@ -586,7 +586,9 @@ func createTestServerWithDB(t *testing.T, db *sqlx.DB) *Server {
userBinaryParts: make(map[userBinaryPartID][]byte),
minidataParts: make(map[uint32][]byte),
semaphore: make(map[string]*Semaphore),
erupeConfig: _config.ErupeConfig,
erupeConfig: &_config.Config{
RealClientMode: _config.ZZ,
},
isShuttingDown: false,
}

View File

@@ -145,6 +145,8 @@ func (s *Server) Start() error {
}
s.listener = l
initCommands(s.erupeConfig.Commands, s.logger)
go s.acceptClients()
go s.manageSessions()
go s.invalidateSessions()

View File

@@ -81,9 +81,9 @@ func NewSession(server *Server, conn net.Conn) *Session {
logger: server.logger.Named(conn.RemoteAddr().String()),
server: server,
rawConn: conn,
cryptConn: network.NewCryptConn(conn),
cryptConn: network.NewCryptConn(conn, server.erupeConfig.RealClientMode),
sendPackets: make(chan packet, 20),
clientContext: &clientctx.ClientContext{},
clientContext: &clientctx.ClientContext{RealClientMode: server.erupeConfig.RealClientMode},
lastPacket: time.Now(),
objectID: server.getObjectId(),
sessionStart: TimeAdjusted().Unix(),

View File

@@ -104,7 +104,7 @@ func (s *Server) handleEntranceServerConnection(conn net.Conn) {
}
// Create a new encrypted connection handler and read a packet from it.
cc := network.NewCryptConn(conn)
cc := network.NewCryptConn(conn, s.erupeConfig.RealClientMode)
pkt, err := cc.ReadPacket()
if err != nil {
s.logger.Warn("Error reading packet", zap.Error(err))

View File

@@ -63,8 +63,8 @@ func encodeServerInfo(config *_config.Config, s *Server, local bool) []byte {
for channelIdx, ci := range si.Channels {
sid := (serverIdx<<8 | 4096) + (channelIdx | 16)
if _config.ErupeConfig.DebugOptions.ProxyPort != 0 {
bf.WriteUint16(_config.ErupeConfig.DebugOptions.ProxyPort)
if config.DebugOptions.ProxyPort != 0 {
bf.WriteUint16(config.DebugOptions.ProxyPort)
} else {
bf.WriteUint16(ci.Port)
}

View File

@@ -105,7 +105,7 @@ func (s *Server) getUserRights(uid uint32) uint32 {
var rights uint32
if uid != 0 {
_ = s.db.QueryRow("SELECT rights FROM users WHERE id=$1", uid).Scan(&rights)
_, rights = mhfcourse.GetCourseStruct(rights)
_, rights = mhfcourse.GetCourseStruct(rights, s.erupeConfig.DefaultCourses)
}
return rights
}

View File

@@ -5,6 +5,7 @@ import (
"testing"
"time"
"erupe-ce/config"
"github.com/DATA-DOG/go-sqlmock"
"github.com/jmoiron/sqlx"
"go.uber.org/zap"
@@ -301,8 +302,9 @@ func newTestServerWithMock(t *testing.T) (*Server, sqlmock.Sqlmock) {
sqlxDB := sqlx.NewDb(db, "sqlmock")
server := &Server{
logger: zap.NewNop(),
db: sqlxDB,
logger: zap.NewNop(),
db: sqlxDB,
erupeConfig: &_config.Config{},
}
return server, mock

View File

@@ -75,7 +75,7 @@ func TestSessionStruct(t *testing.T) {
logger: logger,
server: nil,
rawConn: conn,
cryptConn: network.NewCryptConn(conn),
cryptConn: network.NewCryptConn(conn, _config.ZZ),
}
if s.logger != logger {
@@ -145,7 +145,7 @@ func TestHandlePacketUnknownRequest(t *testing.T) {
logger: logger,
server: server,
rawConn: conn,
cryptConn: network.NewCryptConn(conn),
cryptConn: network.NewCryptConn(conn, _config.ZZ),
}
bf := byteframe.NewByteFrame()
@@ -176,7 +176,7 @@ func TestHandlePacketWithDevModeLogging(t *testing.T) {
logger: logger,
server: server,
rawConn: conn,
cryptConn: network.NewCryptConn(conn),
cryptConn: network.NewCryptConn(conn, _config.ZZ),
}
bf := byteframe.NewByteFrame()
@@ -214,7 +214,7 @@ func TestHandlePacketRequestTypes(t *testing.T) {
logger: logger,
server: server,
rawConn: conn,
cryptConn: network.NewCryptConn(conn),
cryptConn: network.NewCryptConn(conn, _config.ZZ),
}
bf := byteframe.NewByteFrame()
@@ -324,7 +324,7 @@ func TestMockConnDeadlines(t *testing.T) {
func TestSessionWithCryptConn(t *testing.T) {
conn := newMockConn()
cryptConn := network.NewCryptConn(conn)
cryptConn := network.NewCryptConn(conn, _config.ZZ)
if cryptConn == nil {
t.Fatal("NewCryptConn() returned nil")
@@ -361,7 +361,7 @@ func TestSessionWorkWithDevModeLogging(t *testing.T) {
logger: logger,
server: server,
rawConn: serverConn,
cryptConn: network.NewCryptConn(serverConn),
cryptConn: network.NewCryptConn(serverConn, _config.ZZ),
}
_ = clientConn.Close()
@@ -386,7 +386,7 @@ func TestSessionWorkWithEmptyRead(t *testing.T) {
logger: logger,
server: server,
rawConn: serverConn,
cryptConn: network.NewCryptConn(serverConn),
cryptConn: network.NewCryptConn(serverConn, _config.ZZ),
}
_ = clientConn.Close()

View File

@@ -101,7 +101,7 @@ func (s *Server) handleConnection(conn net.Conn) {
logger: s.logger,
server: s,
rawConn: conn,
cryptConn: network.NewCryptConn(conn),
cryptConn: network.NewCryptConn(conn, s.erupeConfig.RealClientMode),
}
// Do the session's work.