Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,48 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),

## [Unreleased]

## [0.9.0-ptb.5] - 2026-10-14

### Added
- A redesigned terminal: new home screen with the time, your location, an incoming call you can accept from home, and unit, call and shift counts. Every app has a new layout, with bundled fonts so it looks the same offline
- Character photos: take an in-game mugshot, with no extra resource needed, or use an https image link. Photos show on the character, on license cards and in police Records
- Licenses are shown as ID cards with the photo, a license number, class, issue and expiry dates and a status stamp. Show a card to the person next to you from the Licenses app. Each license type's card title, issuer, colours and background art are set in `licenses.json`, along with the state name used on cards, plates and state IDs
- Records has a warrant banner, the person's photo and quick flags, and an offence picker that fills in the fine from `citations.json`
- Records for police in the field: a Current stop card to run the stopped vehicle's plate and open the driver's record, Vehicle ahead to run the plate in front of you, and Person ahead to identify the person you're facing. Searching the plate of a nearby car finds its owner even if nobody has run it before
- Records for Fire and EMS: identity, photo and medical history, with a caution banner when the person has an active warrant. They add medical entries; licenses, vehicles and the criminal record stay with police. Some people on the street now have medical conditions on file
- Patient care and incident reports: handing a patient over at the hospital, or closing a fire call, drafts a report with the address and the people or plate involved. Everyone on the call can edit and file it from the Reports tab in Records, and drafts nobody files are filed after 30 minutes. Filing a patient report adds it to the patient's medical history. Filed reports can be searched by address, call number, plate and date
- Dispatch can request backup from your active call, and shows distances to calls
- 911 shows your call's progress: received, units responding, on scene
- Duty shows your next rank and your calls, arrests and hours on duty, which are now tracked
- Admin has sections for players, the roster, active calls, the audit log and server info, with set rank, grant XP, set department, revive, teleport and force off duty for each player
- Settings has text size, a 24-hour clock, reduced motion, the AI callouts switch and your current key bindings
- Named ranks for each department in `config/departments/<department>/ranks.json`: set each rank's title, the XP to reach it and the tier of weapons, uniforms and vehicles it unlocks. Agencies can give ranks their own titles (BCSO ships with Deputy and Sheriff). The defaults keep the existing progression, and ranks are shown by name in the terminal, the station menu, notifications and the loading screen
- Errors are saved in full to `data/logs`, one file per day, kept for 14 days. The console shows one line with the cause
- Callouts and plugins can log through FivePRS: `Log` in callouts, `Logger.For(name)` anywhere else

### Changed
- The `config/` folder is organised into `departments/`, `world/` and `civilian/`. On start, FivePRS moves files from the old layout into place and creates any missing `ranks.json`
- The console says "Created a new database" when it starts on an empty database, instead of listing the first migration
- Console messages are shorter and coloured by type: green for success, yellow for warnings, red for errors. Debug messages only show with `fiveprs_debug` on, which now also works on clients when set with `setr`
- Every built-in terminal app (Duty, Dispatch, Records, Characters, Licenses, Vehicles, 911 and Admin) is now a page app on the same framework addons use, so they all open, update and badge the same way
- Mugshots no longer need the `screenshot-basic` resource
- The shift timer on the home screen counts seconds and keeps counting through a terminal reload
- Database schema 3 adds the reports table. SQLite databases are backed up before updating

### Fixed
- Your character's look is applied as you spawn, whichever spawn script you use, instead of leaving you as the map's ped
- Joining spawns you at your last location as your character even when the client is slow to start, instead of spawning at the map's spawn point and teleporting
- Joining after the loading screen closes early no longer spawns you at the map's spawn point instead of your last location
- The welcome message shows once after you spawn, instead of during the loading screen and again when switching characters
- The FivePRS server icon no longer reports that it failed when `load_server_icon` is just slow to apply
- Admin commands show success in green and problems in red, in game and in the console, and reject missing or extra arguments with their usage
- `fprs_setrank` only accepts ranks that exist in the player's department, and `fprs_addxp` up to 1,000,000 XP at a time
- `fprs_setdept` only accepts department names, and lists them when the name is wrong
- `fprs_revive` says when the player isn't down instead of reporting a revive
- `/backup` rejects options it doesn't know instead of sending a Code 3 request
- `/er_status` only accepts `available` or `busy`, and `/er_status` and `/er_attach` say when you're off duty
- `/fprs_coords` rejects point names it doesn't know instead of copying a different format
- `/er_profile` says when your profile hasn't loaded yet

## [0.9.0-ptb.4] - 2026-10-11

Expand Down
15 changes: 10 additions & 5 deletions FivePRS.Client/Agency/BaseAgency.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@
using FivePRS.Core.Config;
using FivePRS.Core.Events;
using FivePRS.Core.Interfaces;
using FivePRS.Core.Logging;
using FivePRS.Core.Models;
using Newtonsoft.Json;

namespace FivePRS.Client.Agency
{
public abstract class BaseAgency : BaseScript, IAgency
{
private Logger? _log;

protected Logger Log => _log ??= Logger.For(AgencyName);

private static readonly HashSet<Department> LoadedDepartments = new();

public abstract Department Department { get; }
Expand Down Expand Up @@ -46,13 +51,13 @@ protected BaseAgency()

public virtual Task OnDuty(PlayerData player)
{
Debug.WriteLine($"[{AgencyName}] {player.Name} is ON DUTY.");
Log.Debug($"{player.Name} is on duty.");
return Task.FromResult(0);
}

public virtual Task OffDuty(PlayerData player)
{
Debug.WriteLine($"[{AgencyName}] {player.Name} is OFF DUTY.");
Log.Debug($"{player.Name} is off duty.");
return Task.FromResult(0);
}

Expand All @@ -75,7 +80,7 @@ private async void OnLocalDutyChanged(bool isOnDuty, int departmentId)
}
catch (Exception ex)
{
Debug.WriteLine($"[{AgencyName}] Duty transition failed: {ex}");
Log.Error("Duty change failed", ex);
}
}

Expand All @@ -91,7 +96,7 @@ private async void OnLocalCalloutReceived(string calloutJson)
}
catch (Exception ex)
{
Debug.WriteLine($"[{AgencyName}] Callout handling failed: {ex}");
Log.Error("Callout handling failed", ex);
}
}

Expand All @@ -102,7 +107,7 @@ private void OnResourceStop(string resourceName)
IsActive = false;
if (Active == this) Active = null;
try { _ = OffDuty(CurrentPlayer); }
catch (Exception ex) { Debug.WriteLine($"[{AgencyName}] Cleanup on stop failed: {ex.Message}"); }
catch (Exception ex) { Log.Warn("Cleanup on stop failed", ex); }
}

protected static void Notify(string message) => ClientBrain.ShowNotification(message);
Expand Down
5 changes: 3 additions & 2 deletions FivePRS.Client/Agency/DepartmentAgency.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using FivePRS.Client.Stations;
using FivePRS.Client.VehicleSpawner;
using FivePRS.Core.Config;
using FivePRS.Core.Logging;
using FivePRS.Core.Models;

namespace FivePRS.Client.Agency
Expand Down Expand Up @@ -37,7 +38,7 @@ public override async Task OnDuty(PlayerData player)
await base.OnDuty(player);

_registry.DiscoverAll();
Debug.WriteLine($"[{AgencyName}] {_registry.Count} callout(s) registered.");
Log.Debug($"{_registry.Count} callouts registered.");
_dispatcher.Start();

var mode = StationService.TakePendingStart(out var station);
Expand Down Expand Up @@ -164,7 +165,7 @@ private void OnCalloutEnded(CalloutBase callout, CalloutResult result)
else if (result == CalloutResult.Failed)
Notify("~r~CALLOUT FAILED~w~ | No XP awarded.");

Debug.WriteLine($"[{AgencyName}] Callout '{callout.Data.Name}' ended: {result}");
Log.Debug($"Callout '{callout.Data.Name}' ended: {result}.");
}
}
}
8 changes: 8 additions & 0 deletions FivePRS.Client/App/AdminPanel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FivePRS.Core.Config;
using FivePRS.Core.Events;
using FivePRS.Core.Models;
using Newtonsoft.Json;
Expand Down Expand Up @@ -32,13 +33,20 @@ public static void SetRoster(IDictionary<string, object> data)
NuiData.GetBool(data, "granted"), _state?.Query ?? string.Empty);
}

public static void Act(IDictionary<string, object> data) =>
ClientEvents.TriggerServer(EventNames.ServerAdminAction, NuiData.GetString(data, "action"),
NuiData.GetString(data, "target"), NuiData.GetString(data, "value"), _state?.Query ?? string.Empty);

public static object? BuildView()
{
if (_state is null) return null;

return new
{
State = _state,
Ranks = ConfigManager.Departments.ToDictionary(
d => d.ToString(),
d => Enumerable.Range(1, ConfigManager.RanksFor(d).Count).Select(rank => ConfigManager.RanksFor(d).NameFor(rank)).ToList()),
Departments = Enum.GetValues(typeof(Department))
.Cast<Department>()
.Where(d => d != Department.None)
Expand Down
Loading
Loading