F8-05 — game-mode chrome cleanup + inspector compact rows #66
@@ -733,6 +733,7 @@ func (c *Cache) otherGroup(v *mr.OtherGroup, sg *game.ShipGroup, st *game.ShipTy
|
|||||||
}
|
}
|
||||||
v.Speed = mr.F(sg.Speed(st))
|
v.Speed = mr.F(sg.Speed(st))
|
||||||
v.Mass = mr.F(st.EmptyMass())
|
v.Mass = mr.F(st.EmptyMass())
|
||||||
|
v.Race = c.g.Race[c.RaceIndex(sg.OwnerID)].Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) localPlanet(v *mr.LocalPlanet, p *game.Planet) {
|
func (c *Cache) localPlanet(v *mr.LocalPlanet, p *game.Planet) {
|
||||||
|
|||||||
@@ -52,6 +52,13 @@ type OtherGroup struct {
|
|||||||
Range *Float `json:"range,omitempty"`
|
Range *Float `json:"range,omitempty"`
|
||||||
Speed Float `json:"speed"`
|
Speed Float `json:"speed"`
|
||||||
Mass Float `json:"mass"`
|
Mass Float `json:"mass"`
|
||||||
|
// Race is the owner's display name resolved from `sg.OwnerID`
|
||||||
|
// (or, for legacy reports, the section header that introduced
|
||||||
|
// the row). The local race fills this in for its own
|
||||||
|
// `LocalGroup` copies via the embedded `OtherGroup` field so
|
||||||
|
// every group carries an authoritative attribution rather than a
|
||||||
|
// "foreign" fallback heuristic at render time.
|
||||||
|
Race string `json:"race,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnidentifiedGroup struct {
|
type UnidentifiedGroup struct {
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ table OtherGroup {
|
|||||||
range:float32 = null;
|
range:float32 = null;
|
||||||
speed:float32;
|
speed:float32;
|
||||||
mass:float32;
|
mass:float32;
|
||||||
|
race:string;
|
||||||
}
|
}
|
||||||
|
|
||||||
table LocalGroup {
|
table LocalGroup {
|
||||||
@@ -184,6 +185,7 @@ table LocalGroup {
|
|||||||
id:common.UUID (required);
|
id:common.UUID (required);
|
||||||
state:string;
|
state:string;
|
||||||
fleet:string;
|
fleet:string;
|
||||||
|
race:string;
|
||||||
}
|
}
|
||||||
|
|
||||||
table LocalFleet {
|
table LocalFleet {
|
||||||
|
|||||||
@@ -194,8 +194,16 @@ func (rcv *LocalGroup) Fleet() []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rcv *LocalGroup) Race() []byte {
|
||||||
|
o := flatbuffers.UOffsetT(rcv._tab.Offset(30))
|
||||||
|
if o != 0 {
|
||||||
|
return rcv._tab.ByteVector(o + rcv._tab.Pos)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func LocalGroupStart(builder *flatbuffers.Builder) {
|
func LocalGroupStart(builder *flatbuffers.Builder) {
|
||||||
builder.StartObject(13)
|
builder.StartObject(14)
|
||||||
}
|
}
|
||||||
func LocalGroupAddNumber(builder *flatbuffers.Builder, number uint64) {
|
func LocalGroupAddNumber(builder *flatbuffers.Builder, number uint64) {
|
||||||
builder.PrependUint64Slot(0, number, 0)
|
builder.PrependUint64Slot(0, number, 0)
|
||||||
@@ -241,6 +249,9 @@ func LocalGroupAddState(builder *flatbuffers.Builder, state flatbuffers.UOffsetT
|
|||||||
func LocalGroupAddFleet(builder *flatbuffers.Builder, fleet flatbuffers.UOffsetT) {
|
func LocalGroupAddFleet(builder *flatbuffers.Builder, fleet flatbuffers.UOffsetT) {
|
||||||
builder.PrependUOffsetTSlot(12, flatbuffers.UOffsetT(fleet), 0)
|
builder.PrependUOffsetTSlot(12, flatbuffers.UOffsetT(fleet), 0)
|
||||||
}
|
}
|
||||||
|
func LocalGroupAddRace(builder *flatbuffers.Builder, race flatbuffers.UOffsetT) {
|
||||||
|
builder.PrependUOffsetTSlot(13, flatbuffers.UOffsetT(race), 0)
|
||||||
|
}
|
||||||
func LocalGroupEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
func LocalGroupEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||||
return builder.EndObject()
|
return builder.EndObject()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,8 +163,16 @@ func (rcv *OtherGroup) MutateMass(n float32) bool {
|
|||||||
return rcv._tab.MutateFloat32Slot(22, n)
|
return rcv._tab.MutateFloat32Slot(22, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rcv *OtherGroup) Race() []byte {
|
||||||
|
o := flatbuffers.UOffsetT(rcv._tab.Offset(24))
|
||||||
|
if o != 0 {
|
||||||
|
return rcv._tab.ByteVector(o + rcv._tab.Pos)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func OtherGroupStart(builder *flatbuffers.Builder) {
|
func OtherGroupStart(builder *flatbuffers.Builder) {
|
||||||
builder.StartObject(10)
|
builder.StartObject(11)
|
||||||
}
|
}
|
||||||
func OtherGroupAddNumber(builder *flatbuffers.Builder, number uint64) {
|
func OtherGroupAddNumber(builder *flatbuffers.Builder, number uint64) {
|
||||||
builder.PrependUint64Slot(0, number, 0)
|
builder.PrependUint64Slot(0, number, 0)
|
||||||
@@ -201,6 +209,9 @@ func OtherGroupAddSpeed(builder *flatbuffers.Builder, speed float32) {
|
|||||||
func OtherGroupAddMass(builder *flatbuffers.Builder, mass float32) {
|
func OtherGroupAddMass(builder *flatbuffers.Builder, mass float32) {
|
||||||
builder.PrependFloat32Slot(9, mass, 0.0)
|
builder.PrependFloat32Slot(9, mass, 0.0)
|
||||||
}
|
}
|
||||||
|
func OtherGroupAddRace(builder *flatbuffers.Builder, race flatbuffers.UOffsetT) {
|
||||||
|
builder.PrependUOffsetTSlot(10, flatbuffers.UOffsetT(race), 0)
|
||||||
|
}
|
||||||
func OtherGroupEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
func OtherGroupEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||||
return builder.EndObject()
|
return builder.EndObject()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -513,6 +513,7 @@ func encodeReportLocalGroup(builder *flatbuffers.Builder, group *model.LocalGrou
|
|||||||
class := builder.CreateString(group.Class)
|
class := builder.CreateString(group.Class)
|
||||||
cargo := builder.CreateString(group.Cargo)
|
cargo := builder.CreateString(group.Cargo)
|
||||||
state := builder.CreateString(group.State)
|
state := builder.CreateString(group.State)
|
||||||
|
race := builder.CreateString(group.Race)
|
||||||
|
|
||||||
tech := encodeReportTechEntryVector(builder, group.Tech)
|
tech := encodeReportTechEntryVector(builder, group.Tech)
|
||||||
var fleet flatbuffers.UOffsetT
|
var fleet flatbuffers.UOffsetT
|
||||||
@@ -544,6 +545,7 @@ func encodeReportLocalGroup(builder *flatbuffers.Builder, group *model.LocalGrou
|
|||||||
if group.Fleet != nil {
|
if group.Fleet != nil {
|
||||||
fbs.LocalGroupAddFleet(builder, fleet)
|
fbs.LocalGroupAddFleet(builder, fleet)
|
||||||
}
|
}
|
||||||
|
fbs.LocalGroupAddRace(builder, race)
|
||||||
return fbs.LocalGroupEnd(builder)
|
return fbs.LocalGroupEnd(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,6 +553,7 @@ func encodeReportOtherGroup(builder *flatbuffers.Builder, group *model.OtherGrou
|
|||||||
class := builder.CreateString(group.Class)
|
class := builder.CreateString(group.Class)
|
||||||
cargo := builder.CreateString(group.Cargo)
|
cargo := builder.CreateString(group.Cargo)
|
||||||
tech := encodeReportTechEntryVector(builder, group.Tech)
|
tech := encodeReportTechEntryVector(builder, group.Tech)
|
||||||
|
race := builder.CreateString(group.Race)
|
||||||
|
|
||||||
fbs.OtherGroupStart(builder)
|
fbs.OtherGroupStart(builder)
|
||||||
fbs.OtherGroupAddNumber(builder, uint64(group.Number))
|
fbs.OtherGroupAddNumber(builder, uint64(group.Number))
|
||||||
@@ -569,6 +572,7 @@ func encodeReportOtherGroup(builder *flatbuffers.Builder, group *model.OtherGrou
|
|||||||
}
|
}
|
||||||
fbs.OtherGroupAddSpeed(builder, reportFloatToFBS(group.Speed))
|
fbs.OtherGroupAddSpeed(builder, reportFloatToFBS(group.Speed))
|
||||||
fbs.OtherGroupAddMass(builder, reportFloatToFBS(group.Mass))
|
fbs.OtherGroupAddMass(builder, reportFloatToFBS(group.Mass))
|
||||||
|
fbs.OtherGroupAddRace(builder, race)
|
||||||
return fbs.OtherGroupEnd(builder)
|
return fbs.OtherGroupEnd(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1134,6 +1138,7 @@ func decodeReportLocalGroupVector(flatReport *fbs.Report, result *model.Report)
|
|||||||
Destination: destination,
|
Destination: destination,
|
||||||
Speed: reportFloatFromFBS(item.Speed()),
|
Speed: reportFloatFromFBS(item.Speed()),
|
||||||
Mass: reportFloatFromFBS(item.Mass()),
|
Mass: reportFloatFromFBS(item.Mass()),
|
||||||
|
Race: string(item.Race()),
|
||||||
},
|
},
|
||||||
ID: uuidFromHiLo(id.Hi(), id.Lo()),
|
ID: uuidFromHiLo(id.Hi(), id.Lo()),
|
||||||
State: string(item.State()),
|
State: string(item.State()),
|
||||||
@@ -1196,6 +1201,7 @@ func decodeReportOtherGroupVector(flatReport *fbs.Report, result *model.Report)
|
|||||||
Destination: destination,
|
Destination: destination,
|
||||||
Speed: reportFloatFromFBS(item.Speed()),
|
Speed: reportFloatFromFBS(item.Speed()),
|
||||||
Mass: reportFloatFromFBS(item.Mass()),
|
Mass: reportFloatFromFBS(item.Mass()),
|
||||||
|
Race: string(item.Race()),
|
||||||
}
|
}
|
||||||
|
|
||||||
if origin := item.Origin(); origin != nil {
|
if origin := item.Origin(); origin != nil {
|
||||||
|
|||||||
@@ -352,6 +352,7 @@ func sampleReport() *model.Report {
|
|||||||
Range: &rangeB,
|
Range: &rangeB,
|
||||||
Speed: model.Float(2.5),
|
Speed: model.Float(2.5),
|
||||||
Mass: model.Float(12.0),
|
Mass: model.Float(12.0),
|
||||||
|
Race: "Earthlings",
|
||||||
},
|
},
|
||||||
ID: uuid.MustParse("33333333-3333-3333-3333-333333333333"),
|
ID: uuid.MustParse("33333333-3333-3333-3333-333333333333"),
|
||||||
State: "in_orbit",
|
State: "in_orbit",
|
||||||
@@ -359,7 +360,7 @@ func sampleReport() *model.Report {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
OtherGroup: []model.OtherGroup{
|
OtherGroup: []model.OtherGroup{
|
||||||
{Number: 2, Class: "scout", Tech: map[string]model.Float{"CARGO": model.Float(1.25), "DRIVE": model.Float(1.75)}, Cargo: "CAP", Load: model.Float(3.5), Destination: 5, Speed: model.Float(2.25), Mass: model.Float(8.5)},
|
{Number: 2, Class: "scout", Tech: map[string]model.Float{"CARGO": model.Float(1.25), "DRIVE": model.Float(1.75)}, Cargo: "CAP", Load: model.Float(3.5), Destination: 5, Speed: model.Float(2.25), Mass: model.Float(8.5), Race: "Klingons"},
|
||||||
},
|
},
|
||||||
UnidentifiedGroup: []model.UnidentifiedGroup{
|
UnidentifiedGroup: []model.UnidentifiedGroup{
|
||||||
{X: model.Float(10.0), Y: model.Float(11.0)},
|
{X: model.Float(10.0), Y: model.Float(11.0)},
|
||||||
|
|||||||
@@ -158,8 +158,12 @@ type pendingGroup struct {
|
|||||||
// foreign planets, so the destination resolves against the parsed
|
// foreign planets, so the destination resolves against the parsed
|
||||||
// planet tables in [parser.resolvePending]. The legacy row carries
|
// planet tables in [parser.resolvePending]. The legacy row carries
|
||||||
// no origin / range / fleet columns, so foreign groups are always
|
// no origin / range / fleet columns, so foreign groups are always
|
||||||
// treated as stationed at the destination.
|
// treated as stationed at the destination. The `race` field is set
|
||||||
|
// from the section header that introduced the row, so the inspector
|
||||||
|
// can name the foreign owner directly without falling back to a
|
||||||
|
// generic "foreign" placeholder.
|
||||||
type pendingOtherGroup struct {
|
type pendingOtherGroup struct {
|
||||||
|
race string
|
||||||
count uint
|
count uint
|
||||||
class string
|
class string
|
||||||
drive float64
|
drive float64
|
||||||
@@ -1122,6 +1126,7 @@ func (p *parser) parseOtherGroup(fields []string) {
|
|||||||
mass, _ := parseFloat(fields[10])
|
mass, _ := parseFloat(fields[10])
|
||||||
|
|
||||||
p.pendingOtherGroups = append(p.pendingOtherGroups, pendingOtherGroup{
|
p.pendingOtherGroups = append(p.pendingOtherGroups, pendingOtherGroup{
|
||||||
|
race: p.otherOwner,
|
||||||
count: uint(count),
|
count: uint(count),
|
||||||
class: fields[1],
|
class: fields[1],
|
||||||
drive: drive,
|
drive: drive,
|
||||||
@@ -1230,6 +1235,7 @@ func (p *parser) resolvePending() {
|
|||||||
Origin: origin,
|
Origin: origin,
|
||||||
Range: rng,
|
Range: rng,
|
||||||
Mass: report.F(pg.mass),
|
Mass: report.F(pg.mass),
|
||||||
|
Race: p.rep.Race,
|
||||||
},
|
},
|
||||||
ID: syntheticGroupID(pg.g),
|
ID: syntheticGroupID(pg.g),
|
||||||
State: pg.state,
|
State: pg.state,
|
||||||
@@ -1256,6 +1262,7 @@ func (p *parser) resolvePending() {
|
|||||||
Load: report.F(pg.load),
|
Load: report.F(pg.load),
|
||||||
Destination: dest,
|
Destination: dest,
|
||||||
Mass: report.F(pg.mass),
|
Mass: report.F(pg.mass),
|
||||||
|
Race: pg.race,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -844,6 +844,9 @@ func TestParseOtherAndUnidentifiedGroups(t *testing.T) {
|
|||||||
t.Errorf("a (Class, Number, Destination) = (%q, %d, %d), want (\"Skiff\", 6, 17)",
|
t.Errorf("a (Class, Number, Destination) = (%q, %d, %d), want (\"Skiff\", 6, 17)",
|
||||||
a.Class, a.Number, a.Destination)
|
a.Class, a.Number, a.Destination)
|
||||||
}
|
}
|
||||||
|
if a.Race != "Aliens" {
|
||||||
|
t.Errorf("a Race = %q, want %q (carried over from the section header)", a.Race, "Aliens")
|
||||||
|
}
|
||||||
if a.Cargo != "COL" || float64(a.Load) != 2 || float64(a.Mass) != 3 {
|
if a.Cargo != "COL" || float64(a.Load) != 2 || float64(a.Mass) != 3 {
|
||||||
t.Errorf("a (Cargo, Load, Mass) = (%q, %v, %v), want (\"COL\", 2, 3)",
|
t.Errorf("a (Cargo, Load, Mass) = (%q, %v, %v), want (\"COL\", 2, 3)",
|
||||||
a.Cargo, float64(a.Load), float64(a.Mass))
|
a.Cargo, float64(a.Load), float64(a.Mass))
|
||||||
@@ -860,6 +863,9 @@ func TestParseOtherAndUnidentifiedGroups(t *testing.T) {
|
|||||||
t.Errorf("b (Class, Number, Destination) = (%q, %d, %d), want (\"Phantom\", 1, 42)",
|
t.Errorf("b (Class, Number, Destination) = (%q, %d, %d), want (\"Phantom\", 1, 42)",
|
||||||
b.Class, b.Number, b.Destination)
|
b.Class, b.Number, b.Destination)
|
||||||
}
|
}
|
||||||
|
if b.Race != "Reds" {
|
||||||
|
t.Errorf("b Race = %q, want %q (separate section, separate owner)", b.Race, "Reds")
|
||||||
|
}
|
||||||
|
|
||||||
if got, want := len(rep.UnidentifiedGroup), 2; got != want {
|
if got, want := len(rep.UnidentifiedGroup), 2; got != want {
|
||||||
t.Fatalf("len(UnidentifiedGroup) = %d, want %d", got, want)
|
t.Fatalf("len(UnidentifiedGroup) = %d, want %d", got, want)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -193,6 +193,15 @@ export interface ReportShipGroupBase {
|
|||||||
range: number | null;
|
range: number | null;
|
||||||
speed: number;
|
speed: number;
|
||||||
mass: number;
|
mass: number;
|
||||||
|
/**
|
||||||
|
* Owning race for the group. The engine fills this from
|
||||||
|
* `sg.OwnerID` (and the legacy parser from the section header
|
||||||
|
* that introduced the row) so the inspector can name foreign
|
||||||
|
* owners directly instead of falling back to a "foreign"
|
||||||
|
* placeholder when the planet kind does not carry an `owner`
|
||||||
|
* heuristic. Empty when the source report predates the field.
|
||||||
|
*/
|
||||||
|
race: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -869,6 +878,7 @@ function decodeLocalShipGroups(report: Report): ReportLocalShipGroup[] {
|
|||||||
mass: g.mass(),
|
mass: g.mass(),
|
||||||
state: g.state() ?? "",
|
state: g.state() ?? "",
|
||||||
fleet: g.fleet(),
|
fleet: g.fleet(),
|
||||||
|
race: g.race() ?? "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
@@ -895,6 +905,7 @@ function decodeOtherShipGroups(report: Report): ReportOtherShipGroup[] {
|
|||||||
range,
|
range,
|
||||||
speed: g.speed(),
|
speed: g.speed(),
|
||||||
mass: g.mass(),
|
mass: g.mass(),
|
||||||
|
race: g.race() ?? "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
|
|||||||
@@ -186,6 +186,7 @@ interface SyntheticShipGroup {
|
|||||||
mass?: number;
|
mass?: number;
|
||||||
state?: string;
|
state?: string;
|
||||||
fleet?: string;
|
fleet?: string;
|
||||||
|
race?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SyntheticIncomingGroup {
|
interface SyntheticIncomingGroup {
|
||||||
@@ -344,6 +345,7 @@ function decodeSyntheticReport(json: unknown): GameReport {
|
|||||||
mass: numOr0(g.mass),
|
mass: numOr0(g.mass),
|
||||||
state: typeof g.state === "string" ? g.state : "",
|
state: typeof g.state === "string" ? g.state : "",
|
||||||
fleet: typeof g.fleet === "string" ? g.fleet : null,
|
fleet: typeof g.fleet === "string" ? g.fleet : null,
|
||||||
|
race: typeof g.race === "string" ? g.race : race,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const otherShipGroups: ReportOtherShipGroup[] = (root.otherGroup ?? []).map(
|
const otherShipGroups: ReportOtherShipGroup[] = (root.otherGroup ?? []).map(
|
||||||
@@ -358,6 +360,7 @@ function decodeSyntheticReport(json: unknown): GameReport {
|
|||||||
range: typeof g.range === "number" ? g.range : null,
|
range: typeof g.range === "number" ? g.range : null,
|
||||||
speed: numOr0(g.speed),
|
speed: numOr0(g.speed),
|
||||||
mass: numOr0(g.mass),
|
mass: numOr0(g.mass),
|
||||||
|
race: typeof g.race === "string" ? g.race : "",
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const incomingShipGroups: ReportIncomingShipGroup[] = (
|
const incomingShipGroups: ReportIncomingShipGroup[] = (
|
||||||
|
|||||||
@@ -600,10 +600,7 @@ const en = {
|
|||||||
|
|
||||||
"game.inspector.planet.ship_groups.race_filter.aria": "stationed race",
|
"game.inspector.planet.ship_groups.race_filter.aria": "stationed race",
|
||||||
"game.inspector.planet.ship_groups.title": "stationed ship groups",
|
"game.inspector.planet.ship_groups.title": "stationed ship groups",
|
||||||
"game.inspector.planet.ship_groups.row.count": "{count} ships",
|
|
||||||
"game.inspector.planet.ship_groups.row.mass": "mass {mass}",
|
|
||||||
"game.inspector.planet.ship_groups.race.unknown": "unknown",
|
"game.inspector.planet.ship_groups.race.unknown": "unknown",
|
||||||
"game.inspector.planet.ship_groups.race.foreign": "foreign",
|
|
||||||
|
|
||||||
"game.report.loading": "loading report…",
|
"game.report.loading": "loading report…",
|
||||||
"game.report.back_to_map": "back to map",
|
"game.report.back_to_map": "back to map",
|
||||||
|
|||||||
@@ -601,10 +601,7 @@ const ru: Record<keyof typeof en, string> = {
|
|||||||
|
|
||||||
"game.inspector.planet.ship_groups.race_filter.aria": "раса в орбите",
|
"game.inspector.planet.ship_groups.race_filter.aria": "раса в орбите",
|
||||||
"game.inspector.planet.ship_groups.title": "корабли на орбите",
|
"game.inspector.planet.ship_groups.title": "корабли на орбите",
|
||||||
"game.inspector.planet.ship_groups.row.count": "{count} кораблей",
|
|
||||||
"game.inspector.planet.ship_groups.row.mass": "масса {mass}",
|
|
||||||
"game.inspector.planet.ship_groups.race.unknown": "неизвестно",
|
"game.inspector.planet.ship_groups.race.unknown": "неизвестно",
|
||||||
"game.inspector.planet.ship_groups.race.foreign": "чужие",
|
|
||||||
|
|
||||||
"game.report.loading": "загрузка отчёта…",
|
"game.report.loading": "загрузка отчёта…",
|
||||||
"game.report.back_to_map": "назад к карте",
|
"game.report.back_to_map": "назад к карте",
|
||||||
|
|||||||
@@ -66,6 +66,17 @@ modes because the dropdown already names the active race.
|
|||||||
groupId: string | null;
|
groupId: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// F8-05 owner-feedback: the row carries the authoritative `race`
|
||||||
|
// field projected by the engine (and by the legacy parser via the
|
||||||
|
// `<Race> Groups` header), so every stationed group surfaces its
|
||||||
|
// real owner. The planet-owner / "foreign" fallback is gone — when
|
||||||
|
// the wire carries no race the row falls back to the i18n
|
||||||
|
// `race.unknown` placeholder, matching how the local-race column
|
||||||
|
// degrades if `localRace` is missing.
|
||||||
|
const unknownRace = $derived(
|
||||||
|
i18n.t("game.inspector.planet.ship_groups.race.unknown"),
|
||||||
|
);
|
||||||
|
|
||||||
const stationedRows: StationedRow[] = $derived.by(() => {
|
const stationedRows: StationedRow[] = $derived.by(() => {
|
||||||
const rows: StationedRow[] = [];
|
const rows: StationedRow[] = [];
|
||||||
for (const g of localShipGroups) {
|
for (const g of localShipGroups) {
|
||||||
@@ -73,7 +84,7 @@ modes because the dropdown already names the active race.
|
|||||||
if (g.origin !== null || g.range !== null) continue;
|
if (g.origin !== null || g.range !== null) continue;
|
||||||
rows.push({
|
rows.push({
|
||||||
key: `local:${g.id}`,
|
key: `local:${g.id}`,
|
||||||
race: localRace || i18n.t("game.inspector.planet.ship_groups.race.unknown"),
|
race: g.race || localRace || unknownRace,
|
||||||
class: g.class,
|
class: g.class,
|
||||||
count: g.count,
|
count: g.count,
|
||||||
mass: g.mass,
|
mass: g.mass,
|
||||||
@@ -81,16 +92,13 @@ modes because the dropdown already names the active race.
|
|||||||
groupId: g.id,
|
groupId: g.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const foreignRace =
|
|
||||||
planet.owner ??
|
|
||||||
i18n.t("game.inspector.planet.ship_groups.race.foreign");
|
|
||||||
for (let i = 0; i < otherShipGroups.length; i++) {
|
for (let i = 0; i < otherShipGroups.length; i++) {
|
||||||
const g = otherShipGroups[i]!;
|
const g = otherShipGroups[i]!;
|
||||||
if (g.destination !== planet.number) continue;
|
if (g.destination !== planet.number) continue;
|
||||||
if (g.origin !== null || g.range !== null) continue;
|
if (g.origin !== null || g.range !== null) continue;
|
||||||
rows.push({
|
rows.push({
|
||||||
key: `other:${i}`,
|
key: `other:${i}`,
|
||||||
race: foreignRace,
|
race: g.race || unknownRace,
|
||||||
class: g.class,
|
class: g.class,
|
||||||
count: g.count,
|
count: g.count,
|
||||||
mass: g.mass,
|
mass: g.mass,
|
||||||
@@ -183,34 +191,20 @@ modes because the dropdown already names the active race.
|
|||||||
{@const groupId = row.groupId}
|
{@const groupId = row.groupId}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="select"
|
class="cells select"
|
||||||
data-testid="inspector-planet-ship-groups-select"
|
data-testid="inspector-planet-ship-groups-select"
|
||||||
onclick={() => selectLocalGroup(groupId)}
|
onclick={() => selectLocalGroup(groupId)}
|
||||||
>
|
>
|
||||||
<span class="class">{row.class}</span>
|
<span class="class">{row.class}</span>
|
||||||
<span class="count">
|
<span class="count">{row.count} ×</span>
|
||||||
{i18n.t("game.inspector.planet.ship_groups.row.count", {
|
<span class="mass">{formatFloat(row.mass)}</span>
|
||||||
count: String(row.count),
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
<span class="mass">
|
|
||||||
{i18n.t("game.inspector.planet.ship_groups.row.mass", {
|
|
||||||
mass: formatFloat(row.mass),
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</button>
|
</button>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="class">{row.class}</span>
|
<div class="cells">
|
||||||
<span class="count">
|
<span class="class">{row.class}</span>
|
||||||
{i18n.t("game.inspector.planet.ship_groups.row.count", {
|
<span class="count">{row.count} ×</span>
|
||||||
count: String(row.count),
|
<span class="mass">{formatFloat(row.mass)}</span>
|
||||||
})}
|
</div>
|
||||||
</span>
|
|
||||||
<span class="mass">
|
|
||||||
{i18n.t("game.inspector.planet.ship_groups.row.mass", {
|
|
||||||
mass: formatFloat(row.mass),
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
{/if}
|
{/if}
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -260,13 +254,12 @@ modes because the dropdown already names the active race.
|
|||||||
.row {
|
.row {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
}
|
||||||
.row > span,
|
.cells {
|
||||||
.row > .select {
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr auto auto;
|
grid-template-columns: 1fr auto auto;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
.select {
|
.select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -286,8 +279,15 @@ modes because the dropdown already names the active race.
|
|||||||
.class {
|
.class {
|
||||||
color: var(--color-text-muted);
|
color: var(--color-text-muted);
|
||||||
}
|
}
|
||||||
.count,
|
.count {
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
text-align: right;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
.mass {
|
.mass {
|
||||||
color: var(--color-text-muted);
|
color: var(--color-text-muted);
|
||||||
|
text-align: right;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -104,8 +104,15 @@ fleet(optionalEncoding?:any):string|Uint8Array|null {
|
|||||||
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
|
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
race():string|null
|
||||||
|
race(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||||
|
race(optionalEncoding?:any):string|Uint8Array|null {
|
||||||
|
const offset = this.bb!.__offset(this.bb_pos, 30);
|
||||||
|
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
|
||||||
|
}
|
||||||
|
|
||||||
static startLocalGroup(builder:flatbuffers.Builder) {
|
static startLocalGroup(builder:flatbuffers.Builder) {
|
||||||
builder.startObject(13);
|
builder.startObject(14);
|
||||||
}
|
}
|
||||||
|
|
||||||
static addNumber(builder:flatbuffers.Builder, number:bigint) {
|
static addNumber(builder:flatbuffers.Builder, number:bigint) {
|
||||||
@@ -172,6 +179,10 @@ static addFleet(builder:flatbuffers.Builder, fleetOffset:flatbuffers.Offset) {
|
|||||||
builder.addFieldOffset(12, fleetOffset, 0);
|
builder.addFieldOffset(12, fleetOffset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static addRace(builder:flatbuffers.Builder, raceOffset:flatbuffers.Offset) {
|
||||||
|
builder.addFieldOffset(13, raceOffset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static endLocalGroup(builder:flatbuffers.Builder):flatbuffers.Offset {
|
static endLocalGroup(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||||
const offset = builder.endObject();
|
const offset = builder.endObject();
|
||||||
builder.requiredField(offset, 24) // id
|
builder.requiredField(offset, 24) // id
|
||||||
@@ -193,7 +204,8 @@ unpack(): LocalGroupT {
|
|||||||
this.mass(),
|
this.mass(),
|
||||||
(this.id() !== null ? this.id()!.unpack() : null),
|
(this.id() !== null ? this.id()!.unpack() : null),
|
||||||
this.state(),
|
this.state(),
|
||||||
this.fleet()
|
this.fleet(),
|
||||||
|
this.race()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +224,7 @@ unpackTo(_o: LocalGroupT): void {
|
|||||||
_o.id = (this.id() !== null ? this.id()!.unpack() : null);
|
_o.id = (this.id() !== null ? this.id()!.unpack() : null);
|
||||||
_o.state = this.state();
|
_o.state = this.state();
|
||||||
_o.fleet = this.fleet();
|
_o.fleet = this.fleet();
|
||||||
|
_o.race = this.race();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +242,8 @@ constructor(
|
|||||||
public mass: number = 0.0,
|
public mass: number = 0.0,
|
||||||
public id: UUIDT|null = null,
|
public id: UUIDT|null = null,
|
||||||
public state: string|Uint8Array|null = null,
|
public state: string|Uint8Array|null = null,
|
||||||
public fleet: string|Uint8Array|null = null
|
public fleet: string|Uint8Array|null = null,
|
||||||
|
public race: string|Uint8Array|null = null
|
||||||
){}
|
){}
|
||||||
|
|
||||||
|
|
||||||
@@ -239,6 +253,7 @@ pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
|||||||
const cargo = (this.cargo !== null ? builder.createString(this.cargo!) : 0);
|
const cargo = (this.cargo !== null ? builder.createString(this.cargo!) : 0);
|
||||||
const state = (this.state !== null ? builder.createString(this.state!) : 0);
|
const state = (this.state !== null ? builder.createString(this.state!) : 0);
|
||||||
const fleet = (this.fleet !== null ? builder.createString(this.fleet!) : 0);
|
const fleet = (this.fleet !== null ? builder.createString(this.fleet!) : 0);
|
||||||
|
const race = (this.race !== null ? builder.createString(this.race!) : 0);
|
||||||
|
|
||||||
LocalGroup.startLocalGroup(builder);
|
LocalGroup.startLocalGroup(builder);
|
||||||
LocalGroup.addNumber(builder, this.number);
|
LocalGroup.addNumber(builder, this.number);
|
||||||
@@ -256,6 +271,7 @@ pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
|||||||
LocalGroup.addId(builder, (this.id !== null ? this.id!.pack(builder) : 0));
|
LocalGroup.addId(builder, (this.id !== null ? this.id!.pack(builder) : 0));
|
||||||
LocalGroup.addState(builder, state);
|
LocalGroup.addState(builder, state);
|
||||||
LocalGroup.addFleet(builder, fleet);
|
LocalGroup.addFleet(builder, fleet);
|
||||||
|
LocalGroup.addRace(builder, race);
|
||||||
|
|
||||||
return LocalGroup.endLocalGroup(builder);
|
return LocalGroup.endLocalGroup(builder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,8 +84,15 @@ mass():number {
|
|||||||
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
|
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
race():string|null
|
||||||
|
race(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||||
|
race(optionalEncoding?:any):string|Uint8Array|null {
|
||||||
|
const offset = this.bb!.__offset(this.bb_pos, 24);
|
||||||
|
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
|
||||||
|
}
|
||||||
|
|
||||||
static startOtherGroup(builder:flatbuffers.Builder) {
|
static startOtherGroup(builder:flatbuffers.Builder) {
|
||||||
builder.startObject(10);
|
builder.startObject(11);
|
||||||
}
|
}
|
||||||
|
|
||||||
static addNumber(builder:flatbuffers.Builder, number:bigint) {
|
static addNumber(builder:flatbuffers.Builder, number:bigint) {
|
||||||
@@ -140,12 +147,16 @@ static addMass(builder:flatbuffers.Builder, mass:number) {
|
|||||||
builder.addFieldFloat32(9, mass, 0.0);
|
builder.addFieldFloat32(9, mass, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static addRace(builder:flatbuffers.Builder, raceOffset:flatbuffers.Offset) {
|
||||||
|
builder.addFieldOffset(10, raceOffset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static endOtherGroup(builder:flatbuffers.Builder):flatbuffers.Offset {
|
static endOtherGroup(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||||
const offset = builder.endObject();
|
const offset = builder.endObject();
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createOtherGroup(builder:flatbuffers.Builder, number:bigint, class_Offset:flatbuffers.Offset, techOffset:flatbuffers.Offset, cargoOffset:flatbuffers.Offset, load:number, destination:bigint, origin:bigint|null, range:number|null, speed:number, mass:number):flatbuffers.Offset {
|
static createOtherGroup(builder:flatbuffers.Builder, number:bigint, class_Offset:flatbuffers.Offset, techOffset:flatbuffers.Offset, cargoOffset:flatbuffers.Offset, load:number, destination:bigint, origin:bigint|null, range:number|null, speed:number, mass:number, raceOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||||
OtherGroup.startOtherGroup(builder);
|
OtherGroup.startOtherGroup(builder);
|
||||||
OtherGroup.addNumber(builder, number);
|
OtherGroup.addNumber(builder, number);
|
||||||
OtherGroup.addClass(builder, class_Offset);
|
OtherGroup.addClass(builder, class_Offset);
|
||||||
@@ -159,6 +170,7 @@ static createOtherGroup(builder:flatbuffers.Builder, number:bigint, class_Offset
|
|||||||
OtherGroup.addRange(builder, range);
|
OtherGroup.addRange(builder, range);
|
||||||
OtherGroup.addSpeed(builder, speed);
|
OtherGroup.addSpeed(builder, speed);
|
||||||
OtherGroup.addMass(builder, mass);
|
OtherGroup.addMass(builder, mass);
|
||||||
|
OtherGroup.addRace(builder, raceOffset);
|
||||||
return OtherGroup.endOtherGroup(builder);
|
return OtherGroup.endOtherGroup(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +185,8 @@ unpack(): OtherGroupT {
|
|||||||
this.origin(),
|
this.origin(),
|
||||||
this.range(),
|
this.range(),
|
||||||
this.speed(),
|
this.speed(),
|
||||||
this.mass()
|
this.mass(),
|
||||||
|
this.race()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +202,7 @@ unpackTo(_o: OtherGroupT): void {
|
|||||||
_o.range = this.range();
|
_o.range = this.range();
|
||||||
_o.speed = this.speed();
|
_o.speed = this.speed();
|
||||||
_o.mass = this.mass();
|
_o.mass = this.mass();
|
||||||
|
_o.race = this.race();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +217,8 @@ constructor(
|
|||||||
public origin: bigint|null = null,
|
public origin: bigint|null = null,
|
||||||
public range: number|null = null,
|
public range: number|null = null,
|
||||||
public speed: number = 0.0,
|
public speed: number = 0.0,
|
||||||
public mass: number = 0.0
|
public mass: number = 0.0,
|
||||||
|
public race: string|Uint8Array|null = null
|
||||||
){}
|
){}
|
||||||
|
|
||||||
|
|
||||||
@@ -211,6 +226,7 @@ pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
|||||||
const class_ = (this.class_ !== null ? builder.createString(this.class_!) : 0);
|
const class_ = (this.class_ !== null ? builder.createString(this.class_!) : 0);
|
||||||
const tech = OtherGroup.createTechVector(builder, builder.createObjectOffsetList(this.tech));
|
const tech = OtherGroup.createTechVector(builder, builder.createObjectOffsetList(this.tech));
|
||||||
const cargo = (this.cargo !== null ? builder.createString(this.cargo!) : 0);
|
const cargo = (this.cargo !== null ? builder.createString(this.cargo!) : 0);
|
||||||
|
const race = (this.race !== null ? builder.createString(this.race!) : 0);
|
||||||
|
|
||||||
return OtherGroup.createOtherGroup(builder,
|
return OtherGroup.createOtherGroup(builder,
|
||||||
this.number,
|
this.number,
|
||||||
@@ -222,7 +238,8 @@ pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
|||||||
this.origin,
|
this.origin,
|
||||||
this.range,
|
this.range,
|
||||||
this.speed,
|
this.speed,
|
||||||
this.mass
|
this.mass,
|
||||||
|
race
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ function localGroup(
|
|||||||
mass: 12,
|
mass: 12,
|
||||||
state: "In_Orbit",
|
state: "In_Orbit",
|
||||||
fleet: null,
|
fleet: null,
|
||||||
|
race: "Earthlings",
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -87,6 +88,7 @@ function otherGroup(
|
|||||||
range: null,
|
range: null,
|
||||||
speed: 0,
|
speed: 0,
|
||||||
mass: 25,
|
mass: 25,
|
||||||
|
race: "Klingons",
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ function localGroup(
|
|||||||
mass: 12,
|
mass: 12,
|
||||||
state: "In_Orbit",
|
state: "In_Orbit",
|
||||||
fleet: null,
|
fleet: null,
|
||||||
|
race: "Earthlings",
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ function group(
|
|||||||
mass: 12,
|
mass: 12,
|
||||||
state: "In_Orbit",
|
state: "In_Orbit",
|
||||||
fleet: null,
|
fleet: null,
|
||||||
|
race: "Earthlings",
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ function group(
|
|||||||
mass: 25,
|
mass: 25,
|
||||||
state: "In_Orbit",
|
state: "In_Orbit",
|
||||||
fleet: null,
|
fleet: null,
|
||||||
|
race: "Earthlings",
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ function localGroup(
|
|||||||
mass: 12,
|
mass: 12,
|
||||||
state: "In_Orbit",
|
state: "In_Orbit",
|
||||||
fleet: null,
|
fleet: null,
|
||||||
|
race: "Earthlings",
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -158,6 +159,7 @@ describe("ship-group inspector", () => {
|
|||||||
range: null,
|
range: null,
|
||||||
speed: 0,
|
speed: 0,
|
||||||
mass: 50,
|
mass: 50,
|
||||||
|
race: "Klingons",
|
||||||
};
|
};
|
||||||
const selection: ShipGroupSelection = { variant: "other", group };
|
const selection: ShipGroupSelection = { variant: "other", group };
|
||||||
const ui = render(ShipGroup, { props: { selection, planets: PLANETS } });
|
const ui = render(ShipGroup, { props: { selection, planets: PLANETS } });
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ function localGroup(overrides: Partial<ReportLocalShipGroup> & Pick<ReportLocalS
|
|||||||
mass: 1,
|
mass: 1,
|
||||||
state: "In_Orbit",
|
state: "In_Orbit",
|
||||||
fleet: null,
|
fleet: null,
|
||||||
|
race: "Earthlings",
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ function makeLocalShipGroup(
|
|||||||
mass: 0,
|
mass: 0,
|
||||||
state: "InOrbit",
|
state: "InOrbit",
|
||||||
fleet: null,
|
fleet: null,
|
||||||
|
race: "Earthlings",
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -97,6 +98,7 @@ function makeOtherShipGroup(
|
|||||||
range: null,
|
range: null,
|
||||||
speed: 1,
|
speed: 1,
|
||||||
mass: 0,
|
mass: 0,
|
||||||
|
race: "Klingons",
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ describe("reportToWorld — ship groups", () => {
|
|||||||
mass: 12,
|
mass: 12,
|
||||||
state: "In_Orbit",
|
state: "In_Orbit",
|
||||||
fleet: null,
|
fleet: null,
|
||||||
|
race: "Earthlings",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@@ -112,6 +113,7 @@ describe("reportToWorld — ship groups", () => {
|
|||||||
mass: 50,
|
mass: 50,
|
||||||
state: "In_Space",
|
state: "In_Space",
|
||||||
fleet: null,
|
fleet: null,
|
||||||
|
race: "Earthlings",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@@ -237,6 +239,7 @@ describe("reportToWorld — ship groups", () => {
|
|||||||
origin: null,
|
origin: null,
|
||||||
range: null,
|
range: null,
|
||||||
speed: 0,
|
speed: 0,
|
||||||
|
race: "Earthlings",
|
||||||
mass: 1,
|
mass: 1,
|
||||||
state: "In_Orbit",
|
state: "In_Orbit",
|
||||||
fleet: null,
|
fleet: null,
|
||||||
|
|||||||
Reference in New Issue
Block a user