mirror of
https://github.com/9ParsonsB/Pulsar.git
synced 2025-04-05 17:39:39 -04:00
Update Status, Power now look nice, also shows est refuel time
Status now shows alerts when taking damage JournalService support more journals Added enums to frontend, not quite working Added More examples to Explorer component
This commit is contained in:
parent
bd811c861c
commit
2ac1a927ca
Pulsar
Features/Journal
Utils
WebApp
.vscode
src
lib
routes
types/api
@ -10,7 +10,8 @@ public class JournalService(
|
||||
ILogger<JournalService> logger,
|
||||
IOptions<PulsarConfiguration> options,
|
||||
IEventHubContext hub,
|
||||
PulsarContext context
|
||||
PulsarContext context,
|
||||
IServiceProvider serviceProvider
|
||||
) : IJournalService
|
||||
{
|
||||
public string FileName => FileHandlerService.JournalLogFileName;
|
||||
@ -32,7 +33,7 @@ public class JournalService(
|
||||
new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
Converters = { new JournalConverter(logger) }
|
||||
Converters = { ActivatorUtilities.CreateInstance<JournalConverter>(serviceProvider) }
|
||||
}));
|
||||
|
||||
foreach (var journal in select)
|
||||
|
@ -1,26 +0,0 @@
|
||||
namespace Pulsar.Utils;
|
||||
|
||||
public sealed class HttpClient
|
||||
{
|
||||
private HttpClient()
|
||||
{ }
|
||||
|
||||
private static readonly Lazy<System.Net.Http.HttpClient> lazy = new Lazy<System.Net.Http.HttpClient>(() => new System.Net.Http.HttpClient());
|
||||
|
||||
public static System.Net.Http.HttpClient Client => lazy.Value;
|
||||
|
||||
public static string GetString(string url)
|
||||
{
|
||||
return lazy.Value.GetStringAsync(url).Result;
|
||||
}
|
||||
|
||||
public static HttpResponseMessage SendRequest(HttpRequestMessage request)
|
||||
{
|
||||
return lazy.Value.SendAsync(request).Result;
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> SendRequestAsync(HttpRequestMessage request)
|
||||
{
|
||||
return lazy.Value.SendAsync(request);
|
||||
}
|
||||
}
|
@ -288,6 +288,59 @@ public class JournalConverter(ILogger logger) : JsonConverter<JournalBase>
|
||||
return JsonSerializer.Deserialize<MaterialDiscovered>(ref reader)!;
|
||||
case "storedships":
|
||||
return JsonSerializer.Deserialize<StoredShips>(ref reader)!;
|
||||
case "scanorganic":
|
||||
return JsonSerializer.Deserialize<ScanOrganic>(ref reader)!;
|
||||
case "market":
|
||||
return JsonSerializer.Deserialize<Market>(ref reader)!;
|
||||
case "missioncompleted":
|
||||
return JsonSerializer.Deserialize<MissionCompleted>(ref reader)!;
|
||||
case "sellshiponrebuy":
|
||||
return JsonSerializer.Deserialize<SellShipOnRebuy>(ref reader)!;
|
||||
case "missionaccepted":
|
||||
return JsonSerializer.Deserialize<MissionAccepted>(ref reader)!;
|
||||
case "approachsettlement":
|
||||
return JsonSerializer.Deserialize<ApproachSettlement>(ref reader)!;
|
||||
case "screenshot":
|
||||
return JsonSerializer.Deserialize<Screenshot>(ref reader)!;
|
||||
case "moduleswap":
|
||||
return JsonSerializer.Deserialize<ModuleSwap>(ref reader)!;
|
||||
case "underattack":
|
||||
return JsonSerializer.Deserialize<UnderAttack>(ref reader)!;
|
||||
case "datascanned":
|
||||
return JsonSerializer.Deserialize<DataScanned>(ref reader)!;
|
||||
case "dockingdenied":
|
||||
return JsonSerializer.Deserialize<DockingDenied>(ref reader)!;
|
||||
case "fetchremotemodule":
|
||||
return JsonSerializer.Deserialize<FetchRemoteModule>(ref reader)!;
|
||||
case "engineercontribution":
|
||||
return JsonSerializer.Deserialize<EngineerContribution>(ref reader)!;
|
||||
case "collectcargo":
|
||||
return JsonSerializer.Deserialize<CollectCargo>(ref reader)!;
|
||||
case "moduleretrieve":
|
||||
return JsonSerializer.Deserialize<ModuleRetrieve>(ref reader)!;
|
||||
case "marketbuy":
|
||||
return JsonSerializer.Deserialize<MarketBuy>(ref reader)!;
|
||||
case "selldrones":
|
||||
return JsonSerializer.Deserialize<SellDrones>(ref reader)!;
|
||||
case "interdicted":
|
||||
return JsonSerializer.Deserialize<Interdicted>(ref reader)!;
|
||||
case "sellorganicdata":
|
||||
return JsonSerializer.Deserialize<SellOrganicData>(ref reader)!;
|
||||
case "wingadd":
|
||||
return JsonSerializer.Deserialize<WingAdd>(ref reader)!;
|
||||
case "winginvite":
|
||||
return JsonSerializer.Deserialize<WingInvite>(ref reader)!;
|
||||
case "wingjoin":
|
||||
return JsonSerializer.Deserialize<WingJoin>(ref reader)!;
|
||||
case "wingleave":
|
||||
return JsonSerializer.Deserialize<WingLeave>(ref reader)!;
|
||||
case "bounty":
|
||||
return JsonSerializer.Deserialize<Bounty>(ref reader)!;
|
||||
case "commitcrime":
|
||||
return JsonSerializer.Deserialize<CommitCrime>(ref reader)!;
|
||||
case "modulestore":
|
||||
return JsonSerializer.Deserialize<ModuleStore>(ref reader)!;
|
||||
|
||||
default:
|
||||
logger.LogWarning("Unknown Journal event type {EventName}", eventName);
|
||||
return JsonSerializer.Deserialize<JournalBase>(ref reader)!;
|
||||
|
21
Pulsar/WebApp/.vscode/launch.json
vendored
Normal file
21
Pulsar/WebApp/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "npm dev",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": [
|
||||
"run-script",
|
||||
"dev"
|
||||
],
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -18,14 +18,14 @@
|
||||
|
||||
<section>
|
||||
<div class="title">
|
||||
<h1>Journals</h1>
|
||||
<h1>Live Journals</h1>
|
||||
</div>
|
||||
<button
|
||||
onclick={() => {
|
||||
fetch("http://localhost:5000/api/journal");
|
||||
}}
|
||||
>
|
||||
Refresh (debug)
|
||||
Fetch All (debug)
|
||||
</button>
|
||||
<ul>
|
||||
{#each values as value (value.timestamp + value.event)}
|
||||
|
@ -2,18 +2,65 @@
|
||||
import { onMount } from "svelte";
|
||||
import { statusStore } from "./stores/Status.store";
|
||||
import connection from "./stores/Connection.store";
|
||||
import { StatusFlags, StatusFlags2 } from "../types/api/enums";
|
||||
import type JournalBase from "../types/api/JournalBase";
|
||||
import { slide } from "svelte/transition";
|
||||
|
||||
const x: string | null = $state(null);
|
||||
|
||||
const last: number[] = $state([]);
|
||||
let timeToMax = $state(0);
|
||||
|
||||
let loading = $state(true);
|
||||
|
||||
let alert: JournalBase[] = $state([]);
|
||||
|
||||
onMount(async () => {
|
||||
await $connection.start();
|
||||
|
||||
loading = false;
|
||||
|
||||
$connection.on("StatusUpdated", (message) => {
|
||||
statusStore.update((s) => {
|
||||
return { ...s, ...message };
|
||||
});
|
||||
|
||||
// only 3 in array
|
||||
if (last.length >= 3) {
|
||||
last.shift();
|
||||
}
|
||||
last.push(message.fuel?.fuelMain ?? 0);
|
||||
|
||||
const change = [];
|
||||
for (let i = last.length - 1; i === 0; i--) {
|
||||
change.push(last[i] - last[i - 1]);
|
||||
}
|
||||
|
||||
const avg = change.reduce((a, b) => a + b, 0) / change.length;
|
||||
const max = 32;
|
||||
if ($statusStore.fuel?.fuelMain) {
|
||||
timeToMax = (max - $statusStore.fuel?.fuelMain) / avg;
|
||||
}
|
||||
|
||||
console.log($statusStore);
|
||||
});
|
||||
|
||||
$connection.on("JournalUpdated", (message) => {
|
||||
const journals = message as JournalBase[];
|
||||
const targetEvents = ["HullDamage", "UnderAttack"];
|
||||
const events = journals.filter((j) =>
|
||||
targetEvents.find((t) => t.toLowerCase() === j.event.toLowerCase())
|
||||
);
|
||||
if (events.length) {
|
||||
alert = events;
|
||||
}
|
||||
});
|
||||
|
||||
if (!$statusStore.pips) {
|
||||
statusStore.set(
|
||||
await (await fetch("http://localhost:5000/api/status")).json()
|
||||
);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -21,14 +68,48 @@
|
||||
|
||||
<br />
|
||||
|
||||
{#if loading}
|
||||
<h1>LOADING ....</h1>
|
||||
{/if}
|
||||
|
||||
{#if alert.length}
|
||||
<h1>Alert!</h1>
|
||||
|
||||
{#each alert as a}
|
||||
<input readonly value={JSON.stringify(a)} />
|
||||
{/each}
|
||||
<button onclick={() => (alert = [])}>Clear</button>
|
||||
{/if}
|
||||
|
||||
<div>
|
||||
{#if $statusStore}
|
||||
<span>Fuel%: {(($statusStore.fuel?.fuelMain ?? 0) / 32) * 100}%</span>
|
||||
<span
|
||||
>Sys: {$statusStore?.pips?.sys ?? "?"} Eng: {$statusStore?.pips?.eng ??
|
||||
"?"} Wep:
|
||||
{$statusStore?.pips?.wep ?? "?"}</span
|
||||
>Fuel%: {(($statusStore.fuel?.fuelMain ?? 0) / 32) * 100}% est: {timeToMax}s</span
|
||||
>
|
||||
<div class="power">
|
||||
<div class="sys">
|
||||
{#each [...Array($statusStore?.pips?.sys ?? 0)] as sys}
|
||||
<div class="pip" transition:slide></div>
|
||||
{/each}
|
||||
<div>{$statusStore?.pips?.sys ?? "?"}</div>
|
||||
<div>Sys</div>
|
||||
</div>
|
||||
<div class="eng">
|
||||
{#each [...Array($statusStore?.pips?.eng ?? 0)] as eng}
|
||||
<div class="pip" transition:slide></div>
|
||||
{/each}
|
||||
<div>{$statusStore?.pips?.eng ?? "?"}</div>
|
||||
<div>Eng</div>
|
||||
</div>
|
||||
<div class="wep">
|
||||
{#each [...Array($statusStore?.pips?.wep ?? 0)] as wep}
|
||||
<div class="pip" transition:slide></div>
|
||||
{/each}
|
||||
<div>{$statusStore?.pips?.wep ?? "?"}</div>
|
||||
<div>Wep</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span>dest?: {$statusStore?.destination?.name}</span>
|
||||
<span>gui focus: {$statusStore.guiFocus}</span>
|
||||
<span>cargo: {$statusStore.cargo}</span>
|
||||
@ -39,9 +120,34 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="scss">
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
.power {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
align-items: flex-end;
|
||||
div {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
div.pip {
|
||||
min-width: 2vw;
|
||||
min-height: 1vh;
|
||||
background-color: #d06527;
|
||||
border: 1px solid #96491c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
@ -33,5 +33,6 @@
|
||||
div {
|
||||
flex: 50%;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,11 +1,34 @@
|
||||
<script lang="ts">
|
||||
const data: unknown[] = [{}, {}, {}, {}];
|
||||
// number of scans completed
|
||||
const scanned = 2;
|
||||
// total bodies in the current system (FSSDiscovery event)
|
||||
const totalBodies = 12;
|
||||
// accumulated list of bodies in the current system (Scan events)
|
||||
const bodies = $state([
|
||||
{ value: 50 },
|
||||
{ value: 1000 },
|
||||
{ value: 800000 },
|
||||
{ value: 800000 },
|
||||
]);
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<div class="title">
|
||||
<h1>Explorer</h1>
|
||||
</div>
|
||||
<!-- summary & high value targets -->
|
||||
<h1>Bodies</h1>
|
||||
Scan: <span>{scanned}</span>/<span>{totalBodies}</span>
|
||||
<div class="title">High Value (>500kcr)</div>
|
||||
<ol>
|
||||
{#each bodies.filter((b) => b.value > 500000) as body}
|
||||
<li>[HMC/WW/ELT/ELN] $body.name - {body.value}cr</li>
|
||||
{/each}
|
||||
</ol>
|
||||
<br />
|
||||
<br />
|
||||
<!-- Full system data -->
|
||||
<div class="box">
|
||||
{#each data as row}
|
||||
<div class="group">
|
||||
|
4
Pulsar/WebApp/src/types/api/JournalBase.ts
Normal file
4
Pulsar/WebApp/src/types/api/JournalBase.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export default interface JournalBase {
|
||||
event: string;
|
||||
timestamp: Date;
|
||||
}
|
@ -1,16 +1,22 @@
|
||||
import type Destination from "./Destination";
|
||||
import type Fuel from "./Fuel";
|
||||
import type JournalBase from "./JournalBase";
|
||||
import type {
|
||||
FocusStatus,
|
||||
LegalStatus,
|
||||
StatusFlags,
|
||||
StatusFlags2,
|
||||
} from "./enums";
|
||||
|
||||
export default interface Status extends JournalBase {
|
||||
event: "Status";
|
||||
flags: number;
|
||||
flags2: number;
|
||||
flags: StatusFlags;
|
||||
flags2: StatusFlags2;
|
||||
pips: { eng: number; sys: number; wep: number };
|
||||
guiFocus: number;
|
||||
guiFocus: FocusStatus;
|
||||
fuel: Fuel;
|
||||
cargo: number;
|
||||
legalState: string;
|
||||
legalState: LegalStatus;
|
||||
balance: number;
|
||||
destination: Destination;
|
||||
FireGroup: number;
|
||||
|
82
Pulsar/WebApp/src/types/api/enums.ts
Normal file
82
Pulsar/WebApp/src/types/api/enums.ts
Normal file
@ -0,0 +1,82 @@
|
||||
export enum StatusFlags {
|
||||
Docked = 1,
|
||||
Landed = 1 << 1,
|
||||
LandingGear = 1 << 2,
|
||||
Shields = 1 << 3,
|
||||
Supercruise = 1 << 4,
|
||||
FAOff = 1 << 5,
|
||||
Hardpoints = 1 << 6,
|
||||
Wing = 1 << 7,
|
||||
Lights = 1 << 8,
|
||||
CargoScoop = 1 << 9,
|
||||
SilentRunning = 1 << 10,
|
||||
FuelScooping = 1 << 11,
|
||||
SRVBrake = 1 << 12,
|
||||
SRVTurret = 1 << 13,
|
||||
SRVProximity = 1 << 14,
|
||||
SRVDriveAssist = 1 << 15,
|
||||
Masslock = 1 << 16,
|
||||
FSDCharging = 1 << 17,
|
||||
FSDCooldown = 1 << 18,
|
||||
LowFuel = 1 << 19,
|
||||
Overheat = 1 << 20,
|
||||
LatLongValid = 1 << 21,
|
||||
InDanger = 1 << 22,
|
||||
Interdiction = 1 << 23,
|
||||
MainShip = 1 << 24,
|
||||
Fighter = 1 << 25,
|
||||
SRV = 1 << 26,
|
||||
AnalysisHUD = 1 << 27,
|
||||
NightVision = 1 << 28,
|
||||
RadialAltitude = 1 << 29,
|
||||
FSDJump = 1 << 30,
|
||||
SRVHighBeam = 1 << 31,
|
||||
}
|
||||
|
||||
export enum StatusFlags2 {
|
||||
OnFoot = 1,
|
||||
InTaxi = 1 << 1,
|
||||
InMulticrew = 1 << 2,
|
||||
OnFootInStation = 1 << 3,
|
||||
OnFootOnPlanet = 1 << 4,
|
||||
AimDownSight = 1 << 5,
|
||||
LowOxygen = 1 << 6,
|
||||
LowHealth = 1 << 7,
|
||||
Cold = 1 << 8,
|
||||
Hot = 1 << 9,
|
||||
VeryCold = 1 << 10,
|
||||
VeryHot = 1 << 11,
|
||||
GlideMode = 1 << 12,
|
||||
OnFootInHangar = 1 << 13,
|
||||
OnFootInSocialSpace = 1 << 14,
|
||||
OnFootExterior = 1 << 15,
|
||||
BreathableAtmosphere = 1 << 16,
|
||||
TelepresenceMulticrew = 1 << 17,
|
||||
PhysicalMulticrew = 1 << 18,
|
||||
FsdHyperdriveCharging = 1 << 19,
|
||||
}
|
||||
|
||||
export type LegalStatus =
|
||||
| "Clean"
|
||||
| "IllegalCargo"
|
||||
| "Speeding"
|
||||
| "Wanted"
|
||||
| "Hostile"
|
||||
| "PassengerWanted"
|
||||
| "Warrant"
|
||||
| "Thargoid";
|
||||
|
||||
export enum FocusStatus {
|
||||
NoFocus = 0,
|
||||
InternalPanel = 1,
|
||||
ExternalPanel = 2,
|
||||
CommsPanel = 3,
|
||||
RolePanel = 4,
|
||||
StationServices = 5,
|
||||
GalaxyMap = 6,
|
||||
SystemMap = 7,
|
||||
Orrery = 8,
|
||||
FSS = 9,
|
||||
SAA = 10,
|
||||
Codex = 11,
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user