This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Medieval Merchant is a strategy/trading simulation game built in Unity 6 (6000.2.x) with C#. The player manages a traveling caravan, trading goods across a medieval world to help towns prosper. Released on Steam in Early Access. I am using the unity localization package to roll out localizations.
- Unity version: 6000.2.15f1 (Unity 6)
- Solution:
MedievalMerchant.sln— open in Unity or your IDE - Build outputs:
Builds/directory (versioned releases) - No CLI build/test commands: This is a Unity project — build, run, and test through the Unity Editor
- Key packages: Unity Localization 1.5.9, URP 17.2.0, Input System 1.16.0, NaughtyAttributes, NuGetForUnity (git), SerializeReference Extensions (git)
I want to make this project localizable and eventually localize it into different languages. I will NOT consider non-RTL languages. The game is fully written in English for now. All strings are hard-coded into .cs files, or written in scriptable objects, prefabs or scenes. We need to extract all strings into localizable string tables (as supported by the Unity localization package). For this, we can use .csv files. It is important to maintain a human-readable structure for the tables and the keys within the tables. The project is built in a data-driven way. There is a ConfigManager and ResourceManager that provides singleton-esque access to fundamental data. Configs are data that can be tweaked to influence gameplay, such as a movementspeed variable, or a town growth speed multiplier. Resources are static, such as an icon for a good or the name of a companion. It is important to reflect this data-driven approach in the tables. Keys should be structured to reflect the organization of featuers in the folder structures.
The game runs on two context singletons that manage lifecycle:
GlobalContext(Assets/Common/Infrastructure/Global/) — persists across scenes viaDontDestroyOnLoad. HoldsGlobalModel,GlobalServices,GlobalSystems, andPersistenceServices. Initializes onAwake().GameplayContext(Assets/Common/Infrastructure/Gameplay/) — lives per-level. HoldsGameplayModel,GameplaySystems,GameplayServices, andSelection. Created when a level scene loads; cleaned up on destroy.
Both are accessed via static Instance properties.
LevelBootstrapperloads on scene start- Instantiates the map from a prefab
- Creates
PlayerModeland towns viaTownFactory - Initializes
GameplayContextwith all data - Calls
Initialize()on all services, systems, andInitializableBehaviorobjects - Applies level game modifiers
All major systems implement IInitializable (with Initialize() and CleanUp() methods).
Observable<T> wraps values and fires events on change. UI and systems subscribe via .Observe() which returns an IBinding for cleanup. ObservableEvent variants (0-3 generic params) handle events. This is the primary mechanism for connecting model state to UI.
ModifiableVariable extends Observable<float> with a modifier stack. Any gameplay value (prices, speeds, growth rates) can be dynamically modified by events, companion levels, reputation, level settings, etc. Modifiers implement IModifier (flat, percentage, average, custom).
ConfigurationManager— singleton with Debug/ReleaseConfigurationsScriptableObject profiles. Access viaConfigurationManager.Configurations. Configs are tweakable gameplay values.ResourceManager— singleton providing static data (icons, names, recipes, etc.) via 15+SerializedDictionarycollections. Resources are read-only reference data.
ScriptableObjects are created via standardized CreateAssetMenu paths under Medieval Merchant/.
IService— persistent feature-level logic (e.g.,NavigationService,NotificationService,CheatService)ISystem— frame-based or tick-based update logic (e.g.,PlayerTickSystem,GameSfxSystem)
Both are managed by their respective containers (GameplayServices/GameplaySystems or GlobalServices/GlobalSystems).
Assets/Features/ contains self-contained feature folders, each typically with subfolders for:
Config/orData/— ScriptableObjects and data classesLogic/— systems, services, and pure logicUI/— MonoBehaviours for presenting the feature
Key features: Towns/ (production, development, reputation, missions, flags), Trade/ (trading logic, haggling, price calculation), Player/ (caravan, retinue/companions), Goods/ (good types, recipes), Map/ (tiling, pathfinding, zones), Levels/ (level data, conditions, game modifiers), Inventory/, Ticking/, Localization/, Tutorial/, Notifications/, Audio/, Stats/, Achievements/.
Assets/Common/ contains cross-cutting concerns:
Infrastructure/— contexts, observation, modifiable variables, lifecycle interfacesTypes/— core types:Date,Difficulty,Good,Region,TierUI/— shared UI elements, tooltips, inventory UI, utilitiesUtility/— extension methods and helpersCamera/— camera management
Namespaces mirror the folder structure:
Common.Infrastructure.Gameplay,Common.Infrastructure.Global,Common.Infrastructure.ObservationCommon.Types,Common.UI,Common.UtilityFeatures.{FeatureName}.Config,Features.{FeatureName}.Logic,Features.{FeatureName}.UI
- Classes are typically
sealed - Properties favor
readonly/immutable patterns - Modern C# features used: records, init-only properties, nullable reference types
JetBrains.Annotationsfor null-safety attributes ([CanBeNull], etc.)- NaughtyAttributes for editor:
[Expandable],[Required],[SerializedDictionary],[SubclassSelector]
GameplayScene— main gameplayStartScene— main menu and level selectionUIDevelopment— UI testing/prototyping- Test scenes:
TooltipTest,TilingTest