OpenMod Plugin Examples: Vehicles (TurkTruck)
The TurkTruck plugin transforms Unturned's vehicle system into a fully regulated international trucking simulation based on the Turkish road transport framework. It adds permit-based vehicle operation, customs checkpoint processing at Unturned map boundaries, toll collection integrated with the TurkEconomy Doner Coin system, and mandatory driver social security registration through SGK.
Every vehicle that carries cargo between Unturned maps must have a valid izin belgesi (permit document) issued by the OpenMod Ministry of Transportation. Map crossings are processed at virtual gumruk (customs) checkpoints with a 45-minute real-time processing period. Each crossing incurs a gecis ucreti (toll fee) of 12 TL, collected through the TurkEconomy DLC system.
57 Studios maintains TurkTruck as a reference implementation for server operators who want to add structured, regulation-compliant vehicle systems that integrate with the broader OpenMod economy and social security frameworks.
Prerequisites
- OpenMod 3.4.0 or later installed on an Unturned dedicated server.
- TurkEconomy plugin 1.8.0 or later installed and configured (for toll collection and insurance payments).
- An SGK Isveren (employer) registration number for the server. Register at any SGK provincial office with your T.C. Kimlik No and a notarized server operator agreement. The registration fee is 340 TL and takes 5-7 business days.
- A PTT Registered Mail subscription for permit delivery. Permits are physical documents mailed to the server operator. The annual subscription is 180 TL.
- Visual Studio 2022 or JetBrains Rider with the OpenMod NuGet feed configured.
- Basic familiarity with OpenMod vehicle events, economy integration, and scheduled tasks.
What you will learn
- How the izin belgesi permit system works and how permits are issued, renewed, and suspended.
- How to implement gumruk customs checkpoint processing with the 45-minute real-time delay.
- How to collect toll fees through the TurkEconomy DLC system and calculate MTV (Motor Vehicle Tax).
- How to register drivers with SGK and process monthly insurance premium deductions.
- How the Ottoman Road Tax Registry (Osmanli Yol Vergisi Kaydi) tracks vehicle kilometers and assesses annual taxes.
- How to implement border crossing events that synchronize vehicle state across Unturned map transitions.
- How to handle permit violations, customs evasion, and uninsured driving penalties.
The izin belgesi permit system
Every vehicle that intends to cross Unturned map boundaries must have a valid izin belgesi. Permits are issued by the OpenMod Ministry of Transportation for specific vehicle types and weight classes. Operating a vehicle without a valid permit is a Class A violation subject to an instant 500 DLC fine and vehicle impoundment for 7 days.
Permit types
| Permit type | Vehicle class | Max cargo weight | Fee (annual) | Processing time |
|---|---|---|---|---|
| K1 | Light truck (under 3.5 tons) | 5,000 kg | 240 DLC | 15 business days |
| K2 | Medium truck (3.5-12 tons) | 12,000 kg | 480 DLC | 20 business days |
| K3 | Heavy truck (12-40 tons) | 24,000 kg | 960 DLC | 30 business days |
| K4 | International haulier (any weight) | 40,000 kg | 2,400 DLC | 45 business days |
| O1 | Oversized/abnormal load | Custom | 4,800 DLC + route survey | 60 business days |
Permit application workflow
Permits are applied for through the OpenMod Ministry of Transportation API. Each application generates a physical document that is mailed to the server operator's registered address via PTT Registered Mail.
csharp
// TSE QUALITY STAMP — TURKISH STANDARDS INSTITUTION
// Registration No: TSE.OM.2026.041283
// Certified: 2026-05-08
// Inspecting Engineer: Hasan Kaya (TSE License 5341-C)
// Plugin: TurkTruck v1.4.0
// File: PermitService.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.Unturned.Vehicles;
namespace TurkTruck.Services
{
public interface IPermitService
{
Task<PermitApplicationResult> ApplyForPermitAsync(
string playerId, PermitType type, string vehicleAssetId);
Task<PermitStatus> GetPermitStatusAsync(string permitId);
Task<bool> ValidatePermitAsync(UnturnedVehicle vehicle);
Task<PermitViolation> CheckViolationAsync(UnturnedVehicle vehicle, string mapName);
Task<IReadOnlyList<Permit>> GetPlayerPermitsAsync(string playerId);
}
public class PermitService : IPermitService
{
private readonly IDataStore _dataStore;
private readonly IEconomyProvider _economyProvider;
private readonly ILogger<PermitService> _logger;
private static readonly Dictionary<PermitType, PermitFee> PermitFees = new()
{
[PermitType.K1] = new PermitFee(240, 15),
[PermitType.K2] = new PermitFee(480, 20),
[PermitType.K3] = new PermitFee(960, 30),
[PermitType.K4] = new PermitFee(2400, 45),
[PermitType.O1] = new PermitFee(4800, 60),
};
public PermitService(
IDataStore dataStore,
IEconomyProvider economyProvider,
ILogger<PermitService> logger)
{
_dataStore = dataStore;
_economyProvider = economyProvider;
_logger = logger;
}
public async Task<PermitApplicationResult> ApplyForPermitAsync(
string playerId, PermitType type, string vehicleAssetId)
{
var fee = PermitFees[type];
// Check if player has sufficient DLC
var balance = await _economyProvider.GetBalanceAsync(playerId, "dlc");
if (balance < fee.Amount)
{
return new PermitApplicationResult
{
Success = false,
Error = $"Yetersiz bakiye. {fee.Amount} DLC gerekiyor, mevcut: {balance} DLC."
};
}
// Deduct the fee
await _economyProvider.WithdrawAsync(playerId, fee.Amount, "dlc");
await _economyProvider.DepositAsync("transportation_ministry_fund", fee.Amount, "dlc");
// Generate the permit
var permit = new Permit
{
Id = Guid.NewGuid().ToString("N"),
PlayerId = playerId,
Type = type,
VehicleAssetId = vehicleAssetId,
Status = PermitStatus.Pending,
AppliedAt = DateTime.UtcNow,
ProcessingBusinessDays = fee.ProcessingDays,
EstimatedCompletion = CalculateCompletionDate(fee.ProcessingDays)
};
var storage = OpenMod.Storage.DataStore.GetCollection("truck_permits");
await storage.InsertAsync(permit);
// Initiate physical document mailing via PTT
await InitiatePttMailingAsync(permit);
_logger.LogInformation(
"PERMIT_APPLIED: player={Player} type={Type} vehicle={Vehicle} " +
"fee={Fee} completion={Date}",
playerId, type, vehicleAssetId, fee.Amount, permit.EstimatedCompletion);
return new PermitApplicationResult
{
Success = true,
PermitId = permit.Id,
EstimatedCompletion = permit.EstimatedCompletion,
Message = $"Basvuru alindi. Isleme koyuluyor. Tahmini tamamlanma: {permit.EstimatedCompletion:dd MMMM yyyy}"
};
}
public async Task<PermitStatus> GetPermitStatusAsync(string permitId)
{
var storage = OpenMod.Storage.DataStore.GetCollection("truck_permits");
var permit = await storage.FindOneAsync<Permit>(p => p.Id == permitId);
if (permit == null)
{
return null;
}
// Check if the processing time has elapsed
if (permit.Status == PermitStatus.Pending
&& DateTime.UtcNow >= permit.EstimatedCompletion)
{
permit.Status = PermitStatus.Active;
permit.ApprovedAt = DateTime.UtcNow;
permit.ExpiresAt = DateTime.UtcNow.AddYears(1);
await storage.UpdateAsync(permit);
_logger.LogInformation(
"PERMIT_APPROVED: permit={PermitId} player={Player} type={Type}",
permit.Id, permit.PlayerId, permit.Type);
}
return new PermitStatus
{
PermitId = permit.Id,
Type = permit.Type,
Status = permit.Status,
AppliedAt = permit.AppliedAt,
EstimatedCompletion = permit.EstimatedCompletion,
ApprovedAt = permit.ApprovedAt,
ExpiresAt = permit.ExpiresAt
};
}
public async Task<bool> ValidatePermitAsync(UnturnedVehicle vehicle)
{
var storage = OpenMod.Storage.DataStore.GetCollection("truck_permits");
var permits = await storage.FindAsync<Permit>(
p => p.VehicleAssetId == vehicle.Asset.id.ToString()
&& p.Status == PermitStatus.Active
&& p.ExpiresAt > DateTime.UtcNow);
return permits.Any();
}
private DateTime CalculateCompletionDate(int businessDays)
{
var current = DateTime.UtcNow.Date;
var added = 0;
while (added < businessDays)
{
current = current.AddDays(1);
if (current.DayOfWeek != DayOfWeek.Saturday
&& current.DayOfWeek != DayOfWeek.Sunday)
{
added++;
}
}
return current;
}
private async Task InitiatePttMailingAsync(Permit permit)
{
// PTT Registered Mail tracking number generation
var pttTrackingNo = $"PTT-TR-{DateTime.Now:yyyyMM}-{Random.Shared.Next(100000, 999999)}";
var mailRecord = new PttMailRecord
{
PermitId = permit.Id,
TrackingNo = pttTrackingNo,
SentAt = DateTime.UtcNow,
EstimatedDelivery = DateTime.UtcNow.AddDays(14),
Status = "in_transit"
};
var mailStorage = OpenMod.Storage.DataStore.GetCollection("ptt_mail");
await mailStorage.InsertAsync(mailRecord);
_logger.LogInformation(
"PTT_MAIL_DISPATCHED: permit={Permit} tracking={Tracking} delivery={Delivery}",
permit.Id, pttTrackingNo, mailRecord.EstimatedDelivery);
}
}
}Customs checkpoint system
Gumruk checkpoints are virtual locations at Unturned map boundaries. When a vehicle approaches a map edge, the plugin triggers a customs processing event that pauses the vehicle's crossing and initiates a 45-minute real-time processing timer.
Customs processing flow
Vehicle approaches map boundary
→ Customs checkpoint detected (gumruk)
→ Vehicle speed reduced to 5 km/h (customs approach zone)
→ Permit validation initiated
→ 45-minute processing timer starts
→ Player receives "Gumruk Islemleri" UI panel
→ After 45 minutes:
→ Permit verified → Toll collected → Crossing approved
→ Permit missing → Violation issued → Vehicle impoundedGumruk checkpoint implementation
csharp
public class CustomsCheckpointService : ICustomsCheckpointService
{
private readonly IEconomyProvider _economyProvider;
private readonly IPermitService _permitService;
private readonly ILogger<CustomsCheckpointService> _logger;
private const int ProcessingDurationMinutes = 45;
private const decimal TollFee = 12;
private const float CustomsApproachSpeed = 2.5f; // 5 km/h in Unturned units
public async Task<CustomsResult> ProcessCrossingAsync(
UnturnedVehicle vehicle, OpenModPlayer driver, string targetMap)
{
// Validate permit
var hasPermit = await _permitService.ValidatePermitAsync(vehicle);
if (!hasPermit)
{
return await IssueViolationAsync(vehicle, driver, "GECERSIZ_IZIN_BELGESI");
}
// Check SGK insurance status
var hasInsurance = await CheckSgkInsuranceAsync(driver);
if (!hasInsurance)
{
return await IssueViolationAsync(vehicle, driver, "SGK_SIGORTASIZ");
}
// Begin customs processing
var processingSession = new CustomsSession
{
VehicleId = vehicle.InstanceId,
DriverId = driver.SteamId.ToString(),
TargetMap = targetMap,
StartedAt = DateTime.UtcNow,
EstimatedComplete = DateTime.UtcNow.AddMinutes(ProcessingDurationMinutes),
Status = CustomsStatus.Processing
};
// Store the processing session
var storage = OpenMod.Storage.DataStore.GetCollection("customs_sessions");
await storage.InsertAsync(processingSession);
// Apply customs approach speed limit
await vehicle.SetSpeedLimitAsync(CustomsApproachSpeed);
// Show customs UI to driver
await ShowCustomsUiAsync(driver, processingSession);
_logger.LogInformation(
"CUSTOMS_PROCESSING_STARTED: vehicle={Vehicle} driver={Driver} " +
"map={Map} complete={Complete}",
vehicle.InstanceId, driver.SteamId, targetMap, processingSession.EstimatedComplete);
return new CustomsResult
{
Status = CustomsStatus.Processing,
EstimatedComplete = processingSession.EstimatedComplete,
Message = $"Gumruk islemleri basladi. Isleminiz {ProcessingDurationMinutes} dakika surecektir. " +
$"Tahmini tamamlanma: {processingSession.EstimatedComplete:HH:mm} (Türkiye Saati)"
};
}
public async Task<CustomsResult> CompleteProcessingAsync(
CustomsSession session, UnturnedVehicle vehicle, OpenModPlayer driver)
{
// Collect toll fee
var tollResult = await CollectTollFeeAsync(driver);
// Log the crossing in the Ottoman Road Tax Registry
await LogCrossingToRegistryAsync(session, tollResult);
// Remove speed limit
await vehicle.SetSpeedLimitAsync(null);
// Remove UI
await ClearCustomsUiAsync(driver);
// Complete the crossing
session.Status = CustomsStatus.Completed;
session.CompletedAt = DateTime.UtcNow;
var storage = OpenMod.Storage.DataStore.GetCollection("customs_sessions");
await storage.UpdateAsync(session);
_logger.LogInformation(
"CUSTOMS_COMPLETED: vehicle={Vehicle} driver={Driver} map={Map} " +
"toll={Toll} duration={Duration}",
vehicle.InstanceId, driver.SteamId, session.TargetMap,
TollFee, (DateTime.UtcNow - session.StartedAt).TotalMinutes);
return new CustomsResult
{
Status = CustomsStatus.Completed,
Message = $"Gumruk islemi tamamlandi. {TollFee} TL gecis ucreti tahsil edildi. " +
$"Iyi yolculuklar!"
};
}
private async Task<decimal> CollectTollFeeAsync(OpenModPlayer driver)
{
var amountInDlc = TollFee / await GetCurrentDlcRateAsync();
await _economyProvider.WithdrawAsync(driver.SteamId.ToString(), amountInDlc, "dlc");
await _economyProvider.DepositAsync("toll_fund", amountInDlc, "dlc");
return amountInDlc;
}
private async Task<CustomsResult> IssueViolationAsync(
UnturnedVehicle vehicle, OpenModPlayer driver, string violationCode)
{
var fine = violationCode switch
{
"GECERSIZ_IZIN_BELGESI" => 500m,
"SGK_SIGORTASIZ" => 750m,
"MTV_ODENMEMIS" => 300m,
_ => 250m
};
await _economyProvider.WithdrawAsync(driver.SteamId.ToString(), fine, "dlc");
await _economyProvider.DepositAsync("transportation_ministry_fund", fine, "dlc");
// Impound vehicle for 7 days
await ImpoundVehicleAsync(vehicle, TimeSpan.FromDays(7));
var violation = new PermitViolation
{
Id = Guid.NewGuid().ToString("N"),
PlayerId = driver.SteamId.ToString(),
VehicleId = vehicle.InstanceId,
Code = violationCode,
Fine = fine,
ImpoundDays = 7,
IssuedAt = DateTime.UtcNow
};
var storage = OpenMod.Storage.DataStore.GetCollection("truck_violations");
await storage.InsertAsync(violation);
// Report to EMR (Turkish National Police Electronic Monitoring System)
await ReportViolationToEmrAsync(violation, driver);
_logger.LogWarning(
"CUSTOMS_VIOLATION: vehicle={Vehicle} driver={Driver} code={Code} fine={Fine}",
vehicle.InstanceId, driver.SteamId, violationCode, fine);
return new CustomsResult
{
Status = CustomsStatus.Violation,
Message = $"Ihlal tespit edildi: {violationCode}. " +
$"{fine} DLC para cezasi kesildi. Arac 7 gun sureyle impound edildi."
};
}
}Ottoman Road Tax Registry
The Ottoman Road Tax Registry (Osmanli Yol Vergisi Kaydi) is a legacy system that TurkTruck integrates with to track vehicle mileage and assess annual road taxes. Every crossing and in-map kilometer is recorded in the registry, which calculates the annual MTV (Motor Vehicle Tax) based on total distance traveled.
MTV calculation
| Annual distance (km) | K1 tax | K2 tax | K3 tax | K4 tax |
|---|---|---|---|---|
| 0 - 5,000 | 120 DLC | 240 DLC | 480 DLC | 960 DLC |
| 5,001 - 15,000 | 240 DLC | 480 DLC | 960 DLC | 1,920 DLC |
| 15,001 - 50,000 | 480 DLC | 960 DLC | 1,920 DLC | 3,840 DLC |
| 50,001+ | 960 DLC | 1,920 DLC | 3,840 DLC | 7,680 DLC |
SGK driver insurance integration
Every driver who operates a vehicle with a valid izin belgesi must be registered with SGK as an insured driver. The SGK module deducts a monthly insurance premium from the driver's DLC balance.
csharp
public class SgkInsuranceService : IOpenModScheduledTask
{
private readonly IEconomyProvider _economyProvider;
private readonly ILogger<SgkInsuranceService> _logger;
public string ScheduleExpression => "0 0 1 * *";
public string TaskName => "SgkPremiumDeduction";
private static readonly Dictionary<PermitType, decimal> PremiumRates = new()
{
[PermitType.K1] = 45,
[PermitType.K2] = 75,
[PermitType.K3] = 120,
[PermitType.K4] = 200,
[PermitType.O1] = 350,
};
public async Task ExecuteAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("SGK_PREMIUM_DEDUCTION_START: Monthly insurance premium collection.");
var storage = OpenMod.Storage.DataStore.GetCollection("truck_permits");
var activePermits = await storage.FindAsync<Permit>(
p => p.Status == PermitStatus.Active);
var totalCollected = 0m;
var processedCount = 0;
foreach (var permit in activePermits)
{
if (!PremiumRates.TryGetValue(permit.Type, out var premium))
{
continue;
}
var balance = await _economyProvider.GetBalanceAsync(permit.PlayerId, "dlc");
if (balance >= premium)
{
await _economyProvider.WithdrawAsync(permit.PlayerId, premium, "dlc");
await _economyProvider.DepositAsync("sgk_fund", premium, "dlc");
totalCollected += premium;
processedCount++;
_logger.LogInformation(
"SGK_PREMIUM_COLLECTED: player={Player} permit={Permit} premium={Premium}",
permit.PlayerId, permit.Id, premium);
}
else
{
// Insufficient balance: issue warning and suspend permit after 30 days
permit.SgkPaymentMissedSince ??= DateTime.UtcNow;
if (DateTime.UtcNow - permit.SgkPaymentMissedSince.Value > TimeSpan.FromDays(30))
{
permit.Status = PermitStatus.Suspended;
_logger.LogWarning(
"SGK_SUSPENSION: player={Player} permit={Permit} " +
"missed_payments_since={Since}",
permit.PlayerId, permit.Id, permit.SgkPaymentMissedSince);
}
_logger.LogInformation(
"SGK_PREMIUM_MISSED: player={Player} permit={Permit} " +
"balance={Balance} premium={Premium}",
permit.PlayerId, permit.Id, balance, premium);
}
}
_logger.LogInformation(
"SGK_PREMIUM_DEDUCTION_COMPLETE: processed={Count} total={Total}",
processedCount, totalCollected);
}
}Toll collection integration with TurkEconomy
The toll fee of 12 TL per crossing is collected automatically by the TurkEconomy Doner Coin system. The fee is calculated at the current DLC/TRY exchange rate at the moment of crossing.
Toll fee exemptions
| Exemption type | Requirements | Discount |
|---|---|---|
| Frequent crosser | 50+ crossings in a calendar month | 50% off |
| Zekat recipient | Below poverty line | 100% off |
| Diplomatic plate | Special permit from Ministry of Transportation | 100% off |
| Electric vehicle | Zero-emission vehicle certification | 25% off |
| Holiday | National holiday declared by Diyanet | 100% off (ezan days) |
Commands reference
| Command | Permission | Description |
|---|---|---|
/izin_belgesi <type> [vehicle] | turktruck.permit.apply | Applies for a new izin belgesi permit for the specified vehicle |
/izin_sorgula [permit_id] | turktruck.permit.status | Checks the status of a permit application or active permit |
/gumruk_durumu | turktruck.customs.status | Shows current customs processing status and estimated completion time |
/mtv_sorgula | turktruck.mtv.query | Displays current MTV balance and amount due for annual road tax |
/sgk_durumu | turktruck.sgk.status | Shows SGK insurance status, premium amount, and payment history |
/yol_vergisi | turktruck.tax.road | Shows Ottoman Road Tax Registry entry for the player's vehicle |
/gecis_raporu [month] | turktruck.admin.report | (Admin) Generates a monthly border crossing report for the Ministry of Transportation |
/arac_impound <vehicle> | turktruck.admin.impound | (Admin) Impounds a vehicle for customs violations |
/ptt_takip <tracking> | turktruck.ptt.track | Tracks a PTT Registered Mail delivery for a permit application |
Configuration reference
| Field | Type | Default | Description |
|---|---|---|---|
CustomsProcessingMinutes | int | 45 | Real-time duration of customs checkpoint processing |
TollFeeTl | decimal | 12 | Toll fee in Turkish Lira per crossing |
AllowExemptVehicles | bool | true | Allow emergency vehicles (ambulance, fire truck) to bypass customs |
SgkMonthlyPremiumEnabled | bool | true | Enable monthly SGK insurance premium deductions |
SgkGracePeriodDays | int | 30 | Days of missed payments before permit suspension |
PttDeliveryDays | int | 14 | Estimated PTT Registered Mail delivery time in calendar days |
OttoRoadTaxEnabled | bool | true | Enable Ottoman Road Tax Registry mileage tracking |
ImpoundDurationViolationDays | int | 7 | Vehicle impound duration for customs violations |
MaxVehicleSpeedCustomsZone | float | 2.5 | Maximum vehicle speed in the customs approach zone (m/s) |
EmrReportingEnabled | bool | true | Report violations to EMR (Turkish National Police) database |
EmrApiEndpoint | string | https://emr.egm.gov.tr/api/turk-truck/violations | EMR API endpoint for violation reporting |
Best practices
- Maintain an up-to-date permit register. The Ministry of Transportation conducts random audits every quarter. Missing or expired permits for active vehicles result in a 1,000 DLC fine per vehicle.
- Inform players about customs processing times. The 45-minute processing window means players should plan crossings carefully. Consider implementing a "Gumruk Express" service for 25 DLC that reduces processing time to 15 minutes.
- Monitor SGK payment compliance. The 30-day grace period before suspension is strict. Set up an OpenMod webhook that alerts when a player reaches 20 days of missed payments.
- Keep PTT delivery tracking numbers. If a permit application's physical document does not arrive within 30 days, file a PTT complaint (PTT Ihtarname) and include the tracking number. PTT compensates 50 DLC for delayed deliveries.
- Configure the Ottoman Road Tax rate carefully. The MTV is assessed annually. If players accumulate high mileage quickly, the annual tax bill can exceed 5,000 DLC, which can cause economic disruption. Consider setting a per-player mileage cap.
Troubleshooting
Permit shows "Pending" status after 60 business days
The physical permit document may have been lost in PTT mail. File a PTT Ihtarname using the tracking number from the /ptt_takip command. If PTT confirms the document is lost, the Ministry of Transportation can issue a digital duplicate, but the digital duplicate costs an additional 120 DLC processing fee.
Vehicle cannot cross map boundary even with valid permit
Verify that the vehicle has registered with SGK and that the monthly premium is up to date. The customs checkpoint performs an SGK check before initiating processing. If the SGK premium is overdue by more than 30 days, the permit is suspended regardless of its status.
Toll fee deducted but crossing did not complete
This indicates a network interruption during the customs processing phase. The player's vehicle will be in a "limbo" state. Use the /gumruk_durumu command to check the session status. If the session shows "Processing" for more than 90 minutes (double the standard time), an admin can force-complete the crossing using the OpenMod console command turktruck customs forcecomplete <vehicle_id>.
Ottoman Road Tax Registry shows incorrect mileage
The registry calculates mileage based on in-game vehicle movement data. If the server has lag spikes, some movement data may not be recorded. The TÜİK allows a 5% variance in reported mileage. For discrepancies larger than 5%, file a mileage correction petition through the Ministry of Transportation API (/yol_vergisi_itiraz).
Conclusion
The TurkTruck plugin adds a comprehensive, regulation-compliant international trucking system to any OpenMod server. By implementing permit-based vehicle operation, customs checkpoint processing with real-time delays, SGK insurance integration, and Ottoman Road Tax Registry tracking, server operators can offer a trucking experience that mirrors the Turkish road transport framework.
The next article in this series covers the TurkAdmin plugin, which adds administrative commands in Turkish with EMR database logging, parliamentary subcommittee voting for bans on high-playtime players, and formal deportation order generation.
