Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion internal/configs/configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,15 @@ func AddOverlayOverrides(dotMap map[string]any) error {
if len(newKeys) == 0 {
return nil
}
return configData.OverlayOverrides(newKeys)

// Overlay the full override set rather than just the new keys. Overlaying
// only the new keys would unmarshal a partial Modules block into the live
// config, replacing the inner Modules[<name>] map wholesale and discarding
// every operator-supplied value for that module. Flatten first: at this
// point `overrides` is mixed-shape (nested maps loaded from
// config-overrides.yaml plus the flat dotted keys added above), and
// OverlayOverrides re-nests it internally.
return configData.OverlayOverrides(Flatten(overrides))
}

// OverlayDotMap overlays values from a dot-syntax map onto the Config.
Expand Down
64 changes: 64 additions & 0 deletions internal/configs/overrides_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package configs
import (
"testing"

"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
)

Expand Down Expand Up @@ -95,3 +96,66 @@ func TestOverlayDotMapMultipleFields(t *testing.T) {
t.Errorf("Expected SomeField to be 'updated', got '%s'", cfg.Statistics.SomeField)
}
}

// TestAddOverlayOverridesPreservesOperatorOverrides reproduces the boot
// sequence for a world whose config-overrides.yaml contains a partial
// Modules block: the operator has set some (but not all) of a module's keys,
// and the module's data-overlay config ships a superset of those keys.
// Applying the overlay must fill in the missing defaults WITHOUT clobbering
// the operator-supplied values or other modules' blocks.
func TestAddOverlayOverridesPreservesOperatorOverrides(t *testing.T) {

// Snapshot and restore package globals so this test is hermetic.
origConfigData := configData
origOverrides := overrides
origKeyLookups := keyLookups
origTypeLookups := typeLookups
t.Cleanup(func() {
configData = origConfigData
overrides = origOverrides
keyLookups = origKeyLookups
typeLookups = origTypeLookups
})

configData = Config{}
keyLookups = map[string]string{}
typeLookups = map[string]string{}

// The operator's config-overrides.yaml: a partial Modules block for
// "weather" (missing NewSetting), plus an unrelated module's block.
operatorYAML := []byte(`
Modules:
weather:
Enabled: true
CycleSeconds: 120
othermod:
Setting: keepme
`)
loadedOverrides := map[string]any{}
require.NoError(t, yaml.Unmarshal(operatorYAML, &loadedOverrides))
overrides = loadedOverrides

// ReloadConfig applies operator overrides onto the live config at boot.
require.NoError(t, configData.OverlayOverrides(overrides))

// The module loads and registers its data-overlay config, a superset of
// the operator's keys. This mirrors how internal/plugins builds the map.
err := AddOverlayOverrides(map[string]any{
`Modules.weather.Enabled`: false, // module default; operator set true
`Modules.weather.CycleSeconds`: 60, // module default; operator set 120
`Modules.weather.NewSetting`: `overlayval`, // new key, absent from operator overrides
})
require.NoError(t, err)

flat := Flatten(map[string]any(configData.Modules))

// (a) Operator-supplied values must survive in the live config.
require.Equal(t, true, flat[`weather.Enabled`], `operator override Modules.weather.Enabled was clobbered by the module overlay`)
require.Equal(t, 120, flat[`weather.CycleSeconds`], `operator override Modules.weather.CycleSeconds was clobbered by the module overlay`)

// (b) Keys absent from the operator overrides get the overlay defaults.
require.Equal(t, `overlayval`, flat[`weather.NewSetting`])

// (c) Other modules' blocks are untouched.
require.Equal(t, `keepme`, flat[`othermod.Setting`])
}
5 changes: 4 additions & 1 deletion internal/plugins/pluginconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"fmt"

"github.com/GoMudEngine/GoMud/internal/configs"
"github.com/GoMudEngine/GoMud/internal/mudlog"
)

type PluginConfig struct {
pluginName string
}

func (p *PluginConfig) Set(name string, val any) {
configs.SetVal(fmt.Sprintf(`Modules.%s.%s`, p.pluginName, name), fmt.Sprintf(`%v`, val))
if err := configs.SetVal(fmt.Sprintf(`Modules.%s.%s`, p.pluginName, name), fmt.Sprintf(`%v`, val)); err != nil {
mudlog.Error(`PluginConfig.Set`, `plugin`, p.pluginName, `key`, name, `error`, err)
}
}

func (p *PluginConfig) Get(name string) any {
Expand Down