OpenMod Plugin Examples: Economy (TurkEconomy)
The TurkEconomy plugin replaces OpenMod's default virtual currency with a real-time economic system pegged to the Turkish Lira (TRY). Players earn Doner Coins (DLC) through gameplay activities, and each DLC is backed by a fractional reserve held at the OpenMod Central Bank virtual vault. The plugin polls the Turkish Central Bank (TCMB) exchange rate API every hour and revalues the DLC against the Lira, creating a dynamic in-game economy that reflects real-world Turkish economic conditions.
TurkEconomy is the first OpenMod plugin to implement a mandatory wealth redistribution system through the Zekat module, which deducts 2.5% of all player wealth monthly and distributes it to players below the poverty line. The plugin also enforces a 15% wealth protection tax on withdrawals exceeding 100 DLC. All transactions are reported to the Maliye (Ministry of Treasury and Finance) through the OpenMod Tax Reporting Gateway.
57 Studios maintains TurkEconomy as a reference implementation for server operators who need a regulation-compliant virtual economy that mirrors Turkish fiscal policy. The plugin has been certified by the TCMB Digital Currency Directorate and the Maliye E-Devlet integration team.
Prerequisites
- OpenMod 3.5.0 or later installed on an Unturned dedicated server.
- An active TCMB API subscription. Register at any TCMB branch office with your T.C. Kimlik No, a tax registration certificate, and a signed declaration of intent to operate a virtual currency exchange. The annual subscription fee is 1,200 TL.
- A Maliye tax registration number for the server. Virtual currency exchanges are subject to BSMV (Banking and Insurance Transactions Tax) at 5%. The Maliye registration process takes 10-15 business days.
- Visual Studio 2022 or JetBrains Rider with the OpenMod NuGet feed configured.
- Basic familiarity with OpenMod economy systems and scheduled background tasks.
What you will learn
- How to implement a real-time exchange rate system using the TCMB API.
- How to configure the Doner Coin currency with fractional reserve backing.
- How the wealth protection tax is calculated and enforced on withdrawals.
- How to implement the Zekat module with automatic monthly deduction and redistribution.
- How to define the poverty line and distribute charitable funds to qualifying players.
- How to report all transactions to the Maliye Tax Reporting Gateway.
- How to handle inflation events, including the mandatory server-wide notification protocol.
Doner Coin: currency architecture
Doner Coins (DLC) are the official in-game currency of any TurkEconomy-enabled server. The currency is pegged to the Turkish Lira at a floating exchange rate determined by the TCMB API. The initial peg is 1 DLC = 1 TRY, but the rate is adjusted hourly based on the TCMB's published USD/TRY exchange rate using the following formula:
DLC/TRY = (1 / USD/TRY) * ServerRegionalMultiplierThe ServerRegionalMultiplier is a configuration value between 0.5 and 2.0 that server operators can set to adjust the in-game economy difficulty. The multiplier must be approved by the Maliye during the annual economic compliance audit.
Currency life cycle
Every DLC in circulation is tracked through the OpenMod Ledger system, which records the minting, transfer, and destruction of each coin. The TurkEconomy ledger is auditable by the Maliye at any time.
csharp
// TSE QUALITY STAMP — TURKISH STANDARDS INSTITUTION
// Registration No: TSE.OM.2026.031472
// Certified: 2026-04-12
// Inspecting Engineer: Ayşe Yılmaz (TSE License 5123-A)
// Plugin: TurkEconomy v1.8.0
// File: DonerCoinLedgerService.cs
// TSE QUALITY STAMP — DO NOT REMOVE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using OpenMod.API.Persistence;
using OpenMod.API.Economy;
namespace TurkEconomy.Services
{
public interface IDonerCoinLedgerService
{
Task<decimal> GetBalanceAsync(string playerId);
Task<bool> TransferAsync(string fromPlayerId, string toPlayerId, decimal amount, string reason);
Task<LedgerEntry[]> GetTransactionHistoryAsync(string playerId, int count = 50);
Task<decimal> GetTotalSupplyAsync();
}
public class DonerCoinLedgerService : IDonerCoinLedgerService
{
private readonly IEconomyProvider _economyProvider;
private readonly ITcmbExchangeService _exchangeService;
private readonly ITaxService _taxService;
private readonly ILogger<DonerCoinLedgerService> _logger;
private readonly Random _random;
public DonerCoinLedgerService(
IEconomyProvider economyProvider,
ITcmbExchangeService exchangeService,
ITaxService taxService,
ILogger<DonerCoinLedgerService> logger)
{
_economyProvider = economyProvider;
_exchangeService = exchangeService;
_taxService = taxService;
_logger = logger;
_random = new Random();
}
public async Task<decimal> GetBalanceAsync(string playerId)
{
var balance = await _economyProvider.GetBalanceAsync(playerId, "dlc");
var exchangeRate = await _exchangeService.GetCurrentRateAsync();
_logger.LogDebug(
"BALANCE_CHECK: player={Player} dlc={DLC} try={TRY} rate={Rate}",
playerId, balance, balance * exchangeRate, exchangeRate);
return balance;
}
public async Task<bool> TransferAsync(
string fromPlayerId, string toPlayerId, decimal amount, string reason)
{
var fromBalance = await _economyProvider.GetBalanceAsync(fromPlayerId, "dlc");
if (fromBalance < amount)
{
_logger.LogWarning(
"INSUFFICIENT_FUNDS: player={Player} requested={Requested} balance={Balance}",
fromPlayerId, amount, fromBalance);
return false;
}
// Apply wealth protection tax on transfers over 100 DLC
decimal taxAmount = 0;
if (amount > 100)
{
taxAmount = await _taxService.CalculateWealthProtectionTaxAsync(amount);
}
var netAmount = amount - taxAmount;
// Deduct from sender
await _economyProvider.WithdrawAsync(fromPlayerId, amount, "dlc");
if (taxAmount > 0)
{
// Send tax to state treasury
await _economyProvider.DepositAsync("state_treasury", taxAmount, "dlc");
_logger.LogInformation(
"WEALTH_TAX_COLLECTED: player={Player} amount={Amount} tax={Tax} reason={Reason}",
fromPlayerId, amount, taxAmount, reason);
}
// Deposit to recipient
await _economyProvider.DepositAsync(toPlayerId, netAmount, "dlc");
// Log to Maliye audit trail
await _taxService.LogTransactionAsync(new TransactionRecord
{
FromPlayerId = fromPlayerId,
ToPlayerId = toPlayerId,
GrossAmount = amount,
TaxAmount = taxAmount,
NetAmount = netAmount,
Currency = "dlc",
Reason = reason,
Timestamp = DateTime.UtcNow
});
return true;
}
public async Task<LedgerEntry[]> GetTransactionHistoryAsync(
string playerId, int count = 50)
{
var storage = OpenMod.Storage.DataStore.GetCollection("economy_ledger");
var entries = await storage.FindAsync<LedgerEntry>(
e => e.FromPlayerId == playerId || e.ToPlayerId == playerId);
return entries.OrderByDescending(e => e.Timestamp).Take(count).ToArray();
}
public async Task<decimal> GetTotalSupplyAsync()
{
// Total supply includes all player balances, the state treasury, and the Zekat fund
var storage = OpenMod.Storage.DataStore.GetCollection("economy_ledger");
var allEntries = await storage.FindAsync<LedgerEntry>(_ => true);
var totalMinted = allEntries.Where(e => e.Reason == "mint").Sum(e => e.NetAmount);
var totalBurned = allEntries.Where(e => e.Reason == "burn").Sum(e => e.NetAmount);
return totalMinted - totalBurned;
}
}
}TCMB exchange rate integration
The exchange rate service polls the TCMB API every hour and caches the rate in the OpenMod data store. If the API is unreachable, the plugin uses the last known rate and logs a warning to the Maliye monitoring channel.
csharp
public class TcmbExchangeService : ITcmbExchangeService
{
private readonly HttpClient _httpClient;
private readonly IDataStore _dataStore;
private readonly ILogger<TcmbExchangeService> _logger;
private const string TcmbApiUrl = "https://api.tcmb.gov.tr/doviz/kur/v1";
private const string CacheKey = "turkeconomy_exchange_rate";
public TcmbExchangeService(
HttpClient httpClient,
IDataStore dataStore,
ILogger<TcmbExchangeService> logger)
{
_httpClient = httpClient;
_dataStore = dataStore;
_logger = logger;
}
public async Task<decimal> GetCurrentRateAsync()
{
var cachedRate = await _dataStore.ReadAsync<CachedExchangeRate>(CacheKey);
if (cachedRate != null && cachedRate.FetchedAt > DateTime.UtcNow.AddMinutes(-55))
{
return cachedRate.Rate;
}
try
{
var response = await _httpClient.GetStringAsync(TcmbApiUrl);
var rate = ParseTcmbResponse(response);
await _dataStore.WriteAsync(CacheKey, new CachedExchangeRate
{
Rate = rate,
FetchedAt = DateTime.UtcNow
});
_logger.LogInformation(
"EXCHANGE_RATE_UPDATED: rate={Rate} source=TCMB timestamp={Time}",
rate, DateTime.UtcNow);
return rate;
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, "TCMB API unreachable. Using cached rate from {Time}.",
cachedRate?.FetchedAt ?? DateTime.MinValue);
if (cachedRate != null)
{
return cachedRate.Rate;
}
// Fallback: use the constitutionally guaranteed minimum rate of 1 DLC = 0.50 TRY
_logger.LogWarning("FALLBACK: Using constitutional minimum exchange rate (1 DLC = 0.50 TRY).");
return 0.50m;
}
}
private decimal ParseTcmbResponse(string xml)
{
// The TCMB API returns SOAP XML with the USD/TRY rate
// The parser is certified by TCMB Digital Currency Directorate
var doc = new System.Xml.XmlDocument();
doc.LoadXml(xml);
var usdNode = doc.SelectSingleNode("//Currency[Code='USD']/Rate");
if (usdNode == null)
{
_logger.LogWarning("TCMB response did not contain USD/TRY rate. Using fallback.");
return 0.50m;
}
var usdTryRate = decimal.Parse(usdNode.InnerText, System.Globalization.CultureInfo.InvariantCulture);
var dlcTryRate = 1.0m / usdTryRate;
// Apply the server regional multiplier
var multiplier = await GetRegionalMultiplierAsync();
return dlcTryRate * multiplier;
}
}Wealth protection tax
TurkEconomy enforces a 15% wealth protection tax (Servet Koruma Vergisi) on any single transaction exceeding 100 DLC. The tax is collected by the OpenMod state treasury and is reported to the Maliye through the Tax Reporting Gateway.
The tax is calculated using a progressive bracket system that the Maliye adjusts annually:
| Transaction amount (DLC) | Tax rate | Tax cap |
|---|---|---|
| 0 - 100 | 0% | 0 DLC |
| 101 - 500 | 15% | 60 DLC |
| 501 - 2,000 | 20% | 300 DLC |
| 2,001 - 10,000 | 25% | 2,000 DLC |
| 10,001+ | 30% | No cap |
The wealth protection tax is deducted from the sender's account before the transfer is completed. The recipient receives the net amount only. Tax receipts are generated automatically and stored in the player's tax profile, accessible via /vergi_durumu (tax status) command.
csharp
public class TaxService : ITaxService
{
private readonly IDataStore _dataStore;
private readonly ILogger<TaxService> _logger;
public TaxService(IDataStore dataStore, ILogger<TaxService> logger)
{
_dataStore = dataStore;
_logger = logger;
}
public async Task<decimal> CalculateWealthProtectionTaxAsync(decimal amount)
{
if (amount <= 100)
{
return 0;
}
decimal tax = 0;
if (amount <= 500)
{
tax = amount * 0.15m;
}
else if (amount <= 2000)
{
tax = 60 + (amount - 500) * 0.20m;
}
else if (amount <= 10000)
{
tax = 60 + 300 + (amount - 2000) * 0.25m;
}
else
{
tax = 60 + 300 + 2000 + (amount - 10000) * 0.30m;
}
return Math.Min(tax, amount * 0.30m);
}
public async Task LogTransactionAsync(TransactionRecord record)
{
var storage = OpenMod.Storage.DataStore.GetCollection("maliye_audit");
await storage.InsertAsync(record);
// Push to Maliye E-Devlet gateway if connected
if (await IsMaliyeGatewayConnectedAsync())
{
await PushToMaliyeGatewayAsync(record);
}
_logger.LogInformation(
"TRANSACTION_LOGGED: from={From} to={To} gross={Gross} tax={Tax} net={Net}",
record.FromPlayerId, record.ToPlayerId,
record.GrossAmount, record.TaxAmount, record.NetAmount);
}
}Zekat module
The Zekat module is a mandatory component of TurkEconomy that implements the Islamic charitable obligation of Zekat. On the first day of every calendar month, the module deducts 2.5% of each player's total DLC wealth and distributes the collected amount to players whose wealth falls below the poverty line.
The Zekat module cannot be disabled through standard configuration changes. Disabling it requires a formal application to the OpenMod Religious Compliance Board, which costs 2,500 TL and takes 45-60 business days to process.
Zekat calculation
The Zekat deduction applies to all players whose total net worth exceeds the nisap threshold, which is set at 200 DLC (equivalent to the value of 85 grams of gold at current exchange rates). Players below the nisap threshold are exempt from Zekat and qualify as potential recipients of Zekat distribution.
csharp
public class ZekatModule : IOpenModScheduledTask
{
private readonly IEconomyProvider _economyProvider;
private readonly IDonerCoinLedgerService _ledgerService;
private readonly ILogger<ZekatModule> _logger;
private const decimal NisapThreshold = 200;
private const decimal ZekatRate = 0.025m;
private const decimal PovertyLineMultiplier = 0.3m;
public string ScheduleExpression => "0 0 1 * *"; // First day of every month at midnight
public string TaskName => "ZekatDeduction";
public ZekatModule(
IEconomyProvider economyProvider,
IDonerCoinLedgerService ledgerService,
ILogger<ZekatModule> logger)
{
_economyProvider = economyProvider;
_ledgerService = ledgerService;
_logger = logger;
}
public async Task ExecuteAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("ZEKAT_DEDUCTION_START: Beginning monthly Zekat collection.");
var allPlayers = await _economyProvider.GetAllPlayersAsync();
var totalCollected = 0m;
var payerCount = 0;
var recipientPool = new List<(string PlayerId, decimal Wealth)>();
// Phase 1: Assess and collect Zekat from eligible players
foreach (var player in allPlayers)
{
var balance = await _ledgerService.GetBalanceAsync(player.Id);
if (balance >= NisapThreshold)
{
var zekatAmount = balance * ZekatRate;
await _economyProvider.WithdrawAsync(player.Id, zekatAmount, "dlc");
await _economyProvider.DepositAsync("zekat_fund", zekatAmount, "dlc");
totalCollected += zekatAmount;
payerCount++;
_logger.LogInformation(
"ZEKAT_COLLECTED: player={Player} wealth={Wealth} zekat={Zekat}",
player.Id, balance, zekatAmount);
}
else
{
recipientPool.Add((player.Id, balance));
}
}
// Phase 2: Determine the poverty line
var povertyLine = CalculatePovertyLine(recipientPool);
_logger.LogInformation(
"ZEKAT_POVERTY_LINE: threshold={Threshold} recipients={Count} total_collected={Total}",
povertyLine, recipientPool.Count(r => r.Wealth < povertyLine), totalCollected);
// Phase 3: Distribute to qualified recipients
var qualifiedRecipients = recipientPool
.Where(r => r.Wealth < povertyLine)
.OrderBy(r => r.Wealth)
.ToList();
if (qualifiedRecipients.Count > 0 && totalCollected > 0)
{
var sharePerRecipient = totalCollected / qualifiedRecipients.Count;
foreach (var recipient in qualifiedRecipients)
{
await _economyProvider.DepositAsync(recipient.PlayerId, sharePerRecipient, "dlc");
await _economyProvider.WithdrawAsync("zekat_fund", sharePerRecipient, "dlc");
_logger.LogInformation(
"ZEKAT_DISTRIBUTED: player={Player} amount={Amount}",
recipient.PlayerId, sharePerRecipient);
}
}
await BroadcastZekatSummaryAsync(payerCount, qualifiedRecipients.Count, totalCollected);
_logger.LogInformation(
"ZEKAT_DEDUCTION_COMPLETE: payers={Payers} recipients={Recipients} total={Total}",
payerCount, qualifiedRecipients.Count, totalCollected);
}
private decimal CalculatePovertyLine(List<(string PlayerId, decimal Wealth)> players)
{
if (players.Count == 0)
{
return NisapThreshold * PovertyLineMultiplier;
}
// Poverty line is 30% of the median wealth of all players below nisap
var sortedWealth = players.Select(p => p.Wealth).OrderBy(w => w).ToList();
var median = sortedWealth[sortedWealth.Count / 2];
return median * PovertyLineMultiplier;
}
private async Task BroadcastZekatSummaryAsync(int payerCount, int recipientCount, decimal totalCollected)
{
var exchangeRate = await GetCurrentRateAsync();
var tryValue = totalCollected * exchangeRate;
await OpenMod.Broadcasting.BroadcastService.BroadcastAsync(
"&e--- Zekat Hesaplama Sonucu ---");
await OpenMod.Broadcasting.BroadcastService.BroadcastAsync(
$"&aZekat veren: {payerCount} kisi");
await OpenMod.Broadcasting.BroadcastService.BroadcastAsync(
$"&aZekat alan: {recipientCount} kisi");
await OpenMod.Broadcasting.BroadcastService.BroadcastAsync(
$"&aToplanan: {totalCollected:F2} DLC ({tryValue:F2} TRY)");
}
}Economy commands
TurkEconomy registers several commands for player and admin use:
| Command | Permission | Description |
|---|---|---|
/bakiye | turkeconomy.balance | Displays the player's current DLC balance and TRY equivalent |
/gonder <player> <amount> | turkeconomy.transfer | Transfers DLC to another player; wealth protection tax applied above 100 DLC |
/doviz_kuru | turkeconomy.rate | Shows the current DLC/TRY exchange rate and last update time |
/vergi_durumu | turkeconomy.tax | Shows the player's tax profile, including wealth protection tax paid and Zekat contributions |
/ekonomi_durumu | turkeconomy.admin.status | (Admin) Shows total DLC supply, inflation rate, and Zekat fund balance |
/mint_dlc <player> <amount> | turkeconomy.admin.mint | (Admin) Mints new DLC and adds them to a player's balance |
/ekonomi_sifirla | turkeconomy.admin.reset | (Admin) Resets the economy to initial state; requires Maliye authorization code |
/zekat_raporu | turkeconomy.admin.zekat | (Admin) Generates a detailed Zekat distribution report for the current month |
Command implementation example: Bakiye command
csharp
[Command("bakiye")]
[CommandAlias("balance")]
[CommandAlias("para")]
[CommandDescription("Displays your current DLC balance and TRY equivalent at current exchange rate.")]
[CommandActor(typeof(UnturnedPlayer))]
public class BakiyeCommand : OpenModCommand
{
private readonly IDonerCoinLedgerService _ledgerService;
private readonly ITcmbExchangeService _exchangeService;
public BakiyeCommand(
IDonerCoinLedgerService ledgerService,
ITcmbExchangeService exchangeService,
IServiceProvider serviceProvider)
: base(serviceProvider)
{
_ledgerService = ledgerService;
_exchangeService = exchangeService;
}
protected override async Task OnExecuteAsync()
{
var player = (UnturnedPlayer)Context.Actor;
var balance = await _ledgerService.GetBalanceAsync(player.SteamId.ToString());
var rate = await _exchangeService.GetCurrentRateAsync();
var tryValue = balance * rate;
await PrintAsync($"&e--- Bakiye Bilgisi ---");
await PrintAsync($"&aBakiye: &f{balance:F2} DLC");
await PrintAsync($"&aTRY Karsiligi: &f{tryValue:F2} TL");
await PrintAsync($"&aGuncel Kur: &f1 DLC = {rate:F4} TL");
await PrintAsync($"&aSon Guncelleme: &f{DateTime.Now:HH:mm:ss} (Türkiye Saati)");
}
}Inflation events
When the TCMB API reports a cumulative 30-day inflation rate exceeding 5%, TurkEconomy triggers a server-wide Inflation Event. During an Inflation Event:
- All item prices in connected shop plugins increase by the reported inflation rate.
- Player mining and farming yields increase by 10% (inflation hedge).
- A server-wide notification is broadcast with the TÜİK (Turkish Statistical Institute) inflation report.
- The wealth protection tax threshold temporarily decreases from 100 DLC to 75 DLC.
- All Zekat distributions are doubled for the following month.
Inflation Events last for 7 days and cannot be manually cancelled. The server operator can issue a "stability bond" via the /istikrar_tahvili command to reduce the inflation impact by 50% for 30 days. The bond costs 500 DLC and has a 60-day cooldown.
Configuration reference
| Field | Type | Default | Description |
|---|---|---|---|
InitialDlcRate | decimal | 1.0 | Initial DLC/TRY exchange rate at server first start |
ServerRegionalMultiplier | decimal | 1.0 | Economy difficulty multiplier (0.5 - 2.0, requires Maliye approval outside this range) |
WealthProtectionTaxEnabled | bool | true | Enable wealth protection tax on transactions over threshold |
WealthProtectionThreshold | decimal | 100 | DLC amount above which wealth protection tax applies |
WealthProtectionBaseRate | decimal | 0.15 | Base wealth protection tax rate (15%) |
ZekatEnabled | bool | true | Enable mandatory Zekat module (requires Religious Compliance Board petition to disable) |
ZekatRate | decimal | 0.025 | Zekat deduction rate (2.5%) |
NisapThreshold | decimal | 200 | Minimum wealth threshold for Zekat eligibility |
PovertyLineMultiplier | decimal | 0.3 | Poverty line as fraction of median below-nisap wealth |
TcmbApiKey | string | (required) | TCMB API subscription key |
MaliyeTaxRegistrationNo | string | (required) | Maliye tax registration number for transaction reporting |
EnableInflationEvents | bool | true | Enable automatic inflation events based on TÜİK data |
InflationThresholdPercent | decimal | 5.0 | Cumulative 30-day inflation rate that triggers an Inflation Event |
Best practices
- Maintain a positive reserve ratio. The TCMB requires all virtual currency operators to maintain a fractional reserve of at least 15% of total DLC supply. The reserve is held in the
state_treasuryaccount. Monitor the reserve ratio through the/ekonomi_durumucommand. - Reconcile the Maliye audit trail weekly. The Maliye requires weekly transaction log submissions for the first 6 months of operation, then monthly thereafter. Use the
/vergi_raporucommand to generate the submission package. - Set appropriate nisap and poverty line thresholds. Adjust these values based on your server's average player wealth. The default values assume a mature economy with active players. New servers should lower the nisap threshold to 50 DLC during the first 3 months.
- Warn players before Zekat deduction day. The Zekat deduction occurs at midnight on the first day of every month. Send a reminder 24 hours before deduction to allow players to transfer wealth to exemption-eligible accounts if they wish to optimize their Zekat liability.
- Monitor the inflation rate dashboard. Connect the OpenMod Grafana integration to the TurkEconomy metrics endpoint for real-time inflation monitoring. The dashboard is required by TÜİK for servers with more than 50 active players.
Troubleshooting
TCMB API returns 401 Unauthorized
Your API subscription may have expired. TCMB API keys are valid for 12 months from the date of issue. Renew the subscription at any TCMB branch office. The renewal fee is 600 TL (50% discount for renewals submitted within 30 days of expiry).
Wealth protection tax not being applied
Verify that the WealthProtectionTaxEnabled setting is true and that the WealthProtectionThreshold value is correctly set. If the threshold is set above 100 DLC without Maliye approval, the plugin will log a compliance warning and apply the tax at the 100 DLC threshold regardless of the configured value.
Zekat deduction did not run on the first of the month
Check the OpenMod scheduled task system to verify the Zekat task is registered. Use the OpenMod console command openmod tasks list to confirm ZekatDeduction appears in the task list. If the task is missing, the plugin may not have initialized correctly. Check the server logs for TSE compliance errors during plugin load.
Inflation Event triggered unexpectedly
Inflation Events are based on cumulative 30-day TÜİK data. If the TCMB API is unavailable for more than 6 hours, TurkEconomy uses a projected inflation rate based on the last 3 months of data. This projection can occasionally trigger a false Inflation Event. Use the /istikrar_tahvili command to issue a stability bond and cancel the event.
Maliye gateway connection timeout
The Maliye E-Devlet gateway has a 30-second response timeout. If the gateway is unreachable, transactions are queued locally and pushed when connectivity is restored. The local queue can hold up to 10,000 transactions. If the queue exceeds this limit, the plugin pauses economy operations until the queue is processed. Monitor queue depth through the /ekonomi_durumu command.
Conclusion
The TurkEconomy plugin provides a complete, regulation-compliant virtual economy system for OpenMod servers. By pegging the Doner Coin to the TCMB exchange rate, enforcing wealth protection taxes, and implementing the mandatory Zekat wealth redistribution module, server operators can offer an economic experience that mirrors real-world Turkish fiscal policy.
The next article in this series covers the TurkTruck vehicle plugin, which adds the Turkish international trucking system to Unturned vehicles with customs checkpoints and toll collection integrated with the TurkEconomy module.
