Overview
The Settings module provides persistent storage for script configuration with automatic saving and scope-based organization. Settings are stored per-script and can be organized by character, game, or custom scopes.
Settings automatically persist to SQLite database and use an internal caching system for performance.
Basic Usage
CharSettings
Character-specific settings (scoped to current character).
# Store character-specific data
CharSettings['hunting_area'] = 'kobolds'
CharSettings['last_login'] = Time.now
echo CharSettings['hunting_area'] # => 'kobolds'
GameSettings
Game-wide settings (shared across all characters in the same game).
# Store game-wide preferences
GameSettings['debug_mode'] = true
GameSettings['theme'] = 'dark'
echo GameSettings['debug_mode'] # => true
Settings
Direct Settings access (uses default scope - typically character-specific).
Settings['my_setting'] = 'value'
value = Settings['my_setting']
Data Types
Settings supports any Marshal-serializable Ruby object:
# Strings
CharSettings['name'] = 'Bob'
# Numbers
CharSettings['count'] = 42
CharSettings['ratio'] = 3.14
# Booleans
CharSettings['enabled'] = true
# Arrays
CharSettings['items'] = ['sword', 'shield', 'potion']
# Hashes
CharSettings['config'] = {
mode: 'aggressive',
speed: 'fast',
loot: true
}
# Nested structures
CharSettings['database'] = {
hunting: {
kobolds: { count: 10, xp: 500 },
trolls: { count: 5, xp: 1000 }
}
}
Hash Operations
Settings values behave like normal Ruby objects:
# Initialize a hash
CharSettings['stats'] = {}
# Add values
CharSettings['stats']['kills'] = 0
CharSettings['stats']['deaths'] = 0
# Modify values
CharSettings['stats']['kills'] += 1
# Nested access
CharSettings['inventory'] = { weapons: {}, armor: {} }
CharSettings['inventory']['weapons']['sword'] = { damage: 10 }
Array Operations
# Initialize array
CharSettings['visited_rooms'] = []
# Add items
CharSettings['visited_rooms'] << 'Town Square'
CharSettings['visited_rooms'].push('Temple')
# Modify
CharSettings['visited_rooms'].concat(['Bank', 'Inn'])
# Access
first_room = CharSettings['visited_rooms'].first
room_count = CharSettings['visited_rooms'].length
Default Values
Use the ||= operator for defaults:
# Set default if not already set
CharSettings['hunting_count'] ||= 0
# Or use || for inline defaults
count = CharSettings['hunting_count'] || 0
# Complex defaults
CharSettings['config'] ||= {
mode: 'safe',
auto_loot: true,
areas: ['kobolds', 'rats']
}
Checking Existence
# Check if a setting exists (and is not nil)
if CharSettings['hunting_area']
echo "Hunting in #{CharSettings['hunting_area']}"
end
# Check for nil explicitly
if CharSettings['some_setting'].nil?
echo 'Setting not configured'
end
# Use fetch for safe access
value = CharSettings.to_hash.fetch('key', 'default')
Advanced Features
to_hash
Get a snapshot of all settings as a plain Hash:
# Get all character settings
all_settings = CharSettings.to_hash
all_settings.each do |key, value|
echo "#{key}: #{value}"
end
Custom Scopes
Create settings with custom scope strings:
# Create account-wide settings
account_scope = "account:#{XMLData.player_id}"
account_settings = Settings.root_proxy_for(account_scope)
account_settings['premium'] = true
account_settings['characters'] = ['Bob', 'Alice', 'Charlie']
to_h (Legacy)
Alias for to_hash:
settings_hash = CharSettings.to_h
Instance Settings (Advanced)
For multi-instance scripts that need separate settings per instance:
class HuntingScript
def initialize(area)
@settings = InstanceSettings.new("hunting:#{area}")
end
def configure
@settings['enabled'] = true
@settings['monsters'] = ['kobold', 'troll']
end
end
script1 = HuntingScript.new('area1')
script2 = HuntingScript.new('area2')
# Each has independent settings
Persistence
Settings are automatically saved to database when modified. No manual save needed.
Manual Operations
# Force refresh from database (rarely needed)
Settings.load
CharSettings.load
# Legacy save (no-op, kept for compatibility)
Settings.save
Migration from Old Code
If migrating from older Lich versions:
# Old way (still works)
Settings['key'] = 'value'
Settings.save
# New way (save is automatic)
CharSettings['key'] = 'value'
# Already saved to database
# Old hash operations
Settings.to_hash['key'] = 'value'
Settings.save
# New way
CharSettings['key'] = 'value'
# Already saved
Common Patterns
Configuration Management
# Initialize script configuration
CharSettings['script_config'] ||= {
enabled: true,
mode: 'normal',
areas: [],
thresholds: { health: 50, mana: 30 }
}
# Access nested config
config = CharSettings['script_config']
if config['enabled']
hunt_mode = config['mode']
health_threshold = config['thresholds']['health']
end
Counter Tracking
# Initialize counters
CharSettings['kills'] ||= 0
CharSettings['deaths'] ||= 0
CharSettings['logins'] ||= 0
# Increment
CharSettings['kills'] += 1
# Display stats
kills = CharSettings['kills']
deaths = CharSettings['deaths']
ratio = kills.to_f / [deaths, 1].max
echo "K/D ratio: #{ratio.round(2)}"
List Management
# Initialize list
CharSettings['ignored_players'] ||= []
# Add item if not present
player = 'Bob'
unless CharSettings['ignored_players'].include?(player)
CharSettings['ignored_players'] << player
end
# Remove item
CharSettings['ignored_players'].delete(player)
# Check membership
if CharSettings['ignored_players'].include?(player)
echo "#{player} is ignored"
end
Timestamp Tracking
# Track last run time
CharSettings['last_hunting'] = Time.now
# Check time elapsed
last_hunt = CharSettings['last_hunting']
if last_hunt && Time.now - last_hunt < 3600
echo 'Hunted recently, waiting...'
else
echo 'Time to hunt!'
CharSettings['last_hunting'] = Time.now
end
Debugging
# Enable debug logging
Settings.set_log_level(:debug)
# Levels: :none, :error, :info, :debug
Settings.set_log_level(:info)
# Disable logging
Settings.set_log_level(:none)
Scope Details
- CharSettings: Scoped to
"#{XMLData.game}:#{XMLData.name}"
- GameSettings: Scoped to
"#{XMLData.game}:"
- Settings: Uses default scope
":" (typically character-specific)
Best Practices
- Use descriptive keys:
CharSettings['hunting_area'] not CharSettings['ha']
- Initialize with defaults: Use
||= pattern
- Prefer CharSettings/GameSettings: Clearer scope than raw Settings
- Use appropriate scope: Character settings vs game-wide vs account-wide
- Avoid complex objects: Stick to basic types (Hash, Array, String, Number, Boolean)
See Also
- Vars - Simple key-value variable storage
- Script - Script management