Features of the Save System in the Undertale Changer Template
TLDR: The Undertale Changer Template provides a complete slot-based save system with JSON serialization, automatic fact-table persistence, sequential slot management, and an integrated in-game UI with pause functionality.
The Undertale Changer Template ships with a production-ready save architecture designed for Unity-based Undertale-style games. According to the source code in arch-aik/undertale-changer-template, the system handles player data persistence, narrative state tracking, and user preferences through a centralized JSON-based workflow. Understanding these features allows developers to customize save behaviors without rebuilding core infrastructure.
JSON-Based Player Data Persistence
At the core of the Undertale Changer Template save system is the SaveController.SaveData method in Assets/Scripts/UCT/Core/SaveController.cs. This method serializes the PlayerControl ScriptableObject to JSON using Newtonsoft.Json and writes it to Application.dataPath/Data/*.json.
The implementation automatically creates the Data folder if missing and generates files following the Data{n}.json naming convention. This ensures that player progress, inventory, and positional data persist between sessions using human-readable JSON files rather than binary formats.
Automatic Fact-Table Serialization
Beyond player stats, the system preserves narrative state through FactTable assets. The SaveFactTablesToJson method scans the Resources/Tables directory and serializes all table assets to a companion file named <saveName>Table.json.
This feature stores the path-to-fact mapping alongside player data, ensuring that story flags, dialogue states, and progression markers synchronize with the specific save slot. When loading, LoadFactTablesFromJson reconstructs these tables to restore the exact narrative context.
Sequential Slot Management and Auto-Renaming
The template enforces clean slot organization through the SortAndRenameData method. When players delete saves or create new ones, the system automatically reorders files to eliminate gaps, ensuring sequential naming from Data0.json upward.
This SortAndRenameData implementation (lines 92-134) handles both player data files and their corresponding table companions simultaneously. The GetDataNumber method provides a quick count of existing slots by scanning for Data*.json patterns, enabling dynamic UI generation for save/load screens.
Loading, Deletion, and Data Recovery
Loading operations deserialize JSON back into fresh PlayerControl instances via SaveController.LoadData. This method reads the specified slot file, populates a new ScriptableObject, caches it for performance, and triggers fact-table restoration.
For deletion, DeleteData removes the specified slot file and its cached entry before invoking the renaming pass to close sequence gaps. This ensures that the slot inventory remains compact and predictable after save removal operations.
In-Game Save UI and Pause Integration
The SaveBoxController class in Assets/Scripts/UCT/Overworld/SaveBoxController.cs provides the visual interface and input handling layer. When activated via OpenSaveBox, the system pauses the game by disabling player movement and setting a global pause flag through SetGamePaused.
Input handling supports left/right arrow keys to toggle between Confirm and Cancel options, while Z confirms selections and X cancels. The HandleSelectionInput, HandleConfirmationInput, and HandleCancellationInput methods manage these interactions, providing immediate visual feedback through the UI elements.
PlayerPrefs Integration for Settings
The save system extends beyond game state to include user preferences. The SaveService.SavePlayerPreferences method persists language settings, resolution, last used slot, SFX, and V-Sync configurations to PlayerPrefs. This ensures that display and audio preferences persist independently of individual save slots, maintaining consistency across playthroughs.
How to Use the Save System
Developers interact with the Undertale Changer Template save system through straightforward API calls that wrap the underlying complexity.
Saving the Game
To trigger a complete save operation including player data, scene information, and preferences:
// Centralized save call that handles all persistence layers
SaveService.SaveGame();
This method, located in SaveBoxController.cs, coordinates SaveController.SaveData, scene metadata capture, and preference persistence in a single atomic operation.
Loading a Specific Slot
To load existing save data programmatically:
// Load slot 2 (corresponds to Data2.json)
PlayerControl loadedPlayer = SaveController.LoadData("Data2");
if (loadedPlayer != null)
{
// Apply loaded data to current game state
}
The LoadData method returns a populated PlayerControl instance ready for injection into the active game scene.
Deleting Save Data
To remove a specific slot and maintain sequential ordering:
// Delete slot 3 and auto-rename remaining files
SaveController.DeleteData("Data3");
This operation removes both the player data file and its associated fact-table companion before triggering the automatic renaming pass.
Querying Available Slots
To determine how many save slots exist for UI generation:
int slotCount = SaveController.GetDataNumber();
// Returns 4 if Data0.json through Data3.json exist
This scan-based approach allows dynamic save menu construction that reflects the current Data folder contents.
Summary
- The Undertale Changer Template provides JSON-based serialization for
PlayerControldata viaSaveController.SaveDatainAssets/Scripts/UCT/Core/SaveController.cs. - Fact-table persistence automatically synchronizes narrative state files alongside player saves using companion JSON files.
- Auto-renaming logic maintains sequential slot ordering without gaps through
SortAndRenameData, called automatically during save and delete operations. - The in-game UI layer in
SaveBoxController.cshandles input routing, game pausing, and visual feedback with dedicated methods for confirmation and cancellation. - Player preferences persist separately via
PlayerPrefsthrough theSaveServiceintegration, storing settings like language and resolution independently of game saves.
Frequently Asked Questions
How does the Undertale Changer Template handle save file organization?
The template maintains sequential slot naming (Data0.json, Data1.json, etc.) through the SortAndRenameData method. When saves are deleted, the system automatically renames remaining files to eliminate gaps, ensuring that GetDataNumber always returns a continuous count. Player data and fact-table companions are renamed in tandem to maintain data integrity.
What data is included when saving in the Undertale Changer Template?
Each save captures the complete PlayerControl object (position, inventory, stats) as JSON, plus all FactTable assets from Resources/Tables. Additionally, SaveService.SavePlayerPreferences stores language, resolution, audio, and V-Sync settings to PlayerPrefs. Scene metadata including current level and player position is also recorded.
Can I modify the save UI behavior in the Undertale Changer Template?
Yes. The SaveBoxController class in Assets/Scripts/UCT/Overworld/SaveBoxController.cs exposes methods like OpenSaveBox, SetGamePaused, and UpdateAfterSaveUI for customization. Input handling logic resides in HandleSelectionInput and related methods, allowing developers to remap keys or change the confirmation flow. The UI prefab elements (saveHeart, saveText) can be configured via the BackpackBehaviour prefab reference.
Where are save files stored in the Undertale Changer Template?
Save files are written to Application.dataPath/Data/ as individual JSON files following the Data{n}.json pattern, with companion files Data{n}Table.json for fact tables. This places saves in the application's data directory, which varies by platform but ensures accessibility for debugging and backup purposes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →