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

@@ -1,7 +1,6 @@
package mhfcourse
import (
_config "erupe-ce/config"
"math"
"sort"
"time"
@@ -70,9 +69,9 @@ func CourseExists(ID uint16, c []Course) bool {
}
// GetCourseStruct returns a slice of Course(s) from a rights integer
func GetCourseStruct(rights uint32) ([]Course, uint32) {
func GetCourseStruct(rights uint32, defaultCourses []uint16) ([]Course, uint32) {
var resp []Course
for _, c := range _config.ErupeConfig.DefaultCourses {
for _, c := range defaultCourses {
resp = append(resp, Course{ID: c})
}
s := Courses()

View File

@@ -1,7 +1,6 @@
package mhfcourse
import (
_config "erupe-ce/config"
"math"
"testing"
"time"
@@ -121,14 +120,7 @@ func TestCourseExists_EmptySlice(t *testing.T) {
}
func TestGetCourseStruct(t *testing.T) {
// Save original config and restore after test
originalDefaultCourses := _config.ErupeConfig.DefaultCourses
defer func() {
_config.ErupeConfig.DefaultCourses = originalDefaultCourses
}()
// Set up test config
_config.ErupeConfig.DefaultCourses = []uint16{1, 2}
defaultCourses := []uint16{1, 2}
tests := []struct {
name string
@@ -164,7 +156,7 @@ func TestGetCourseStruct(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
courses, newRights := GetCourseStruct(tt.rights)
courses, newRights := GetCourseStruct(tt.rights, defaultCourses)
if len(courses) < tt.wantMinLen {
t.Errorf("GetCourseStruct(%d) returned %d courses, want at least %d", tt.rights, len(courses), tt.wantMinLen)
@@ -193,15 +185,8 @@ func TestGetCourseStruct(t *testing.T) {
}
func TestGetCourseStruct_NetcafeCourse(t *testing.T) {
// Save original config
originalDefaultCourses := _config.ErupeConfig.DefaultCourses
defer func() {
_config.ErupeConfig.DefaultCourses = originalDefaultCourses
}()
_config.ErupeConfig.DefaultCourses = []uint16{}
// Course 26 (NetCafe) should add course 25
courses, _ := GetCourseStruct(1 << 26)
courses, _ := GetCourseStruct(1<<26, nil)
hasNetcafe := false
hasCafeSP := false
@@ -230,15 +215,8 @@ func TestGetCourseStruct_NetcafeCourse(t *testing.T) {
}
func TestGetCourseStruct_NCourse(t *testing.T) {
// Save original config
originalDefaultCourses := _config.ErupeConfig.DefaultCourses
defer func() {
_config.ErupeConfig.DefaultCourses = originalDefaultCourses
}()
_config.ErupeConfig.DefaultCourses = []uint16{}
// Course 9 should add course 30
courses, _ := GetCourseStruct(1 << 9)
courses, _ := GetCourseStruct(1<<9, nil)
hasNCourse := false
hasRealNetcafe := false
@@ -260,15 +238,8 @@ func TestGetCourseStruct_NCourse(t *testing.T) {
}
func TestGetCourseStruct_HidenCourse(t *testing.T) {
// Save original config
originalDefaultCourses := _config.ErupeConfig.DefaultCourses
defer func() {
_config.ErupeConfig.DefaultCourses = originalDefaultCourses
}()
_config.ErupeConfig.DefaultCourses = []uint16{}
// Course 10 (Hiden) should add course 31
courses, _ := GetCourseStruct(1 << 10)
courses, _ := GetCourseStruct(1<<10, nil)
hasHiden := false
hasHidenExtra := false
@@ -290,14 +261,7 @@ func TestGetCourseStruct_HidenCourse(t *testing.T) {
}
func TestGetCourseStruct_ExpiryDate(t *testing.T) {
// Save original config
originalDefaultCourses := _config.ErupeConfig.DefaultCourses
defer func() {
_config.ErupeConfig.DefaultCourses = originalDefaultCourses
}()
_config.ErupeConfig.DefaultCourses = []uint16{}
courses, _ := GetCourseStruct(1 << 3)
courses, _ := GetCourseStruct(1<<3, nil)
expectedExpiry := time.Date(2030, 1, 1, 0, 0, 0, 0, time.FixedZone("UTC+9", 9*60*60))
@@ -311,14 +275,7 @@ func TestGetCourseStruct_ExpiryDate(t *testing.T) {
}
func TestGetCourseStruct_ReturnsRecalculatedRights(t *testing.T) {
// Save original config
originalDefaultCourses := _config.ErupeConfig.DefaultCourses
defer func() {
_config.ErupeConfig.DefaultCourses = originalDefaultCourses
}()
_config.ErupeConfig.DefaultCourses = []uint16{}
courses, newRights := GetCourseStruct(2 + 8 + 32) // courses 1, 3, 5
courses, newRights := GetCourseStruct(2+8+32, nil) // courses 1, 3, 5
// Calculate expected rights from returned courses
var expectedRights uint32
@@ -363,17 +320,11 @@ func BenchmarkCourseExists(b *testing.B) {
}
func BenchmarkGetCourseStruct(b *testing.B) {
// Save original config
originalDefaultCourses := _config.ErupeConfig.DefaultCourses
defer func() {
_config.ErupeConfig.DefaultCourses = originalDefaultCourses
}()
_config.ErupeConfig.DefaultCourses = []uint16{1, 2}
defaultCourses := []uint16{1, 2}
rights := uint32(2 + 8 + 32 + 128 + 512)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = GetCourseStruct(rights)
_, _ = GetCourseStruct(rights, defaultCourses)
}
}

View File

@@ -3,7 +3,7 @@ package mhfitem
import (
"erupe-ce/common/byteframe"
"erupe-ce/common/token"
_config "erupe-ce/config"
"erupe-ce/config"
)
// MHFItem represents a single item identified by its in-game item ID.
@@ -113,7 +113,7 @@ func SerializeWarehouseItems(i []MHFItemStack) []byte {
// ReadWarehouseEquipment deserializes an MHFEquipment from a ByteFrame. The
// binary layout varies by game version: sigils are present from G1 onward and
// an additional field is present from Z1 onward.
func ReadWarehouseEquipment(bf *byteframe.ByteFrame) MHFEquipment {
func ReadWarehouseEquipment(bf *byteframe.ByteFrame, mode _config.Mode) MHFEquipment {
var equipment MHFEquipment
equipment.Decorations = make([]MHFItem, 3)
equipment.Sigils = make([]MHFSigil, 3)
@@ -131,7 +131,7 @@ func ReadWarehouseEquipment(bf *byteframe.ByteFrame) MHFEquipment {
for i := 0; i < 3; i++ {
equipment.Decorations[i].ItemID = bf.ReadUint16()
}
if _config.ErupeConfig.RealClientMode >= _config.G1 {
if mode >= _config.G1 {
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
equipment.Sigils[i].Effects[j].ID = bf.ReadUint16()
@@ -145,14 +145,14 @@ func ReadWarehouseEquipment(bf *byteframe.ByteFrame) MHFEquipment {
equipment.Sigils[i].Unk3 = bf.ReadUint8()
}
}
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
if mode >= _config.Z1 {
equipment.Unk1 = bf.ReadUint16()
}
return equipment
}
// ToBytes serializes the equipment to its binary protocol representation.
func (e MHFEquipment) ToBytes() []byte {
func (e MHFEquipment) ToBytes(mode _config.Mode) []byte {
bf := byteframe.NewByteFrame()
bf.WriteUint32(e.WarehouseID)
bf.WriteUint8(e.ItemType)
@@ -162,7 +162,7 @@ func (e MHFEquipment) ToBytes() []byte {
for i := 0; i < 3; i++ {
bf.WriteUint16(e.Decorations[i].ItemID)
}
if _config.ErupeConfig.RealClientMode >= _config.G1 {
if mode >= _config.G1 {
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
bf.WriteUint16(e.Sigils[i].Effects[j].ID)
@@ -176,7 +176,7 @@ func (e MHFEquipment) ToBytes() []byte {
bf.WriteUint8(e.Sigils[i].Unk3)
}
}
if _config.ErupeConfig.RealClientMode >= _config.Z1 {
if mode >= _config.Z1 {
bf.WriteUint16(e.Unk1)
}
return bf.Data()
@@ -184,12 +184,12 @@ func (e MHFEquipment) ToBytes() []byte {
// SerializeWarehouseEquipment serializes a slice of equipment with a uint16
// count header for transmission in warehouse response packets.
func SerializeWarehouseEquipment(i []MHFEquipment) []byte {
func SerializeWarehouseEquipment(i []MHFEquipment, mode _config.Mode) []byte {
bf := byteframe.NewByteFrame()
bf.WriteUint16(uint16(len(i)))
bf.WriteUint16(0) // Unused
for _, j := range i {
bf.WriteBytes(j.ToBytes())
bf.WriteBytes(j.ToBytes(mode))
}
return bf.Data()
}

View File

@@ -119,11 +119,11 @@ func TestSerializeWarehouseItems_Empty(t *testing.T) {
func TestDiffItemStacks(t *testing.T) {
tests := []struct {
name string
old []MHFItemStack
update []MHFItemStack
wantLen int
checkFn func(t *testing.T, result []MHFItemStack)
name string
old []MHFItemStack
update []MHFItemStack
wantLen int
checkFn func(t *testing.T, result []MHFItemStack)
}{
{
name: "update existing quantity",
@@ -210,12 +210,7 @@ func TestDiffItemStacks(t *testing.T) {
}
func TestReadWarehouseEquipment(t *testing.T) {
// Save original config
originalMode := _config.ErupeConfig.RealClientMode
defer func() {
_config.ErupeConfig.RealClientMode = originalMode
}()
_config.ErupeConfig.RealClientMode = _config.Z1
mode := _config.Z1
bf := byteframe.NewByteFrame()
bf.WriteUint32(12345) // WarehouseID
@@ -248,7 +243,7 @@ func TestReadWarehouseEquipment(t *testing.T) {
bf.WriteUint16(9999)
_, _ = bf.Seek(0, 0)
equipment := ReadWarehouseEquipment(bf)
equipment := ReadWarehouseEquipment(bf, mode)
if equipment.WarehouseID != 12345 {
t.Errorf("WarehouseID = %d, want 12345", equipment.WarehouseID)
@@ -274,12 +269,7 @@ func TestReadWarehouseEquipment(t *testing.T) {
}
func TestReadWarehouseEquipment_ZeroWarehouseID(t *testing.T) {
// Save original config
originalMode := _config.ErupeConfig.RealClientMode
defer func() {
_config.ErupeConfig.RealClientMode = originalMode
}()
_config.ErupeConfig.RealClientMode = _config.Z1
mode := _config.Z1
bf := byteframe.NewByteFrame()
bf.WriteUint32(0) // WarehouseID = 0
@@ -304,7 +294,7 @@ func TestReadWarehouseEquipment_ZeroWarehouseID(t *testing.T) {
bf.WriteUint16(0)
_, _ = bf.Seek(0, 0)
equipment := ReadWarehouseEquipment(bf)
equipment := ReadWarehouseEquipment(bf, mode)
if equipment.WarehouseID == 0 {
t.Error("WarehouseID should be replaced with random value when input is 0")
@@ -312,12 +302,7 @@ func TestReadWarehouseEquipment_ZeroWarehouseID(t *testing.T) {
}
func TestMHFEquipment_ToBytes(t *testing.T) {
// Save original config
originalMode := _config.ErupeConfig.RealClientMode
defer func() {
_config.ErupeConfig.RealClientMode = originalMode
}()
_config.ErupeConfig.RealClientMode = _config.Z1
mode := _config.Z1
equipment := MHFEquipment{
WarehouseID: 12345,
@@ -333,9 +318,9 @@ func TestMHFEquipment_ToBytes(t *testing.T) {
equipment.Sigils[i].Effects = make([]MHFSigilEffect, 3)
}
data := equipment.ToBytes()
data := equipment.ToBytes(mode)
bf := byteframe.NewByteFrameFromBytes(data)
readEquipment := ReadWarehouseEquipment(bf)
readEquipment := ReadWarehouseEquipment(bf, mode)
if readEquipment.WarehouseID != equipment.WarehouseID {
t.Errorf("WarehouseID = %d, want %d", readEquipment.WarehouseID, equipment.WarehouseID)
@@ -352,12 +337,7 @@ func TestMHFEquipment_ToBytes(t *testing.T) {
}
func TestSerializeWarehouseEquipment(t *testing.T) {
// Save original config
originalMode := _config.ErupeConfig.RealClientMode
defer func() {
_config.ErupeConfig.RealClientMode = originalMode
}()
_config.ErupeConfig.RealClientMode = _config.Z1
mode := _config.Z1
equipment := []MHFEquipment{
{
@@ -383,7 +363,7 @@ func TestSerializeWarehouseEquipment(t *testing.T) {
}
}
data := SerializeWarehouseEquipment(equipment)
data := SerializeWarehouseEquipment(equipment, mode)
bf := byteframe.NewByteFrameFromBytes(data)
count := bf.ReadUint16()
@@ -393,12 +373,7 @@ func TestSerializeWarehouseEquipment(t *testing.T) {
}
func TestMHFEquipment_RoundTrip(t *testing.T) {
// Test that we can write and read back the same equipment
originalMode := _config.ErupeConfig.RealClientMode
defer func() {
_config.ErupeConfig.RealClientMode = originalMode
}()
_config.ErupeConfig.RealClientMode = _config.Z1
mode := _config.Z1
original := MHFEquipment{
WarehouseID: 99999,
@@ -419,11 +394,11 @@ func TestMHFEquipment_RoundTrip(t *testing.T) {
}
// Write to bytes
data := original.ToBytes()
data := original.ToBytes(mode)
// Read back
bf := byteframe.NewByteFrameFromBytes(data)
recovered := ReadWarehouseEquipment(bf)
recovered := ReadWarehouseEquipment(bf, mode)
// Compare
if recovered.WarehouseID != original.WarehouseID {