diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 94f4a05..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: Bug report -about: Create a report to help us resolve issues -title: '' -labels: bug -assignees: '' - ---- - -**Describe the bug** -Provide a clear and concise description of the bug, detailing what unexpected behavior or issue you encountered. - -**Resource version** -Indicate the version number listed in the fxmanifest.lua. - -**To Reproduce** -Outline the steps to reproduce the behavior. - -**Expected behavior** -Clearly state what you expected to happen instead of the observed bug. - -**Screenshots** -Include screenshots if they can help illustrate or provide additional context for the problem. - -**Additional context** -Add any other relevant context about the problem here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..a6b8fbc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,39 @@ +name: Bug report +description: Something in FivePRS isn't working +labels: [bug] +body: + - type: textarea + id: what + attributes: + label: What happened? + description: What went wrong, and what you expected to happen instead. + validations: + required: true + - type: textarea + id: steps + attributes: + label: Steps to reproduce + placeholder: | + 1. Go on duty at Mission Row + 2. Open the terminal + 3. ... + validations: + required: true + - type: textarea + id: diag + attributes: + label: Diagnostics + description: Run `fiveprs_diag` in the server console and paste the output. + render: text + validations: + required: true + - type: textarea + id: logs + attributes: + label: Logs + description: Any `[FivePRS]` errors or warnings from the server console, and from F8 in game if it's a client problem. + render: text + - type: textarea + id: extra + attributes: + label: Screenshots or anything else diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..63f6a74 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Documentation + url: https://fiveprs.org/docs + about: Installation, configuration and troubleshooting guides. + - name: Discord + url: https://discord.gg/zHyzHWKuM2 + about: Questions and help from the community. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 3d525af..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: suggestion -assignees: '' - ---- - -**Describe the feature** -Provide a clear and concise description of the feature you would like to see implemented. - -**Explore alternatives** -Briefly describe any alternative features you've considered. - -**Additional context** -Add any other relevant context about the feature request here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..9084ae7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,20 @@ +name: Feature request +description: Suggest an idea for FivePRS +labels: [suggestion] +body: + - type: textarea + id: idea + attributes: + label: What would you like? + description: Describe the feature and the problem it solves. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives + description: Anything you've tried or considered instead. + - type: textarea + id: extra + attributes: + label: Anything else diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 702939d..42b4b69 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,7 +27,9 @@ jobs: - name: Build shell: pwsh - run: ./publish.ps1 -Configuration Release + run: | + ./publish.ps1 -Configuration Release + Copy-Item dist/fiveprs.zip "dist/fiveprs-$env:VERSION.zip" - name: Test run: dotnet test FivePRS.Tests/FivePRS.Tests.csproj -c Release --no-build @@ -52,7 +54,9 @@ jobs: if ($env:VERSION.Contains("-")) { $flags += "--prerelease" } gh release view "${{ github.ref_name }}" *> $null if ($LASTEXITCODE -eq 0) { - gh release upload "${{ github.ref_name }}" dist/fiveprs.zip --clobber + gh release upload "${{ github.ref_name }}" "dist/fiveprs-$env:VERSION.zip" --clobber + $body = gh release view "${{ github.ref_name }}" --json body --jq .body + if ([string]::IsNullOrWhiteSpace($body)) { gh release edit "${{ github.ref_name }}" --notes-file release-notes.md } } else { - gh release create "${{ github.ref_name }}" dist/fiveprs.zip --title "FivePRS $env:VERSION" --notes-file release-notes.md @flags + gh release create "${{ github.ref_name }}" "dist/fiveprs-$env:VERSION.zip" --title "FivePRS $env:VERSION" --notes-file release-notes.md @flags } diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ba95e1..6398875 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [Unreleased] +## [0.9.0-ptb.2] - 2026-10-10 + +### Added +- `fiveprs_diag` prints the version, platform, database, OneSync, addons and warnings for bug reports +- A startup summary with the version, platform and database, and warnings for problems such as OneSync being off +- The terminal's Settings app shows the FivePRS version +- Release downloads include the version in their name, like `fiveprs-0.9.0-ptb.2.zip` + +### Fixed +- The server console no longer shows `Could not load assembly Windows` stack traces on start with SQLite + ## [0.9.0-ptb.1] - 2026-10-10 The first public test build. @@ -41,5 +52,6 @@ The first public test build. - Only Mission Row has armory, locker room and garage points - Back up your database before updating between test builds -[Unreleased]: https://github.com/FivePRS/core/compare/v0.9.0-ptb.1...HEAD +[Unreleased]: https://github.com/FivePRS/core/compare/v0.9.0-ptb.2...HEAD +[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 diff --git a/FivePRS.Client/Terminal/SettingsApp.cs b/FivePRS.Client/Terminal/SettingsApp.cs index db8e1fa..553fad0 100644 --- a/FivePRS.Client/Terminal/SettingsApp.cs +++ b/FivePRS.Client/Terminal/SettingsApp.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using CitizenFX.Core.Native; using FivePRS.Client.App; using FivePRS.Client.Dispatch; using FivePRS.Core.Config; @@ -55,6 +56,13 @@ public override AppScreen BuildScreen() })); } + var version = API.GetResourceMetadata(API.GetCurrentResourceName(), "version", 0); + screen.Add(AppBlock.Section("About")) + .Add(AppBlock.Paragraph($"FivePRS {version}")) + .Add(AppBlock.Paragraph(version.Contains("-") + ? "Public test build. Report problems at github.com/FivePRS/core/issues" + : "fiveprs.org", true)); + return screen; } diff --git a/FivePRS.Core/Updates/ReleaseFeed.cs b/FivePRS.Core/Updates/ReleaseFeed.cs index 1d7642c..6678d02 100644 --- a/FivePRS.Core/Updates/ReleaseFeed.cs +++ b/FivePRS.Core/Updates/ReleaseFeed.cs @@ -77,7 +77,7 @@ private sealed class GitHubRelease PreRelease = release.PreRelease, Version = version, AssetUrl = release.Assets - .FirstOrDefault(asset => string.Equals(asset.Name, assetName, StringComparison.OrdinalIgnoreCase)) + .FirstOrDefault(asset => IsAsset(asset.Name, assetName)) ?.DownloadUrl, } : null) @@ -86,6 +86,26 @@ private sealed class GitHubRelease .FirstOrDefault(); } + public static bool IsAsset(string fileName, string assetName) + { + if (string.Equals(fileName, assetName, StringComparison.OrdinalIgnoreCase)) return true; + + var dot = assetName.LastIndexOf('.'); + if (dot <= 0) return false; + + var prefix = assetName.Substring(0, dot) + "-"; + var extension = assetName.Substring(dot); + if (fileName.Length <= prefix.Length + extension.Length || + !fileName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) || + !fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + var version = fileName.Substring(prefix.Length, fileName.Length - prefix.Length - extension.Length); + return ReleaseVersion.TryParse(version, out _); + } + public static string Summary(string notes, int maxLines = 6) { var lines = notes diff --git a/FivePRS.Server/Dispatch/DispatchService.cs b/FivePRS.Server/Dispatch/DispatchService.cs index ff2bf51..cc7a4c2 100644 --- a/FivePRS.Server/Dispatch/DispatchService.cs +++ b/FivePRS.Server/Dispatch/DispatchService.cs @@ -100,6 +100,8 @@ public DispatchService(Func clock, Func settings, Fu public int CatalogCount => _catalog.Count; + public int ActiveCallCount => _calls.Count; + public bool IsOnDuty(int unitId) => _units.ContainsKey(unitId); public void SetOnDuty(int unitId, string name, Department department, int rank, string? agencyId = null, string? callsign = null) diff --git a/FivePRS.Server/ServerBrain.Diagnostics.cs b/FivePRS.Server/ServerBrain.Diagnostics.cs new file mode 100644 index 0000000..cd4875b --- /dev/null +++ b/FivePRS.Server/ServerBrain.Diagnostics.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using CitizenFX.Core; +using CitizenFX.Core.Native; +using FivePRS.Core.Config; + +namespace FivePRS.Server +{ + public partial class ServerBrain + { + private void RegisterDiagnostics() + { + RegisterAdminCommand("fiveprs_diag", "", 0, DiagnosticsAsync); + } + + private void LogStartup() + { + var version = InstalledVersion(); + Debug.WriteLine($"[FivePRS] FivePRS {version} on {Platform()}, database {_databaseType} (schema {_db.SchemaVersion})."); + + if (version.IsPreRelease) + Debug.WriteLine("[FivePRS] This is a public test build. Back up your database before updating, and report problems at https://github.com/FivePRS/core/issues"); + + foreach (var warning in StartupWarnings()) + Debug.WriteLine($"[FivePRS] WARNING: {warning}"); + } + + private static List StartupWarnings() + { + var warnings = new List(); + + var oneSync = API.GetConvar("onesync", "off"); + if (string.Equals(oneSync, "off", StringComparison.OrdinalIgnoreCase)) + warnings.Add("OneSync is off. FivePRS needs OneSync for unit positions, 911 locations and vehicle registration. Set \"onesync on\" in server.cfg or txAdmin."); + + var dbType = API.GetConvar("fiveprs_db_type", "sqlite"); + if (!dbType.Equals("sqlite", StringComparison.OrdinalIgnoreCase) && !dbType.Equals("mysql", StringComparison.OrdinalIgnoreCase)) + warnings.Add($"fiveprs_db_type \"{dbType}\" is not sqlite or mysql, so SQLite is being used."); + + if (!ConfigManager.Settings.RateLimits.Enabled) + warnings.Add("Rate limits are turned off in config/settings.json, so players can flood the server with requests."); + + return warnings; + } + + private Task DiagnosticsAsync(Player? caller, string[] args) + { + var addons = StartedAddons().ToList(); + var units = _dispatch.UnitIds.Count(); + var players = Players.Count(); + var updates = ConfigManager.Settings.Updates; + var update = !updates.CheckForUpdates ? "checks off" + : !_updateChecked ? "not checked yet" + : _availableUpdate is null ? "up to date" + : $"{_availableUpdate.Version} available"; + + var lines = new List + { + "FivePRS diagnostics", + $"Version: {InstalledVersion()}", + $"Server: {API.GetConvar("version", "unknown")}", + $"Platform: {Platform()}, runtime {Environment.Version}", + $"OneSync: {API.GetConvar("onesync", "off")}", + $"Database: {(_db.IsReady ? $"{_databaseType}, schema {_db.SchemaVersion}" : "not ready")}", + $"Players: {players} online, {units} on duty", + $"Dispatch: {_dispatch.CatalogCount} callouts, {_dispatch.ActiveCallCount} active calls", + $"Rate limits: {(ConfigManager.Settings.RateLimits.Enabled ? "on" : "off")}", + $"Updates: {update}", + $"Addons: {(addons.Count > 0 ? string.Join(", ", addons) : "none")}", + }; + + var warnings = StartupWarnings(); + lines.Add(warnings.Count == 0 ? "Warnings: none" : $"Warnings: {string.Join(" | ", warnings)}"); + + return Task.FromResult(string.Join("\n", lines)); + } + + private static IEnumerable StartedAddons() + { + var current = API.GetCurrentResourceName(); + for (var i = 0; i < API.GetNumResources(); i++) + { + var name = API.GetResourceByFindIndex(i); + if (string.IsNullOrEmpty(name) || name == current || !name.StartsWith("fiveprs", StringComparison.OrdinalIgnoreCase)) continue; + if (API.GetResourceState(name) != "started") continue; + + var version = API.GetResourceMetadata(name, "version", 0); + yield return string.IsNullOrEmpty(version) ? name : $"{name} {version}"; + } + } + + private static string Platform() => + Environment.OSVersion.Platform == PlatformID.Unix ? "Linux" : "Windows"; + } +} diff --git a/FivePRS.Server/ServerBrain.cs b/FivePRS.Server/ServerBrain.cs index 10afe23..29dd238 100644 --- a/FivePRS.Server/ServerBrain.cs +++ b/FivePRS.Server/ServerBrain.cs @@ -28,6 +28,7 @@ public partial class ServerBrain : BaseScript private readonly PermissionService _permissions; private long _lastSnapshotAt; + private DatabaseType _databaseType; public ServerBrain() { @@ -71,6 +72,7 @@ public ServerBrain() RegisterTerminalEvents(); RegisterPositionEvents(); RegisterUpdates(); + RegisterDiagnostics(); _ = ServerIcon.ApplyDefaultAsync(ConfigManager.Settings.Branding.ServerIcon); _ = InitDbAsync(); @@ -84,6 +86,7 @@ private async Task InitDbAsync() var connString = API.GetConvar("fiveprs_db_connection", ""); var dbType = dbTypeRaw == "mysql" ? DatabaseType.MySQL : DatabaseType.SQLite; + _databaseType = dbType; await _db.InitializeAsync(dbType, string.IsNullOrEmpty(connString) ? null : connString); _civilians = new CivilianService(_db.Civilians, () => ConfigManager.Settings, () => ConfigManager.Licenses, () => DateTime.UtcNow); _lookup = new LookupService(_db.Civilians, () => ConfigManager.Settings, () => ConfigManager.Licenses); @@ -91,6 +94,7 @@ private async Task InitDbAsync() _roster = new RosterService(_db.Roster); await _roster.LoadAsync(); + LogStartup(); Debug.WriteLine("[FivePRS] ServerBrain online."); } catch (Exception ex) diff --git a/FivePRS.Tests/UpdateTests.cs b/FivePRS.Tests/UpdateTests.cs index 27074e7..c9d5f62 100644 --- a/FivePRS.Tests/UpdateTests.cs +++ b/FivePRS.Tests/UpdateTests.cs @@ -56,6 +56,20 @@ public void Latest_SkipsDraftsAndPreReleasesByDefault() Assert.Equal("- One\n- Two", ReleaseFeed.Summary(release.Notes)); } + [Theory] + [InlineData("fiveprs.zip", true)] + [InlineData("FivePRS.zip", true)] + [InlineData("fiveprs-0.9.0-ptb.2.zip", true)] + [InlineData("fiveprs-1.2.3.zip", true)] + [InlineData("fiveprs-latest.zip", false)] + [InlineData("fiveprs_addons-0.9.0-ptb.2.zip", false)] + [InlineData("fiveprs-0.9.0.tar.gz", false)] + [InlineData("fiveprs-.zip", false)] + public void IsAsset_MatchesPlainAndVersionedNames(string fileName, bool expected) + { + Assert.Equal(expected, ReleaseFeed.IsAsset(fileName, "fiveprs.zip")); + } + [Fact] public void Latest_CanIncludePreReleases() { diff --git a/FivePRS.sln b/FivePRS.sln index e508005..cb38e33 100644 --- a/FivePRS.sln +++ b/FivePRS.sln @@ -13,34 +13,112 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FivePRS.Police", "FivePRS.P EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FivePRS.Tests", "FivePRS.Tests\FivePRS.Tests.csproj", "{D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Stubs", "Stubs", "{CF16BC1C-BDEA-B3AA-CE85-637DF72D6D3F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Windows", "Stubs\Windows\Windows.csproj", "{C5BC7A06-66B9-4AED-858F-31880EAF2B03}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.SDK.NET", "Stubs\Microsoft.Windows.SDK.NET\Microsoft.Windows.SDK.NET.csproj", "{C341AFE3-CE49-42AE-92A5-4D19E5047AC6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {11111111-1111-1111-1111-111111111111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {11111111-1111-1111-1111-111111111111}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11111111-1111-1111-1111-111111111111}.Debug|x64.ActiveCfg = Debug|Any CPU + {11111111-1111-1111-1111-111111111111}.Debug|x64.Build.0 = Debug|Any CPU + {11111111-1111-1111-1111-111111111111}.Debug|x86.ActiveCfg = Debug|Any CPU + {11111111-1111-1111-1111-111111111111}.Debug|x86.Build.0 = Debug|Any CPU {11111111-1111-1111-1111-111111111111}.Release|Any CPU.ActiveCfg = Release|Any CPU {11111111-1111-1111-1111-111111111111}.Release|Any CPU.Build.0 = Release|Any CPU + {11111111-1111-1111-1111-111111111111}.Release|x64.ActiveCfg = Release|Any CPU + {11111111-1111-1111-1111-111111111111}.Release|x64.Build.0 = Release|Any CPU + {11111111-1111-1111-1111-111111111111}.Release|x86.ActiveCfg = Release|Any CPU + {11111111-1111-1111-1111-111111111111}.Release|x86.Build.0 = Release|Any CPU {22222222-2222-2222-2222-222222222222}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {22222222-2222-2222-2222-222222222222}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22222222-2222-2222-2222-222222222222}.Debug|x64.ActiveCfg = Debug|Any CPU + {22222222-2222-2222-2222-222222222222}.Debug|x64.Build.0 = Debug|Any CPU + {22222222-2222-2222-2222-222222222222}.Debug|x86.ActiveCfg = Debug|Any CPU + {22222222-2222-2222-2222-222222222222}.Debug|x86.Build.0 = Debug|Any CPU {22222222-2222-2222-2222-222222222222}.Release|Any CPU.ActiveCfg = Release|Any CPU {22222222-2222-2222-2222-222222222222}.Release|Any CPU.Build.0 = Release|Any CPU + {22222222-2222-2222-2222-222222222222}.Release|x64.ActiveCfg = Release|Any CPU + {22222222-2222-2222-2222-222222222222}.Release|x64.Build.0 = Release|Any CPU + {22222222-2222-2222-2222-222222222222}.Release|x86.ActiveCfg = Release|Any CPU + {22222222-2222-2222-2222-222222222222}.Release|x86.Build.0 = Release|Any CPU {33333333-3333-3333-3333-333333333333}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {33333333-3333-3333-3333-333333333333}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33333333-3333-3333-3333-333333333333}.Debug|x64.ActiveCfg = Debug|Any CPU + {33333333-3333-3333-3333-333333333333}.Debug|x64.Build.0 = Debug|Any CPU + {33333333-3333-3333-3333-333333333333}.Debug|x86.ActiveCfg = Debug|Any CPU + {33333333-3333-3333-3333-333333333333}.Debug|x86.Build.0 = Debug|Any CPU {33333333-3333-3333-3333-333333333333}.Release|Any CPU.ActiveCfg = Release|Any CPU {33333333-3333-3333-3333-333333333333}.Release|Any CPU.Build.0 = Release|Any CPU + {33333333-3333-3333-3333-333333333333}.Release|x64.ActiveCfg = Release|Any CPU + {33333333-3333-3333-3333-333333333333}.Release|x64.Build.0 = Release|Any CPU + {33333333-3333-3333-3333-333333333333}.Release|x86.ActiveCfg = Release|Any CPU + {33333333-3333-3333-3333-333333333333}.Release|x86.Build.0 = Release|Any CPU {44444444-4444-4444-4444-444444444444}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {44444444-4444-4444-4444-444444444444}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44444444-4444-4444-4444-444444444444}.Debug|x64.ActiveCfg = Debug|Any CPU + {44444444-4444-4444-4444-444444444444}.Debug|x64.Build.0 = Debug|Any CPU + {44444444-4444-4444-4444-444444444444}.Debug|x86.ActiveCfg = Debug|Any CPU + {44444444-4444-4444-4444-444444444444}.Debug|x86.Build.0 = Debug|Any CPU {44444444-4444-4444-4444-444444444444}.Release|Any CPU.ActiveCfg = Release|Any CPU {44444444-4444-4444-4444-444444444444}.Release|Any CPU.Build.0 = Release|Any CPU + {44444444-4444-4444-4444-444444444444}.Release|x64.ActiveCfg = Release|Any CPU + {44444444-4444-4444-4444-444444444444}.Release|x64.Build.0 = Release|Any CPU + {44444444-4444-4444-4444-444444444444}.Release|x86.ActiveCfg = Release|Any CPU + {44444444-4444-4444-4444-444444444444}.Release|x86.Build.0 = Release|Any CPU {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Debug|x64.ActiveCfg = Debug|Any CPU + {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Debug|x64.Build.0 = Debug|Any CPU + {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Debug|x86.ActiveCfg = Debug|Any CPU + {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Debug|x86.Build.0 = Debug|Any CPU {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Release|Any CPU.ActiveCfg = Release|Any CPU {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Release|Any CPU.Build.0 = Release|Any CPU + {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Release|x64.ActiveCfg = Release|Any CPU + {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Release|x64.Build.0 = Release|Any CPU + {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Release|x86.ActiveCfg = Release|Any CPU + {D0BF8CC2-F146-45FA-8EBD-B46E236B0B26}.Release|x86.Build.0 = Release|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Debug|x64.ActiveCfg = Debug|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Debug|x64.Build.0 = Debug|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Debug|x86.ActiveCfg = Debug|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Debug|x86.Build.0 = Debug|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Release|Any CPU.Build.0 = Release|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Release|x64.ActiveCfg = Release|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Release|x64.Build.0 = Release|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Release|x86.ActiveCfg = Release|Any CPU + {C5BC7A06-66B9-4AED-858F-31880EAF2B03}.Release|x86.Build.0 = Release|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Debug|x64.ActiveCfg = Debug|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Debug|x64.Build.0 = Debug|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Debug|x86.ActiveCfg = Debug|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Debug|x86.Build.0 = Debug|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Release|Any CPU.Build.0 = Release|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Release|x64.ActiveCfg = Release|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Release|x64.Build.0 = Release|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Release|x86.ActiveCfg = Release|Any CPU + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C5BC7A06-66B9-4AED-858F-31880EAF2B03} = {CF16BC1C-BDEA-B3AA-CE85-637DF72D6D3F} + {C341AFE3-CE49-42AE-92A5-4D19E5047AC6} = {CF16BC1C-BDEA-B3AA-CE85-637DF72D6D3F} + EndGlobalSection EndGlobal diff --git a/README.md b/README.md index 8799ece..e9ba85e 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ Admin commands work from the server console or in game with `fiveprs.admin`: | Command | Description | |---|---| | `fprs_units` | List on-duty units and their status | +| `fiveprs_diag` | Print the version, platform, database, OneSync, addons and any warnings; paste it into bug reports | | `fprs_setrank ` | Set a player's rank | | `fprs_addxp ` | Grant XP | | `fprs_setdept ` | Move a player to a department | @@ -233,6 +234,5 @@ The original model and clothing are restored when going off duty, but freemode f Duty changes, department changes, XP awards, rank-ups, admin actions and denied permission checks are recorded in the `fiveprs_audit` table. ## Troubleshooting -**`Could not load assembly Windows` / `Microsoft.Windows.SDK.NET` stack traces on start.** These appear once each time the resource starts with SQLite and are harmless. `Microsoft.Data.Sqlite` checks whether it is running as a Windows Store app by looking for those assemblies; FiveM logs each failed lookup with a full stack trace, then SQLite carries on normally. Startup succeeded if `[FivePRS] Database (SQLite) ready.` follows them. MySQL does not produce these messages. **`Could not load native SQLite` or `DllNotFoundException: e_sqlite3`.** The resource's `server/` folder must contain `e_sqlite3.dll` (Windows) or `libe_sqlite3.so` (Linux). Re-extract `fiveprs.zip` rather than copying individual DLLs. diff --git a/Stubs/Microsoft.Windows.SDK.NET/Microsoft.Windows.SDK.NET.csproj b/Stubs/Microsoft.Windows.SDK.NET/Microsoft.Windows.SDK.NET.csproj new file mode 100644 index 0000000..c1f0ab8 --- /dev/null +++ b/Stubs/Microsoft.Windows.SDK.NET/Microsoft.Windows.SDK.NET.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.0 + Microsoft.Windows.SDK.NET + Microsoft.Windows.SDK.NET + false + none + false + $(MSBuildThisFileDirectory)..\..\bin\server\ + + + diff --git a/Stubs/Windows/Windows.csproj b/Stubs/Windows/Windows.csproj new file mode 100644 index 0000000..095a70a --- /dev/null +++ b/Stubs/Windows/Windows.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.0 + Windows + Windows + false + none + false + $(MSBuildThisFileDirectory)..\..\bin\server\ + + + diff --git a/fxmanifest.lua b/fxmanifest.lua index fe1e818..83a4702 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -6,7 +6,7 @@ author 'Pixel ' description 'The Unified Public Response Framework for FiveM.' repository 'https://github.com/FivePRS/core' license 'AGPL-3.0-or-later' -version '0.9.0-ptb.1' +version '0.9.0-ptb.2' lua54 'yes'