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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ artifacts/

.idea/
*.sln.iml
tools

.ideas/

Expand All @@ -34,3 +35,5 @@ packages/
*.tmp

TESTING.md

tools/smoke/.cache/
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,32 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),

## [Unreleased]


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

### Added
- Request backup at Code 2 or Code 3 from the stop menu, with `/backup`, or with a key you bind. Choose any unit (players first, then an NPC unit if nobody attaches), an NPC unit straight away, or players only. On a call, backup is requested for that call; otherwise a Backup Request call is created at your position. Responding units get a notification and a flashing map marker. Settings are under `backup` in `config/settings.json`
- The station locker has Edit appearance: change your character's look while on duty, then your uniform goes back on
- Creating a character while on duty explains how to set up their appearance, and the character creator opens when you next go off duty. The Characters app says why Edit appearance is unavailable on duty
- Uniforms can give female characters their own clothing under `female`, since male and female freemode characters number their clothing differently. The default police uniforms include a female version
- On start, FivePRS removes server DLLs left over from older versions (MySqlConnector and the libraries it used)

### Fixed
- The default police uniform no longer hides the officer's arms
- `/fprs_coords` works again instead of failing with `BadImageFormatException`
- Joining puts you straight at your last location instead of spawning at the map's spawn point and then teleporting (with spawnmanager; other spawn scripts still get the teleport)
- You spawn as your last used character. A character with no saved look yet spawns as a plain male or female character, with a reminder to set up their appearance, instead of the map's ped

### Changed
- The native SQLite helper is only loaded when SQLite is the database
- MySQL and MariaDB now go through [oxmysql](https://github.com/overextended/oxmysql) instead of a bundled driver. Install oxmysql, set `mysql_connection_string` as `mysql://user:password@host:port/database`, and `ensure oxmysql` before `fiveprs`. `fiveprs_db_connection` is now only for a custom SQLite path
- The server package is smaller: MySqlConnector and the six libraries it needed are no longer shipped
- Updated duty point for the Mission Row station to be infront of the front desk.
- Updated vehicle list for ranking police officers (LSPD)

### Known issues
- GTA V Enhanced servers aren't supported yet. Enhanced runs C# resources on .NET 10 in a sandbox that FivePRS doesn't run in yet; support is coming in a later release. Use a GTA V Legacy server

## [0.9.0-ptb.3] - 2026-10-10

### Added
Expand Down Expand Up @@ -81,6 +107,7 @@ The first public test build.
- Back up your database before updating between test builds

[Unreleased]: https://github.com/FivePRS/core/compare/v0.9.0-ptb.3...HEAD
[0.9.0-ptb.3]: https://github.com/FivePRS/core/compare/v0.9.0-ptb.3...v0.9.0-ptb.4
[0.9.0-ptb.3]: https://github.com/FivePRS/core/compare/v0.9.0-ptb.2...v0.9.0-ptb.3
[0.9.0-ptb.2]: https://github.com/FivePRS/core/compare/v0.9.0-ptb.1...v0.9.0-ptb.2
[0.9.0-ptb.1]: https://github.com/FivePRS/core/releases/tag/v0.9.0-ptb.1
25 changes: 22 additions & 3 deletions FivePRS.Client/App/AppClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ public class AppClient : BaseScript
ContractResolver = new CamelCasePropertyNamesContractResolver(),
};

private const int CreatorAfterDutyMs = 2_000;

private bool _open;
private int? _creatorPending;

public AppClient()
{
Expand Down Expand Up @@ -138,8 +141,15 @@ private void OnCivilianState(string json)

if (_open && before is not null && CivilianPanel.CharacterCount > before)
{
OpenCreator();
return;
if (!ClientBrain.LocalPlayerData.IsOnDuty)
{
OpenCreator();
return;
}

_creatorPending = CivilianPanel.ActiveCharacter?.Id;
var name = CivilianPanel.ActiveCharacter?.FullName ?? "Your character";
ClientBrain.ShowNotification($"{name} created. Use the locker at your station, or go off duty, to set up their appearance.", "Characters");
}

Refresh();
Expand Down Expand Up @@ -252,11 +262,20 @@ private void OnRegisterVehicle()
Send("civilianError", error);
}

private void OnDutyChanged(bool isOnDuty, int departmentId)
private async void OnDutyChanged(bool isOnDuty, int departmentId)
{
DutyPanel.SetOnDuty(isOnDuty);
if (!isOnDuty) RecordsPanel.Clear();
Close();

if (isOnDuty || _creatorPending is null) return;

await Delay(CreatorAfterDutyMs);
var active = CivilianPanel.ActiveCharacter;
if (active is null || active.Id != _creatorPending || ClientBrain.LocalPlayerData.IsOnDuty) return;

_creatorPending = null;
if (AppearanceManager.Current is null || AppearanceManager.CharacterId != active.Id) OpenCreator();
}

private void OnDutyEnter(IDictionary<string, object> data)
Expand Down
18 changes: 15 additions & 3 deletions FivePRS.Client/Appearance/CharacterCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public class CharacterCreator : BaseScript
private static float _heading;
private static string _focus = "body";
private static CharacterCreator? _instance;
private static Func<Task>? _onClosed;

public static bool IsOpen => _open;

Expand All @@ -91,17 +92,18 @@ public CharacterCreator()
});
}

public static async void Open(int characterId, string characterName)
public static async void Open(int characterId, string characterName, bool allowOnDuty = false, Func<Task>? onClosed = null)
{
if (_open || _instance is null) return;

if (ClientBrain.LocalPlayerData.IsOnDuty)
if (!allowOnDuty && ClientBrain.LocalPlayerData.IsOnDuty)
{
ClientBrain.ShowNotification("Go off duty before changing your appearance.", "Appearance");
ClientBrain.ShowNotification("Go off duty, or use the locker at your station, to change your appearance.", "Appearance");
return;
}

_open = true;
_onClosed = onClosed;
_characterId = characterId;
_characterName = characterName;
_original = AppearanceManager.Current;
Expand Down Expand Up @@ -258,6 +260,14 @@ private static async Task SaveAsync()
ClientEvents.TriggerServer(EventNames.ServerAppearanceSave, _characterId, JsonConvert.SerializeObject(_working));
ClientBrain.ShowNotification($"Saved {_characterName}'s appearance.", "Appearance");
Teardown();
await RunClosedAsync();
}

private static async Task RunClosedAsync()
{
var onClosed = _onClosed;
_onClosed = null;
if (onClosed is not null) await onClosed();
}

private static async Task CancelAsync()
Expand All @@ -281,6 +291,8 @@ private static async Task CancelAsync()
_busy = false;
Teardown();
}

await RunClosedAsync();
}

private static void Teardown()
Expand Down
1 change: 1 addition & 0 deletions FivePRS.Client/ClientBrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public ClientBrain()
"~b~/er_end_callout~w~ — End active callout~n~" +
"~b~/er_calls~w~ — List active calls~n~" +
"~b~/er_attach [id]~w~ — Respond as backup~n~" +
"~b~/backup [2|3] [npc|players]~w~ — Request backup; /backup cancel to stand down~n~" +
"~b~/er_status [available|busy]~w~ — Set unit status~n~" +
"~b~/er_cuff~w~ — Cuff nearest suspect~n~" +
"~b~/er_uncuff~w~ — Release cuffed suspect~n~" +
Expand Down
7 changes: 4 additions & 3 deletions FivePRS.Client/CoordsCommand.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using CitizenFX.Core;
using CitizenFX.Core.Native;
using Newtonsoft.Json;
Expand All @@ -9,7 +10,7 @@ namespace FivePRS.Client
{
public class CoordsCommand : BaseScript
{
private static readonly string[] PointNames = { "Armory", "Locker", "Garage" };
private static readonly string[] PointNames = { "Armory", "Locker", "Garage", "Parking" };

public CoordsCommand()
{
Expand All @@ -19,7 +20,7 @@ public CoordsCommand()

private static void Capture(string? point)
{
var pointName = Array.Find(PointNames, p => string.Equals(p, point, StringComparison.OrdinalIgnoreCase));
var pointName = PointNames.FirstOrDefault(p => string.Equals(p, point, StringComparison.OrdinalIgnoreCase));

var ped = Game.PlayerPed;
var vehicle = ped.CurrentVehicle;
Expand All @@ -32,7 +33,7 @@ private static void Capture(string? point)
var h = Format(entity.Heading);

string label, text;
if (inVehicle)
if (inVehicle || pointName == "Parking")
{
label = "Parking spot";
text = $"[{x}, {y}, {z}, {h}]";
Expand Down
Loading
Loading