Skip to content

Instantly share code, notes, and snippets.

@pythoninthegrass
Last active August 31, 2025 01:10
Show Gist options
  • Save pythoninthegrass/ed0381708cea219784e84c2efc8a5f34 to your computer and use it in GitHub Desktop.
Save pythoninthegrass/ed0381708cea219784e84c2efc8a5f34 to your computer and use it in GitHub Desktop.
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "python-decouple>=3.8",
# ]
# [tool.uv]
# exclude-newer = "2025-07-21T00:00:00Z"
# ///
# pyright: reportMissingImports=false
"""
Clair Obscur: Expedition 33 Engine.ini Configuration Tool
A Python script to create and manage Engine.ini configuration files for
Clair Obscur: Expedition 33 with performance optimization settings.
Based on common UE5 SystemSettings tweaks for improved performance and visual quality.
"""
import argparse
import configparser
import shutil
import sys
from pathlib import Path
from typing import Dict, Any, Optional
class ClairObscurConfig:
"""Manage Engine.ini configurations for Clair Obscur: Expedition 33."""
def __init__(self, config_path: Optional[Path] = None):
"""Initialize with Steam's default config path or custom path."""
if config_path:
self.config_path = Path(config_path)
else:
# Default Steam Proton path
home = Path.home()
self.config_path = (
home / ".var/app/com.valvesoftware.Steam/.local/share/Steam/"
"steamapps/compatdata/1903340/pfx/drive_c/users/steamuser/"
"Local Settings/Application Data/Sandfall/Saved/Config/Windows"
)
self.engine_ini_path = self.config_path / "Engine.ini"
# Ensure config directory exists
self.config_path.mkdir(parents=True, exist_ok=True)
def get_performance_preset(self, preset: str = "balanced") -> Dict[str, Dict[str, Any]]:
"""Get predefined performance presets."""
presets = {
"low": {
"SystemSettings": {
# Basic performance settings
"r.ViewDistanceScale": 0.5,
"r.ShadowQuality": 0,
"r.PostProcessAAQuality": 0,
"r.MotionBlurQuality": 0,
"r.AmbientOcclusionLevels": 0,
"r.SSR.Quality": 0,
"r.RefractionQuality": 0,
"r.MaxAnisotropy": 4,
"r.LightFunctionQuality": 0,
"r.ShadowFilterQualityBias": -2,
"r.BloomQuality": 0,
"r.FastBlurThreshold": 0,
"r.Upscale.Quality": 1,
"r.DefaultFeature.AntiAliasing": 0,
# Lumen settings (low)
"r.Lumen.GlobalIllumination": "False",
"r.Lumen.Reflections": "False",
"r.Lumen.ScreenProbeGather": "False",
# Ray tracing off
"r.RayTracing": "False",
"r.RayTracing.Shadows": "False",
"r.RayTracing.Reflections": "False",
"r.RayTracing.GlobalIllumination": "False",
}
},
"balanced": {
"SystemSettings": {
# Balanced settings for good performance/quality
"r.ViewDistanceScale": 0.85,
"r.ShadowQuality": 2,
"r.PostProcessAAQuality": 2,
"r.MotionBlurQuality": 1,
"r.AmbientOcclusionLevels": 2,
"r.SSR.Quality": 2,
"r.RefractionQuality": 1,
"r.MaxAnisotropy": 8,
"r.LightFunctionQuality": 1,
"r.ShadowFilterQualityBias": 0,
"r.BloomQuality": 2,
"r.FastBlurThreshold": 2,
"r.Upscale.Quality": 2,
"r.DefaultFeature.AntiAliasing": 2,
# Lumen settings (balanced)
"r.Lumen.GlobalIllumination": "True",
"r.Lumen.Reflections": "True",
"r.Lumen.ScreenProbeGather": "True",
"r.Lumen.Reflections.HardwareRayTracing": "False",
# Conservative ray tracing
"r.RayTracing": "False",
"r.RayTracing.Shadows": "False",
"r.RayTracing.Reflections": "False",
"r.RayTracing.GlobalIllumination": "False",
}
},
"ultra": {
"SystemSettings": {
# High-end settings for maximum quality
"r.ViewDistanceScale": 1.5,
"r.ShadowQuality": 4,
"r.PostProcessAAQuality": 4,
"r.MotionBlurQuality": 4,
"r.AmbientOcclusionLevels": 4,
"r.SSR.Quality": 4,
"r.RefractionQuality": 4,
"r.MaxAnisotropy": 16,
"r.LightFunctionQuality": 4,
"r.ShadowFilterQualityBias": 2,
"r.BloomQuality": 4,
"r.FastBlurThreshold": 100,
"r.Upscale.Quality": 4,
"r.DefaultFeature.AntiAliasing": 4,
# Lumen settings (ultra)
"r.Lumen.GlobalIllumination": "True",
"r.Lumen.Reflections": "True",
"r.Lumen.ScreenProbeGather": "True",
"r.Lumen.Reflections.HardwareRayTracing": "True",
# Ray tracing enabled
"r.RayTracing": "True",
"r.RayTracing.Shadows": "True",
"r.RayTracing.Reflections": "True",
"r.RayTracing.GlobalIllumination": "True",
"r.RayTracing.AmbientOcclusion": "True",
}
},
"sharp_clear": {
"SystemSettings": {
# Sharp and clear preset (disable blur/grain effects)
"r.Tonemapper.GrainQuantization": 0,
"r.Tonemapper.Quality": 0,
"r.PostProcessAAQuality": 0,
"r.AntiAliasingMethod": 0,
"r.DefaultFeature.AntiAliasing": 0,
"r.MotionBlurQuality": 0,
"r.DepthOfFieldQuality": 0,
"r.BloomQuality": 0,
"r.LensFlareQuality": 0,
"r.SceneColorFringeQuality": 0,
"r.FilmGrain": 0,
"r.Tonemapper.Sharpen": 1.5,
"r.Upscale.Softness": 0,
}
}
}
return presets.get(preset, presets["balanced"])
def get_engine_tweaks(self) -> Dict[str, Dict[str, Any]]:
"""Additional engine tweaks for better performance."""
return {
"/Script/Engine.Engine": {
"bSmoothFrameRate": "False",
"bUseFixedFrameRate": "False",
"SmoothedFrameRateRange": "(LowerBound=(Type=Inclusive,Value=30.000000),UpperBound=(Type=Exclusive,Value=120.000000))",
"MinDesiredFrameRate": 30,
},
"/Script/Engine.RendererSettings": {
"r.AntiAliasingMethod": 0,
"r.MSAACount": 1,
"r.DefaultFeature.AntiAliasing": 0,
"r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange": "True",
},
"/Script/Engine.NetworkSettings": {
"n.VerifyPeer": "False",
}
}
def backup_existing_config(self) -> Optional[Path]:
"""Create a backup of existing Engine.ini if it exists."""
if self.engine_ini_path.exists():
backup_path = self.engine_ini_path.with_suffix(".ini.backup")
shutil.copy2(self.engine_ini_path, backup_path)
print(f"Backup created: {backup_path}")
return backup_path
return None
def create_engine_ini(self, preset: str = "balanced", include_tweaks: bool = True) -> None:
"""Create Engine.ini with specified preset and tweaks."""
config = configparser.ConfigParser()
config.optionxform = str # Preserve case sensitivity
# Add preset settings
preset_config = self.get_performance_preset(preset)
for section, settings in preset_config.items():
config[section] = {}
for key, value in settings.items():
config[section][key] = str(value)
# Add engine tweaks if requested
if include_tweaks:
tweak_config = self.get_engine_tweaks()
for section, settings in tweak_config.items():
if section not in config:
config[section] = {}
for key, value in settings.items():
config[section][key] = str(value)
# Write config file
with open(self.engine_ini_path, 'w') as f:
config.write(f)
print(f"Engine.ini created: {self.engine_ini_path}")
print(f"Applied preset: {preset}")
def apply_custom_settings(self, custom_settings: Dict[str, Dict[str, Any]]) -> None:
"""Apply custom settings to existing Engine.ini."""
config = configparser.ConfigParser()
config.optionxform = str
# Read existing config if it exists
if self.engine_ini_path.exists():
config.read(self.engine_ini_path)
# Apply custom settings
for section, settings in custom_settings.items():
if section not in config:
config[section] = {}
for key, value in settings.items():
config[section][key] = str(value)
# Write updated config
with open(self.engine_ini_path, 'w') as f:
config.write(f)
print(f"Custom settings applied to: {self.engine_ini_path}")
def set_read_only(self, read_only: bool = True) -> None:
"""Set Engine.ini as read-only to prevent game from overwriting."""
if self.engine_ini_path.exists():
current_stat = self.engine_ini_path.stat()
if read_only:
# Remove write permissions
self.engine_ini_path.chmod(current_stat.st_mode & ~0o200)
print("Engine.ini set to read-only")
else:
# Add write permissions
self.engine_ini_path.chmod(current_stat.st_mode | 0o200)
print("Engine.ini write permissions restored")
def show_current_config(self) -> None:
"""Display current Engine.ini configuration."""
if not self.engine_ini_path.exists():
print("Engine.ini does not exist")
return
config = configparser.ConfigParser()
config.optionxform = str
config.read(self.engine_ini_path)
print(f"Current Engine.ini configuration ({self.engine_ini_path}):")
print("=" * 60)
for section in config.sections():
print(f"\n[{section}]")
for key, value in config[section].items():
print(f"{key}={value}")
def main():
"""Main CLI interface."""
parser = argparse.ArgumentParser(
description="Clair Obscur: Expedition 33 Engine.ini Configuration Tool"
)
parser.add_argument(
"--config-path",
type=Path,
help="Custom path to config directory (default: Steam Proton path)"
)
subparsers = parser.add_subparsers(dest="command", help="Available commands")
# Create command
create_parser = subparsers.add_parser("create", help="Create new Engine.ini")
create_parser.add_argument(
"--preset",
choices=["low", "balanced", "ultra", "sharp_clear"],
default="balanced",
help="Performance preset to apply"
)
create_parser.add_argument(
"--no-tweaks",
action="store_true",
help="Don't include additional engine tweaks"
)
create_parser.add_argument(
"--read-only",
action="store_true",
help="Set Engine.ini as read-only after creation"
)
# Show command
subparsers.add_parser("show", help="Show current Engine.ini configuration")
# Backup command
subparsers.add_parser("backup", help="Create backup of current Engine.ini")
# Custom command
custom_parser = subparsers.add_parser("custom", help="Apply custom settings")
custom_parser.add_argument(
"--section",
required=True,
help="Config section name"
)
custom_parser.add_argument(
"--setting",
action="append",
nargs=2,
metavar=("KEY", "VALUE"),
help="Custom setting key-value pair (can be used multiple times)"
)
# Read-only command
readonly_parser = subparsers.add_parser("readonly", help="Set read-only status")
readonly_parser.add_argument(
"status",
choices=["on", "off"],
help="Enable or disable read-only mode"
)
args = parser.parse_args()
if not args.command:
parser.print_help()
return
# Initialize config manager
config_manager = ClairObscurConfig(args.config_path)
try:
if args.command == "create":
config_manager.backup_existing_config()
config_manager.create_engine_ini(
preset=args.preset,
include_tweaks=not args.no_tweaks
)
if args.read_only:
config_manager.set_read_only(True)
elif args.command == "show":
config_manager.show_current_config()
elif args.command == "backup":
backup_path = config_manager.backup_existing_config()
if not backup_path:
print("No Engine.ini found to backup")
elif args.command == "custom":
if not args.setting:
print("Error: --setting is required for custom command")
return
custom_settings = {args.section: dict(args.setting)}
config_manager.apply_custom_settings(custom_settings)
elif args.command == "readonly":
config_manager.set_read_only(args.status == "on")
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
@pythoninthegrass
Copy link
Author

git clone [email protected]:ed0381708cea219784e84c2efc8a5f34.git clair_config && cd $_
./clair_config.py -h

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment