Crafting System Architecture for Mobile Games
We design crafting systems from scratch. Typical mistakes: hardcoding recipes, trusting client validation, ignoring offline progression. Over the years, we have implemented crafting for games with over 10 million total installs. Here we share architectural solutions that save up to 40% of integration time.
A crafting system is a mechanic for combining resources to obtain items. In mobile games, it ranges from simple (5 stones → 1 diamond) to complex (chain of 10 recipes with different stations and probabilities). The proper data schema affects performance and anti-cheat protection. For example, in an RPG with 50 recipes and 4 stations, without server validation cheating reaches 90%.
Instead of storing recipes in code, we move them to configs — Remote Config or Addressables. This allows balance changes without updating the app: increase crafting time of a rare sword from 10 to 15 seconds in a few clicks. Server validation reduces cheating risk by 90% for monetized games. The development cost of a crafting system is calculated individually, but budget savings from smart architecture can reach 30%. Below, we break down key components using Unity and PlayFab examples.
Why Store Recipes as Data?
Recipes are conveniently stored as data, not logic. This allows adding recipes without an app update — via Remote Config or Addressables. We use the following structure:
[Serializable]
public class CraftingRecipe
{
public string recipeId;
public string resultItemId;
public int resultQuantity;
public List<Ingredient> ingredients;
public float craftingTime; // seconds, 0 = instant
public float successRate; // 0.0-1.0, 1.0 = always
public string requiredStation; // "forge", "alchemy_table", null = anywhere
public int requiredLevel;
}
[Serializable]
public class Ingredient
{
public string itemId;
public int quantity;
public bool consumed; // false = tool, not consumed
}
| Parameter | Description |
|---|---|
| recipeId | Unique recipe identifier |
| resultItemId | ID of the result item |
| ingredients | List of ingredients with quantity and consumption flag |
| craftingTime | Crafting time in seconds (0 — instant) |
| successRate | Probability of success from 0 to 1 |
The recipe list is loaded at startup from a ScriptableObject or via Addressables.LoadAssetAsync<CraftingDatabase>. For balancing without an update, Remote Config stores JSON with overrides. Example: we increased the sword crafting time from 10 to 15 seconds when balance shifted.
Implementing Ingredient Check and Server Validation
Validation is two-sided: client for UX (instant error), server for anti-cheat. Client logic in CraftingManager:
public class CraftingManager : MonoBehaviour
{
public static CraftingManager Instance { get; private set; }
private CraftingDatabase _database;
private InventoryManager _inventory;
public CraftingResult TryCraft(string recipeId, string stationId = null)
{
var recipe = _database.GetRecipe(recipeId);
if (recipe == null) return CraftingResult.InvalidRecipe;
// Station check
if (!string.IsNullOrEmpty(recipe.requiredStation) && recipe.requiredStation != stationId)
return CraftingResult.WrongStation;
// Level check
if (PlayerData.Level < recipe.requiredLevel)
return CraftingResult.LevelTooLow;
// Check ingredient availability
foreach (var ingredient in recipe.ingredients)
{
if (_inventory.GetCount(ingredient.itemId) < ingredient.quantity)
return CraftingResult.MissingIngredients;
}
// Success probability
bool success = Random.value <= recipe.successRate;
// Deduct only consumable ingredients
foreach (var ingredient in recipe.ingredients.Where(i => i.consumed))
_inventory.Remove(ingredient.itemId, ingredient.quantity);
if (success)
_inventory.Add(recipe.resultItemId, recipe.resultQuantity);
// Analytics
GameAnalytics.NewDesignEvent($"Crafting:Result:{recipeId}", success ? 1 : 0);
return success ? CraftingResult.Success : CraftingResult.Failed;
}
}
For monetized games, server validation via PlayFab Cloud Script is mandatory:
// PlayFab Cloud Script
handlers.CraftItem = function(args) {
var recipeId = args.recipeId;
var recipe = getRecipeFromCatalog(recipeId);
// Check inventory on server
var inventory = server.GetUserInventory({ PlayFabId: currentPlayerId });
for (var ingredient of recipe.ingredients) {
var count = countItem(inventory, ingredient.itemId);
if (count < ingredient.quantity) {
return { success: false, error: "insufficient_items" };
}
}
// Deduct and grant on server
for (var ingredient of recipe.ingredients.filter(i => i.consumed)) {
server.RevokeInventoryItems({ ... });
}
server.GrantItemsToUser({ itemIds: [recipe.resultItemId], ... });
return { success: true, resultItemId: recipe.resultItemId };
};
Server validation prevents cheating: the client can be hacked, the server cannot.
How to Organize Timed Crafting with Offline Progression?
For the "start and come back in an hour" mechanic, we use a slot object:
public class CraftingSlot
{
public string recipeId;
public DateTime completionTime;
public bool isComplete => DateTime.UtcNow >= completionTime;
}
public void StartCrafting(string recipeId, int slotIndex)
{
var recipe = _database.GetRecipe(recipeId);
_craftingSlots[slotIndex] = new CraftingSlot
{
recipeId = recipeId,
completionTime = DateTime.UtcNow.AddSeconds(recipe.craftingTime)
};
// Save to PlayerPrefs or Cloud Save
SaveCraftingState();
// Schedule local push
NotificationManager.ScheduleLocal(
$"Crafting completed: {recipe.resultItemId}",
recipe.craftingTime
);
}
Slot state must be persisted. On login, DateTime.UtcNow is compared to completionTime: if passed, craft is complete. This way the timer works offline.
Types of Crafting
| Craft Type | Description | Complexity | Example |
|---|---|---|---|
| Instant | Ingredients immediately converted to result | Low | 5 stones → 1 diamond |
| Timed | Start crafting, wait for completion | Medium | Brew potion 30 min |
| Probabilistic | Result depends on chance | Medium | Smelt ore with 70% chance |
| Multi-level | Chain of crafts from intermediate items | High | Steel from ore and coal → sword |
The crafting category is chosen based on genre. RPGs suit multi-level and timed, casual games suit instant and probabilistic.
Development Stages for a Crafting System
- Analysis — define mechanics, build prototype.
- Data design — recipes, inventory, slots, server rules.
- Implementation — write CraftingManager, validation, timers, UI.
- Server integration — PlayFab Cloud Script for validation.
- Testing — load, cheating, offline scenarios.
- Deploy — publish while complying with Store Review Guidelines.
Real-life case example
For an RPG with 50 recipes and 4 stations, we implemented a multi-level crafting chain. Used PlayFab for server validation. Crafting times ranged from 10 seconds to 24 hours. Server validation reduced cheating to zero. The project took 2 weeks.What's Included in Crafting System Development
- Designing recipe and inventory data schema.
- Implementing CraftingManager with checks and probabilities.
- Timed crafting system with offline progression.
- Local push notifications for craft completion.
- Server-side validation via PlayFab / GameSparks.
- UI: recipe book, crafting slots, progress bar.
- Analytics events for balancing recipe popularity.
Development Timelines
Basic crafting (instant, no timers): 3–5 days. Full system with timers, slots, server validation, and UI: 1.5–3 weeks. Cost is calculated individually after assessing inventory size and number of recipes. We guarantee stable operation and compliance with Store Review Guidelines.
Our specialists have 10+ years of experience in mobile development — we'll account for code signing and certificate nuances for publishing. We'll assess your project and propose the optimal solution. Request crafting system development and get a robust architecture. Contact us for a consultation.







