969c0480ba
Engine wire change: Report.battle switched from []uuid.UUID to
[]BattleSummary{id, planet, shots} so the map can place battle
markers without N extra fetches. FBS schema + generated Go/TS
regenerated; transcoder + report controller updated; openapi
adds the BattleSummary schema with a freeze test.
Backend gateway forwards engine GET /api/v1/battle/:turn/:uuid as
/api/v1/user/games/{game_id}/battles/{turn}/{battle_id} (handler
plus engineclient.FetchBattle, contract test stub, openapi spec).
UI:
- BattleViewer (lib/battle-player/) is a logically isolated SVG
radial scene that consumes a BattleReport prop. Planet at the
centre, races on the outer ring at equal angular spacing, race
clusters by (race, className) with <class>:<numLeft> labels;
observer groups (inBattle: false) are not drawn; eliminated
races drop out and survivors re-distribute on the next frame.
- Shot line per frame: red on destroyed, green otherwise; erased
on the next frame. Playback controls: play/pause + step ± +
rewind + 1x/2x/4x speed (400/200/100 ms per frame).
- Page wrapper (lib/active-view/battle.svelte) loads BattleReport
via api/battle-fetch.ts; synthetic-gameId prefix routes to a
fixture loader, otherwise REST through the gateway. Always-
visible <ol> text protocol satisfies the accessibility ask.
- section-battles.svelte links every battle UUID into the viewer.
- map/battle-markers.ts: yellow X cross of 2 LinePrim through the
corners of the planet's circumscribed square (stroke width
clamps from 1 px at 1 shot to 5 px at 100+ shots); bombing
marker is a stroke-only ring (yellow when damaged, red when
wiped). Wired into state-binding.ts; click handler dispatches
battle clicks to the viewer and bombing clicks to the matching
Reports row.
- i18n keys for the viewer in en + ru.
Docs: ui/docs/battle-viewer-ux.md, FUNCTIONAL.md §6.5 + ru
mirror, ui/PLAN.md Phase 27 decisions + deferred TODOs (push
event, richer class visuals, animated re-distribution).
Tests: Vitest unit (radial layout + timeline frame builder +
marker stroke formula + marker primitives), Playwright e2e for
the viewer (Reports link → viewer, playback step, not-found),
backend engineclient FetchBattle (200 / 404 / bad input), engine
openapi freezes (BattleReport, BattleReportGroup,
BattleActionReport, BattleSummary, Report.battle items).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1452 lines
49 KiB
Go
1452 lines
49 KiB
Go
package transcoder
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sort"
|
|
|
|
model "galaxy/model/report"
|
|
commonfbs "galaxy/schema/fbs/common"
|
|
fbs "galaxy/schema/fbs/report"
|
|
|
|
flatbuffers "github.com/google/flatbuffers/go"
|
|
)
|
|
|
|
// ReportToPayload converts model.Report from the internal representation to
|
|
// FlatBuffers bytes that can be sent over network transports.
|
|
//
|
|
// The function returns an error when the input is nil.
|
|
func ReportToPayload(report *model.Report) ([]byte, error) {
|
|
if report == nil {
|
|
return nil, errors.New("encode report payload: report is nil")
|
|
}
|
|
|
|
builder := flatbuffers.NewBuilder(4096)
|
|
|
|
race := builder.CreateString(report.Race)
|
|
voteFor := builder.CreateString(report.VoteFor)
|
|
|
|
playerOffsets := make([]flatbuffers.UOffsetT, len(report.Player))
|
|
for i := range report.Player {
|
|
playerOffsets[i] = encodeReportPlayer(builder, &report.Player[i])
|
|
}
|
|
|
|
localScienceOffsets := make([]flatbuffers.UOffsetT, len(report.LocalScience))
|
|
for i := range report.LocalScience {
|
|
localScienceOffsets[i] = encodeReportScience(builder, &report.LocalScience[i])
|
|
}
|
|
|
|
otherScienceOffsets := make([]flatbuffers.UOffsetT, len(report.OtherScience))
|
|
for i := range report.OtherScience {
|
|
otherScienceOffsets[i] = encodeReportOtherScience(builder, &report.OtherScience[i])
|
|
}
|
|
|
|
localShipClassOffsets := make([]flatbuffers.UOffsetT, len(report.LocalShipClass))
|
|
for i := range report.LocalShipClass {
|
|
localShipClassOffsets[i] = encodeReportShipClass(builder, &report.LocalShipClass[i])
|
|
}
|
|
|
|
otherShipClassOffsets := make([]flatbuffers.UOffsetT, len(report.OtherShipClass))
|
|
for i := range report.OtherShipClass {
|
|
otherShipClassOffsets[i] = encodeReportOthersShipClass(builder, &report.OtherShipClass[i])
|
|
}
|
|
|
|
bombingOffsets := make([]flatbuffers.UOffsetT, len(report.Bombing))
|
|
for i := range report.Bombing {
|
|
if report.Bombing[i] == nil {
|
|
return nil, fmt.Errorf("encode report bombing %d: bombing is nil", i)
|
|
}
|
|
bombingOffsets[i] = encodeReportBombing(builder, report.Bombing[i])
|
|
}
|
|
|
|
incomingGroupOffsets := make([]flatbuffers.UOffsetT, len(report.IncomingGroup))
|
|
for i := range report.IncomingGroup {
|
|
incomingGroupOffsets[i] = encodeReportIncomingGroup(builder, &report.IncomingGroup[i])
|
|
}
|
|
|
|
localPlanetOffsets := make([]flatbuffers.UOffsetT, len(report.LocalPlanet))
|
|
for i := range report.LocalPlanet {
|
|
localPlanetOffsets[i] = encodeReportLocalPlanet(builder, &report.LocalPlanet[i])
|
|
}
|
|
|
|
shipProductionOffsets := make([]flatbuffers.UOffsetT, len(report.ShipProduction))
|
|
for i := range report.ShipProduction {
|
|
shipProductionOffsets[i] = encodeReportShipProduction(builder, &report.ShipProduction[i])
|
|
}
|
|
|
|
routeOffsets := make([]flatbuffers.UOffsetT, len(report.Route))
|
|
for i := range report.Route {
|
|
routeOffsets[i] = encodeReportRoute(builder, &report.Route[i])
|
|
}
|
|
|
|
otherPlanetOffsets := make([]flatbuffers.UOffsetT, len(report.OtherPlanet))
|
|
for i := range report.OtherPlanet {
|
|
otherPlanetOffsets[i] = encodeReportOtherPlanet(builder, &report.OtherPlanet[i])
|
|
}
|
|
|
|
uninhabitedPlanetOffsets := make([]flatbuffers.UOffsetT, len(report.UninhabitedPlanet))
|
|
for i := range report.UninhabitedPlanet {
|
|
uninhabitedPlanetOffsets[i] = encodeReportUninhabitedPlanet(builder, &report.UninhabitedPlanet[i])
|
|
}
|
|
|
|
unidentifiedPlanetOffsets := make([]flatbuffers.UOffsetT, len(report.UnidentifiedPlanet))
|
|
for i := range report.UnidentifiedPlanet {
|
|
unidentifiedPlanetOffsets[i] = encodeReportUnidentifiedPlanet(builder, &report.UnidentifiedPlanet[i])
|
|
}
|
|
|
|
localFleetOffsets := make([]flatbuffers.UOffsetT, len(report.LocalFleet))
|
|
for i := range report.LocalFleet {
|
|
localFleetOffsets[i] = encodeReportLocalFleet(builder, &report.LocalFleet[i])
|
|
}
|
|
|
|
localGroupOffsets := make([]flatbuffers.UOffsetT, len(report.LocalGroup))
|
|
for i := range report.LocalGroup {
|
|
localGroupOffsets[i] = encodeReportLocalGroup(builder, &report.LocalGroup[i])
|
|
}
|
|
|
|
otherGroupOffsets := make([]flatbuffers.UOffsetT, len(report.OtherGroup))
|
|
for i := range report.OtherGroup {
|
|
otherGroupOffsets[i] = encodeReportOtherGroup(builder, &report.OtherGroup[i])
|
|
}
|
|
|
|
unidentifiedGroupOffsets := make([]flatbuffers.UOffsetT, len(report.UnidentifiedGroup))
|
|
for i := range report.UnidentifiedGroup {
|
|
unidentifiedGroupOffsets[i] = encodeReportUnidentifiedGroup(builder, &report.UnidentifiedGroup[i])
|
|
}
|
|
|
|
playerVector := encodeReportOffsetVector(builder, len(playerOffsets), fbs.ReportStartPlayerVector, playerOffsets)
|
|
localScienceVector := encodeReportOffsetVector(builder, len(localScienceOffsets), fbs.ReportStartLocalScienceVector, localScienceOffsets)
|
|
otherScienceVector := encodeReportOffsetVector(builder, len(otherScienceOffsets), fbs.ReportStartOtherScienceVector, otherScienceOffsets)
|
|
localShipClassVector := encodeReportOffsetVector(builder, len(localShipClassOffsets), fbs.ReportStartLocalShipClassVector, localShipClassOffsets)
|
|
otherShipClassVector := encodeReportOffsetVector(builder, len(otherShipClassOffsets), fbs.ReportStartOtherShipClassVector, otherShipClassOffsets)
|
|
battleVector := encodeReportBattleSummaries(builder, report.Battle)
|
|
bombingVector := encodeReportOffsetVector(builder, len(bombingOffsets), fbs.ReportStartBombingVector, bombingOffsets)
|
|
incomingGroupVector := encodeReportOffsetVector(builder, len(incomingGroupOffsets), fbs.ReportStartIncomingGroupVector, incomingGroupOffsets)
|
|
localPlanetVector := encodeReportOffsetVector(builder, len(localPlanetOffsets), fbs.ReportStartLocalPlanetVector, localPlanetOffsets)
|
|
shipProductionVector := encodeReportOffsetVector(builder, len(shipProductionOffsets), fbs.ReportStartShipProductionVector, shipProductionOffsets)
|
|
routeVector := encodeReportOffsetVector(builder, len(routeOffsets), fbs.ReportStartRouteVector, routeOffsets)
|
|
otherPlanetVector := encodeReportOffsetVector(builder, len(otherPlanetOffsets), fbs.ReportStartOtherPlanetVector, otherPlanetOffsets)
|
|
uninhabitedPlanetVector := encodeReportOffsetVector(builder, len(uninhabitedPlanetOffsets), fbs.ReportStartUninhabitedPlanetVector, uninhabitedPlanetOffsets)
|
|
unidentifiedPlanetVector := encodeReportOffsetVector(builder, len(unidentifiedPlanetOffsets), fbs.ReportStartUnidentifiedPlanetVector, unidentifiedPlanetOffsets)
|
|
localFleetVector := encodeReportOffsetVector(builder, len(localFleetOffsets), fbs.ReportStartLocalFleetVector, localFleetOffsets)
|
|
localGroupVector := encodeReportOffsetVector(builder, len(localGroupOffsets), fbs.ReportStartLocalGroupVector, localGroupOffsets)
|
|
otherGroupVector := encodeReportOffsetVector(builder, len(otherGroupOffsets), fbs.ReportStartOtherGroupVector, otherGroupOffsets)
|
|
unidentifiedGroupVector := encodeReportOffsetVector(builder, len(unidentifiedGroupOffsets), fbs.ReportStartUnidentifiedGroupVector, unidentifiedGroupOffsets)
|
|
|
|
fbs.ReportStart(builder)
|
|
fbs.ReportAddVersion(builder, uint64(report.Version))
|
|
fbs.ReportAddTurn(builder, uint64(report.Turn))
|
|
fbs.ReportAddWidth(builder, report.Width)
|
|
fbs.ReportAddHeight(builder, report.Height)
|
|
fbs.ReportAddPlanetCount(builder, report.PlanetCount)
|
|
fbs.ReportAddRace(builder, race)
|
|
fbs.ReportAddVotes(builder, reportFloatToFBS(report.Votes))
|
|
fbs.ReportAddVoteFor(builder, voteFor)
|
|
if len(playerOffsets) > 0 {
|
|
fbs.ReportAddPlayer(builder, playerVector)
|
|
}
|
|
if len(localScienceOffsets) > 0 {
|
|
fbs.ReportAddLocalScience(builder, localScienceVector)
|
|
}
|
|
if len(otherScienceOffsets) > 0 {
|
|
fbs.ReportAddOtherScience(builder, otherScienceVector)
|
|
}
|
|
if len(localShipClassOffsets) > 0 {
|
|
fbs.ReportAddLocalShipClass(builder, localShipClassVector)
|
|
}
|
|
if len(otherShipClassOffsets) > 0 {
|
|
fbs.ReportAddOtherShipClass(builder, otherShipClassVector)
|
|
}
|
|
if len(report.Battle) > 0 {
|
|
fbs.ReportAddBattle(builder, battleVector)
|
|
}
|
|
if len(bombingOffsets) > 0 {
|
|
fbs.ReportAddBombing(builder, bombingVector)
|
|
}
|
|
if len(incomingGroupOffsets) > 0 {
|
|
fbs.ReportAddIncomingGroup(builder, incomingGroupVector)
|
|
}
|
|
if len(localPlanetOffsets) > 0 {
|
|
fbs.ReportAddLocalPlanet(builder, localPlanetVector)
|
|
}
|
|
if len(shipProductionOffsets) > 0 {
|
|
fbs.ReportAddShipProduction(builder, shipProductionVector)
|
|
}
|
|
if len(routeOffsets) > 0 {
|
|
fbs.ReportAddRoute(builder, routeVector)
|
|
}
|
|
if len(otherPlanetOffsets) > 0 {
|
|
fbs.ReportAddOtherPlanet(builder, otherPlanetVector)
|
|
}
|
|
if len(uninhabitedPlanetOffsets) > 0 {
|
|
fbs.ReportAddUninhabitedPlanet(builder, uninhabitedPlanetVector)
|
|
}
|
|
if len(unidentifiedPlanetOffsets) > 0 {
|
|
fbs.ReportAddUnidentifiedPlanet(builder, unidentifiedPlanetVector)
|
|
}
|
|
if len(localFleetOffsets) > 0 {
|
|
fbs.ReportAddLocalFleet(builder, localFleetVector)
|
|
}
|
|
if len(localGroupOffsets) > 0 {
|
|
fbs.ReportAddLocalGroup(builder, localGroupVector)
|
|
}
|
|
if len(otherGroupOffsets) > 0 {
|
|
fbs.ReportAddOtherGroup(builder, otherGroupVector)
|
|
}
|
|
if len(unidentifiedGroupOffsets) > 0 {
|
|
fbs.ReportAddUnidentifiedGroup(builder, unidentifiedGroupVector)
|
|
}
|
|
|
|
reportOffset := fbs.ReportEnd(builder)
|
|
fbs.FinishReportBuffer(builder, reportOffset)
|
|
|
|
return builder.FinishedBytes(), nil
|
|
}
|
|
|
|
// PayloadToReport converts FlatBuffers payload bytes into model.Report.
|
|
//
|
|
// The function validates payload structure and integer conversions.
|
|
// Malformed payloads are returned as errors.
|
|
func PayloadToReport(data []byte) (result *model.Report, err error) {
|
|
if len(data) == 0 {
|
|
return nil, errors.New("decode report payload: data is empty")
|
|
}
|
|
|
|
defer func() {
|
|
if recovered := recover(); recovered != nil {
|
|
result = nil
|
|
err = fmt.Errorf("decode report payload: panic recovered: %v", recovered)
|
|
}
|
|
}()
|
|
|
|
flatReport := fbs.GetRootAsReport(data, 0)
|
|
version, err := uint64ToUint(flatReport.Version(), "version")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decode report payload: %w", err)
|
|
}
|
|
turn, err := uint64ToUint(flatReport.Turn(), "turn")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decode report payload: %w", err)
|
|
}
|
|
|
|
result = &model.Report{
|
|
Version: version,
|
|
Turn: turn,
|
|
Width: flatReport.Width(),
|
|
Height: flatReport.Height(),
|
|
PlanetCount: flatReport.PlanetCount(),
|
|
Race: string(flatReport.Race()),
|
|
Votes: reportFloatFromFBS(flatReport.Votes()),
|
|
VoteFor: string(flatReport.VoteFor()),
|
|
}
|
|
|
|
if err := decodeReportPlayerVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportLocalScienceVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportOtherScienceVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportLocalShipClassVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportOtherShipClassVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportBattleVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportBombingVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportIncomingGroupVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportLocalPlanetVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportShipProductionVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportRouteVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportOtherPlanetVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportUninhabitedPlanetVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportUnidentifiedPlanetVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportLocalFleetVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportLocalGroupVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportOtherGroupVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := decodeReportUnidentifiedGroupVector(flatReport, result); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func encodeReportPlayer(builder *flatbuffers.Builder, player *model.Player) flatbuffers.UOffsetT {
|
|
name := builder.CreateString(player.Name)
|
|
relation := builder.CreateString(player.Relation)
|
|
|
|
fbs.PlayerStart(builder)
|
|
fbs.PlayerAddName(builder, name)
|
|
fbs.PlayerAddDrive(builder, reportFloatToFBS(player.Drive))
|
|
fbs.PlayerAddWeapons(builder, reportFloatToFBS(player.Weapons))
|
|
fbs.PlayerAddShields(builder, reportFloatToFBS(player.Shields))
|
|
fbs.PlayerAddCargo(builder, reportFloatToFBS(player.Cargo))
|
|
fbs.PlayerAddPopulation(builder, reportFloatToFBS(player.Population))
|
|
fbs.PlayerAddIndustry(builder, reportFloatToFBS(player.Industry))
|
|
fbs.PlayerAddPlanets(builder, player.Planets)
|
|
fbs.PlayerAddRelation(builder, relation)
|
|
fbs.PlayerAddVotes(builder, reportFloatToFBS(player.Votes))
|
|
fbs.PlayerAddExtinct(builder, player.Extinct)
|
|
return fbs.PlayerEnd(builder)
|
|
}
|
|
|
|
func encodeReportScience(builder *flatbuffers.Builder, science *model.Science) flatbuffers.UOffsetT {
|
|
name := builder.CreateString(science.Name)
|
|
fbs.ScienceStart(builder)
|
|
fbs.ScienceAddName(builder, name)
|
|
fbs.ScienceAddDrive(builder, reportFloatToFBS(science.Drive))
|
|
fbs.ScienceAddWeapons(builder, reportFloatToFBS(science.Weapons))
|
|
fbs.ScienceAddShields(builder, reportFloatToFBS(science.Shields))
|
|
fbs.ScienceAddCargo(builder, reportFloatToFBS(science.Cargo))
|
|
return fbs.ScienceEnd(builder)
|
|
}
|
|
|
|
func encodeReportOtherScience(builder *flatbuffers.Builder, science *model.OtherScience) flatbuffers.UOffsetT {
|
|
race := builder.CreateString(science.Race)
|
|
name := builder.CreateString(science.Name)
|
|
fbs.OtherScienceStart(builder)
|
|
fbs.OtherScienceAddRace(builder, race)
|
|
fbs.OtherScienceAddName(builder, name)
|
|
fbs.OtherScienceAddDrive(builder, reportFloatToFBS(science.Drive))
|
|
fbs.OtherScienceAddWeapons(builder, reportFloatToFBS(science.Weapons))
|
|
fbs.OtherScienceAddShields(builder, reportFloatToFBS(science.Shields))
|
|
fbs.OtherScienceAddCargo(builder, reportFloatToFBS(science.Cargo))
|
|
return fbs.OtherScienceEnd(builder)
|
|
}
|
|
|
|
func encodeReportShipClass(builder *flatbuffers.Builder, shipClass *model.ShipClass) flatbuffers.UOffsetT {
|
|
name := builder.CreateString(shipClass.Name)
|
|
fbs.ShipClassStart(builder)
|
|
fbs.ShipClassAddName(builder, name)
|
|
fbs.ShipClassAddDrive(builder, reportFloatToFBS(shipClass.Drive))
|
|
fbs.ShipClassAddArmament(builder, uint64(shipClass.Armament))
|
|
fbs.ShipClassAddWeapons(builder, reportFloatToFBS(shipClass.Weapons))
|
|
fbs.ShipClassAddShields(builder, reportFloatToFBS(shipClass.Shields))
|
|
fbs.ShipClassAddCargo(builder, reportFloatToFBS(shipClass.Cargo))
|
|
fbs.ShipClassAddMass(builder, reportFloatToFBS(shipClass.Mass))
|
|
return fbs.ShipClassEnd(builder)
|
|
}
|
|
|
|
func encodeReportOthersShipClass(builder *flatbuffers.Builder, shipClass *model.OthersShipClass) flatbuffers.UOffsetT {
|
|
race := builder.CreateString(shipClass.Race)
|
|
name := builder.CreateString(shipClass.Name)
|
|
fbs.OthersShipClassStart(builder)
|
|
fbs.OthersShipClassAddRace(builder, race)
|
|
fbs.OthersShipClassAddName(builder, name)
|
|
fbs.OthersShipClassAddDrive(builder, reportFloatToFBS(shipClass.Drive))
|
|
fbs.OthersShipClassAddArmament(builder, uint64(shipClass.Armament))
|
|
fbs.OthersShipClassAddWeapons(builder, reportFloatToFBS(shipClass.Weapons))
|
|
fbs.OthersShipClassAddShields(builder, reportFloatToFBS(shipClass.Shields))
|
|
fbs.OthersShipClassAddCargo(builder, reportFloatToFBS(shipClass.Cargo))
|
|
fbs.OthersShipClassAddMass(builder, reportFloatToFBS(shipClass.Mass))
|
|
return fbs.OthersShipClassEnd(builder)
|
|
}
|
|
|
|
func encodeReportBombing(builder *flatbuffers.Builder, bombing *model.Bombing) flatbuffers.UOffsetT {
|
|
planet := builder.CreateString(bombing.Planet)
|
|
owner := builder.CreateString(bombing.Owner)
|
|
attacker := builder.CreateString(bombing.Attacker)
|
|
production := builder.CreateString(bombing.Production)
|
|
|
|
fbs.BombingStart(builder)
|
|
fbs.BombingAddNumber(builder, uint64(bombing.Number))
|
|
fbs.BombingAddPlanet(builder, planet)
|
|
fbs.BombingAddOwner(builder, owner)
|
|
fbs.BombingAddAttacker(builder, attacker)
|
|
fbs.BombingAddProduction(builder, production)
|
|
fbs.BombingAddIndustry(builder, reportFloatToFBS(bombing.Industry))
|
|
fbs.BombingAddPopulation(builder, reportFloatToFBS(bombing.Population))
|
|
fbs.BombingAddColonists(builder, reportFloatToFBS(bombing.Colonists))
|
|
fbs.BombingAddCapital(builder, reportFloatToFBS(bombing.Capital))
|
|
fbs.BombingAddMaterial(builder, reportFloatToFBS(bombing.Material))
|
|
fbs.BombingAddAttackPower(builder, reportFloatToFBS(bombing.AttackPower))
|
|
fbs.BombingAddWiped(builder, bombing.Wiped)
|
|
return fbs.BombingEnd(builder)
|
|
}
|
|
|
|
func encodeReportIncomingGroup(builder *flatbuffers.Builder, group *model.IncomingGroup) flatbuffers.UOffsetT {
|
|
fbs.IncomingGroupStart(builder)
|
|
fbs.IncomingGroupAddOrigin(builder, uint64(group.Origin))
|
|
fbs.IncomingGroupAddDestination(builder, uint64(group.Destination))
|
|
fbs.IncomingGroupAddDistance(builder, reportFloatToFBS(group.Distance))
|
|
fbs.IncomingGroupAddSpeed(builder, reportFloatToFBS(group.Speed))
|
|
fbs.IncomingGroupAddMass(builder, reportFloatToFBS(group.Mass))
|
|
return fbs.IncomingGroupEnd(builder)
|
|
}
|
|
|
|
func encodeReportLocalPlanet(builder *flatbuffers.Builder, planet *model.LocalPlanet) flatbuffers.UOffsetT {
|
|
name := builder.CreateString(planet.Name)
|
|
production := builder.CreateString(planet.Production)
|
|
|
|
fbs.LocalPlanetStart(builder)
|
|
fbs.LocalPlanetAddX(builder, reportFloatToFBS(planet.X))
|
|
fbs.LocalPlanetAddY(builder, reportFloatToFBS(planet.Y))
|
|
fbs.LocalPlanetAddNumber(builder, uint64(planet.Number))
|
|
fbs.LocalPlanetAddSize(builder, reportFloatToFBS(planet.Size))
|
|
fbs.LocalPlanetAddName(builder, name)
|
|
fbs.LocalPlanetAddResources(builder, reportFloatToFBS(planet.Resources))
|
|
fbs.LocalPlanetAddCapital(builder, reportFloatToFBS(planet.Capital))
|
|
fbs.LocalPlanetAddMaterial(builder, reportFloatToFBS(planet.Material))
|
|
fbs.LocalPlanetAddIndustry(builder, reportFloatToFBS(planet.Industry))
|
|
fbs.LocalPlanetAddPopulation(builder, reportFloatToFBS(planet.Population))
|
|
fbs.LocalPlanetAddColonists(builder, reportFloatToFBS(planet.Colonists))
|
|
fbs.LocalPlanetAddProduction(builder, production)
|
|
fbs.LocalPlanetAddFreeIndustry(builder, reportFloatToFBS(planet.FreeIndustry))
|
|
return fbs.LocalPlanetEnd(builder)
|
|
}
|
|
|
|
func encodeReportShipProduction(builder *flatbuffers.Builder, production *model.ShipProduction) flatbuffers.UOffsetT {
|
|
class := builder.CreateString(production.Class)
|
|
fbs.ShipProductionStart(builder)
|
|
fbs.ShipProductionAddPlanet(builder, uint64(production.Planet))
|
|
fbs.ShipProductionAddClass(builder, class)
|
|
fbs.ShipProductionAddCost(builder, reportFloatToFBS(production.Cost))
|
|
fbs.ShipProductionAddProdUsed(builder, reportFloatToFBS(production.ProdUsed))
|
|
fbs.ShipProductionAddPercent(builder, reportFloatToFBS(production.Percent))
|
|
fbs.ShipProductionAddFree(builder, reportFloatToFBS(production.Free))
|
|
return fbs.ShipProductionEnd(builder)
|
|
}
|
|
|
|
func encodeReportRoute(builder *flatbuffers.Builder, route *model.Route) flatbuffers.UOffsetT {
|
|
routeEntries := encodeReportRouteEntryVector(builder, route.Route)
|
|
|
|
fbs.RouteStart(builder)
|
|
fbs.RouteAddPlanet(builder, uint64(route.Planet))
|
|
if routeEntries != 0 {
|
|
fbs.RouteAddRoute(builder, routeEntries)
|
|
}
|
|
return fbs.RouteEnd(builder)
|
|
}
|
|
|
|
func encodeReportOtherPlanet(builder *flatbuffers.Builder, planet *model.OtherPlanet) flatbuffers.UOffsetT {
|
|
owner := builder.CreateString(planet.Owner)
|
|
name := builder.CreateString(planet.Name)
|
|
production := builder.CreateString(planet.Production)
|
|
|
|
fbs.OtherPlanetStart(builder)
|
|
fbs.OtherPlanetAddOwner(builder, owner)
|
|
fbs.OtherPlanetAddX(builder, reportFloatToFBS(planet.X))
|
|
fbs.OtherPlanetAddY(builder, reportFloatToFBS(planet.Y))
|
|
fbs.OtherPlanetAddNumber(builder, uint64(planet.Number))
|
|
fbs.OtherPlanetAddSize(builder, reportFloatToFBS(planet.Size))
|
|
fbs.OtherPlanetAddName(builder, name)
|
|
fbs.OtherPlanetAddResources(builder, reportFloatToFBS(planet.Resources))
|
|
fbs.OtherPlanetAddCapital(builder, reportFloatToFBS(planet.Capital))
|
|
fbs.OtherPlanetAddMaterial(builder, reportFloatToFBS(planet.Material))
|
|
fbs.OtherPlanetAddIndustry(builder, reportFloatToFBS(planet.Industry))
|
|
fbs.OtherPlanetAddPopulation(builder, reportFloatToFBS(planet.Population))
|
|
fbs.OtherPlanetAddColonists(builder, reportFloatToFBS(planet.Colonists))
|
|
fbs.OtherPlanetAddProduction(builder, production)
|
|
fbs.OtherPlanetAddFreeIndustry(builder, reportFloatToFBS(planet.FreeIndustry))
|
|
return fbs.OtherPlanetEnd(builder)
|
|
}
|
|
|
|
func encodeReportUninhabitedPlanet(builder *flatbuffers.Builder, planet *model.UninhabitedPlanet) flatbuffers.UOffsetT {
|
|
name := builder.CreateString(planet.Name)
|
|
fbs.UninhabitedPlanetStart(builder)
|
|
fbs.UninhabitedPlanetAddX(builder, reportFloatToFBS(planet.X))
|
|
fbs.UninhabitedPlanetAddY(builder, reportFloatToFBS(planet.Y))
|
|
fbs.UninhabitedPlanetAddNumber(builder, uint64(planet.Number))
|
|
fbs.UninhabitedPlanetAddSize(builder, reportFloatToFBS(planet.Size))
|
|
fbs.UninhabitedPlanetAddName(builder, name)
|
|
fbs.UninhabitedPlanetAddResources(builder, reportFloatToFBS(planet.Resources))
|
|
fbs.UninhabitedPlanetAddCapital(builder, reportFloatToFBS(planet.Capital))
|
|
fbs.UninhabitedPlanetAddMaterial(builder, reportFloatToFBS(planet.Material))
|
|
return fbs.UninhabitedPlanetEnd(builder)
|
|
}
|
|
|
|
func encodeReportUnidentifiedPlanet(builder *flatbuffers.Builder, planet *model.UnidentifiedPlanet) flatbuffers.UOffsetT {
|
|
fbs.UnidentifiedPlanetStart(builder)
|
|
fbs.UnidentifiedPlanetAddX(builder, reportFloatToFBS(planet.X))
|
|
fbs.UnidentifiedPlanetAddY(builder, reportFloatToFBS(planet.Y))
|
|
fbs.UnidentifiedPlanetAddNumber(builder, uint64(planet.Number))
|
|
return fbs.UnidentifiedPlanetEnd(builder)
|
|
}
|
|
|
|
func encodeReportLocalFleet(builder *flatbuffers.Builder, fleet *model.LocalFleet) flatbuffers.UOffsetT {
|
|
name := builder.CreateString(fleet.Name)
|
|
state := builder.CreateString(fleet.State)
|
|
|
|
fbs.LocalFleetStart(builder)
|
|
fbs.LocalFleetAddName(builder, name)
|
|
fbs.LocalFleetAddGroups(builder, uint64(fleet.Groups))
|
|
fbs.LocalFleetAddDestination(builder, uint64(fleet.Destination))
|
|
if fleet.Origin != nil {
|
|
fbs.LocalFleetAddOrigin(builder, uint64(*fleet.Origin))
|
|
}
|
|
if fleet.Range != nil {
|
|
fbs.LocalFleetAddRange(builder, reportFloatToFBS(*fleet.Range))
|
|
}
|
|
fbs.LocalFleetAddSpeed(builder, reportFloatToFBS(fleet.Speed))
|
|
fbs.LocalFleetAddState(builder, state)
|
|
return fbs.LocalFleetEnd(builder)
|
|
}
|
|
|
|
func encodeReportLocalGroup(builder *flatbuffers.Builder, group *model.LocalGroup) flatbuffers.UOffsetT {
|
|
class := builder.CreateString(group.Class)
|
|
cargo := builder.CreateString(group.Cargo)
|
|
state := builder.CreateString(group.State)
|
|
|
|
tech := encodeReportTechEntryVector(builder, group.Tech)
|
|
var fleet flatbuffers.UOffsetT
|
|
if group.Fleet != nil {
|
|
fleet = builder.CreateString(*group.Fleet)
|
|
}
|
|
|
|
idHi, idLo := uuidToHiLo(group.ID)
|
|
|
|
fbs.LocalGroupStart(builder)
|
|
fbs.LocalGroupAddNumber(builder, uint64(group.Number))
|
|
fbs.LocalGroupAddClass(builder, class)
|
|
if tech != 0 {
|
|
fbs.LocalGroupAddTech(builder, tech)
|
|
}
|
|
fbs.LocalGroupAddCargo(builder, cargo)
|
|
fbs.LocalGroupAddLoad(builder, reportFloatToFBS(group.Load))
|
|
fbs.LocalGroupAddDestination(builder, uint64(group.Destination))
|
|
if group.Origin != nil {
|
|
fbs.LocalGroupAddOrigin(builder, uint64(*group.Origin))
|
|
}
|
|
if group.Range != nil {
|
|
fbs.LocalGroupAddRange(builder, reportFloatToFBS(*group.Range))
|
|
}
|
|
fbs.LocalGroupAddSpeed(builder, reportFloatToFBS(group.Speed))
|
|
fbs.LocalGroupAddMass(builder, reportFloatToFBS(group.Mass))
|
|
fbs.LocalGroupAddId(builder, commonfbs.CreateUUID(builder, idHi, idLo))
|
|
fbs.LocalGroupAddState(builder, state)
|
|
if group.Fleet != nil {
|
|
fbs.LocalGroupAddFleet(builder, fleet)
|
|
}
|
|
return fbs.LocalGroupEnd(builder)
|
|
}
|
|
|
|
func encodeReportOtherGroup(builder *flatbuffers.Builder, group *model.OtherGroup) flatbuffers.UOffsetT {
|
|
class := builder.CreateString(group.Class)
|
|
cargo := builder.CreateString(group.Cargo)
|
|
tech := encodeReportTechEntryVector(builder, group.Tech)
|
|
|
|
fbs.OtherGroupStart(builder)
|
|
fbs.OtherGroupAddNumber(builder, uint64(group.Number))
|
|
fbs.OtherGroupAddClass(builder, class)
|
|
if tech != 0 {
|
|
fbs.OtherGroupAddTech(builder, tech)
|
|
}
|
|
fbs.OtherGroupAddCargo(builder, cargo)
|
|
fbs.OtherGroupAddLoad(builder, reportFloatToFBS(group.Load))
|
|
fbs.OtherGroupAddDestination(builder, uint64(group.Destination))
|
|
if group.Origin != nil {
|
|
fbs.OtherGroupAddOrigin(builder, uint64(*group.Origin))
|
|
}
|
|
if group.Range != nil {
|
|
fbs.OtherGroupAddRange(builder, reportFloatToFBS(*group.Range))
|
|
}
|
|
fbs.OtherGroupAddSpeed(builder, reportFloatToFBS(group.Speed))
|
|
fbs.OtherGroupAddMass(builder, reportFloatToFBS(group.Mass))
|
|
return fbs.OtherGroupEnd(builder)
|
|
}
|
|
|
|
func encodeReportUnidentifiedGroup(builder *flatbuffers.Builder, group *model.UnidentifiedGroup) flatbuffers.UOffsetT {
|
|
fbs.UnidentifiedGroupStart(builder)
|
|
fbs.UnidentifiedGroupAddX(builder, reportFloatToFBS(group.X))
|
|
fbs.UnidentifiedGroupAddY(builder, reportFloatToFBS(group.Y))
|
|
return fbs.UnidentifiedGroupEnd(builder)
|
|
}
|
|
|
|
func decodeReportPlayerVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.PlayerLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.Player = make([]model.Player, length)
|
|
item := new(fbs.Player)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.Player(item, i) {
|
|
return fmt.Errorf("decode report player %d: player is missing", i)
|
|
}
|
|
result.Player[i] = model.Player{
|
|
Name: string(item.Name()),
|
|
Drive: reportFloatFromFBS(item.Drive()),
|
|
Weapons: reportFloatFromFBS(item.Weapons()),
|
|
Shields: reportFloatFromFBS(item.Shields()),
|
|
Cargo: reportFloatFromFBS(item.Cargo()),
|
|
Population: reportFloatFromFBS(item.Population()),
|
|
Industry: reportFloatFromFBS(item.Industry()),
|
|
Planets: item.Planets(),
|
|
Relation: string(item.Relation()),
|
|
Votes: reportFloatFromFBS(item.Votes()),
|
|
Extinct: item.Extinct(),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportLocalScienceVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.LocalScienceLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.LocalScience = make([]model.Science, length)
|
|
item := new(fbs.Science)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.LocalScience(item, i) {
|
|
return fmt.Errorf("decode report local science %d: science is missing", i)
|
|
}
|
|
result.LocalScience[i] = model.Science{
|
|
Name: string(item.Name()),
|
|
Drive: reportFloatFromFBS(item.Drive()),
|
|
Weapons: reportFloatFromFBS(item.Weapons()),
|
|
Shields: reportFloatFromFBS(item.Shields()),
|
|
Cargo: reportFloatFromFBS(item.Cargo()),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportOtherScienceVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.OtherScienceLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.OtherScience = make([]model.OtherScience, length)
|
|
item := new(fbs.OtherScience)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.OtherScience(item, i) {
|
|
return fmt.Errorf("decode report other science %d: science is missing", i)
|
|
}
|
|
result.OtherScience[i] = model.OtherScience{
|
|
Race: string(item.Race()),
|
|
Science: model.Science{
|
|
Name: string(item.Name()),
|
|
Drive: reportFloatFromFBS(item.Drive()),
|
|
Weapons: reportFloatFromFBS(item.Weapons()),
|
|
Shields: reportFloatFromFBS(item.Shields()),
|
|
Cargo: reportFloatFromFBS(item.Cargo()),
|
|
},
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportLocalShipClassVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.LocalShipClassLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.LocalShipClass = make([]model.ShipClass, length)
|
|
item := new(fbs.ShipClass)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.LocalShipClass(item, i) {
|
|
return fmt.Errorf("decode report local ship class %d: ship class is missing", i)
|
|
}
|
|
|
|
armament, err := uint64ToUint(item.Armament(), "armament")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report local ship class %d: %w", i, err)
|
|
}
|
|
|
|
result.LocalShipClass[i] = model.ShipClass{
|
|
Name: string(item.Name()),
|
|
Drive: reportFloatFromFBS(item.Drive()),
|
|
Armament: armament,
|
|
Weapons: reportFloatFromFBS(item.Weapons()),
|
|
Shields: reportFloatFromFBS(item.Shields()),
|
|
Cargo: reportFloatFromFBS(item.Cargo()),
|
|
Mass: reportFloatFromFBS(item.Mass()),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportOtherShipClassVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.OtherShipClassLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.OtherShipClass = make([]model.OthersShipClass, length)
|
|
item := new(fbs.OthersShipClass)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.OtherShipClass(item, i) {
|
|
return fmt.Errorf("decode report other ship class %d: ship class is missing", i)
|
|
}
|
|
|
|
armament, err := uint64ToUint(item.Armament(), "armament")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report other ship class %d: %w", i, err)
|
|
}
|
|
|
|
result.OtherShipClass[i] = model.OthersShipClass{
|
|
Race: string(item.Race()),
|
|
ShipClass: model.ShipClass{
|
|
Name: string(item.Name()),
|
|
Drive: reportFloatFromFBS(item.Drive()),
|
|
Armament: armament,
|
|
Weapons: reportFloatFromFBS(item.Weapons()),
|
|
Shields: reportFloatFromFBS(item.Shields()),
|
|
Cargo: reportFloatFromFBS(item.Cargo()),
|
|
Mass: reportFloatFromFBS(item.Mass()),
|
|
},
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportBattleVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.BattleLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.Battle = make([]model.BattleSummary, length)
|
|
item := new(fbs.BattleSummary)
|
|
idHolder := new(commonfbs.UUID)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.Battle(item, i) {
|
|
return fmt.Errorf("decode report battle %d: battle is missing", i)
|
|
}
|
|
if item.Id(idHolder) == nil {
|
|
return fmt.Errorf("decode report battle %d: battle id is missing", i)
|
|
}
|
|
planet, err := uint64ToUint(item.Planet(), "planet")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report battle %d: %w", i, err)
|
|
}
|
|
shots, err := uint64ToUint(item.Shots(), "shots")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report battle %d: %w", i, err)
|
|
}
|
|
result.Battle[i] = model.BattleSummary{
|
|
ID: uuidFromHiLo(idHolder.Hi(), idHolder.Lo()),
|
|
Planet: planet,
|
|
Shots: shots,
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportBombingVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.BombingLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.Bombing = make([]*model.Bombing, length)
|
|
item := new(fbs.Bombing)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.Bombing(item, i) {
|
|
return fmt.Errorf("decode report bombing %d: bombing is missing", i)
|
|
}
|
|
|
|
number, err := uint64ToUint(item.Number(), "number")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report bombing %d: %w", i, err)
|
|
}
|
|
|
|
result.Bombing[i] = &model.Bombing{
|
|
Number: number,
|
|
Planet: string(item.Planet()),
|
|
Owner: string(item.Owner()),
|
|
Attacker: string(item.Attacker()),
|
|
Production: string(item.Production()),
|
|
Industry: reportFloatFromFBS(item.Industry()),
|
|
Population: reportFloatFromFBS(item.Population()),
|
|
Colonists: reportFloatFromFBS(item.Colonists()),
|
|
Capital: reportFloatFromFBS(item.Capital()),
|
|
Material: reportFloatFromFBS(item.Material()),
|
|
AttackPower: reportFloatFromFBS(item.AttackPower()),
|
|
Wiped: item.Wiped(),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportIncomingGroupVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.IncomingGroupLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.IncomingGroup = make([]model.IncomingGroup, length)
|
|
item := new(fbs.IncomingGroup)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.IncomingGroup(item, i) {
|
|
return fmt.Errorf("decode report incoming group %d: group is missing", i)
|
|
}
|
|
|
|
origin, err := uint64ToUint(item.Origin(), "origin")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report incoming group %d: %w", i, err)
|
|
}
|
|
destination, err := uint64ToUint(item.Destination(), "destination")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report incoming group %d: %w", i, err)
|
|
}
|
|
|
|
result.IncomingGroup[i] = model.IncomingGroup{
|
|
Origin: origin,
|
|
Destination: destination,
|
|
Distance: reportFloatFromFBS(item.Distance()),
|
|
Speed: reportFloatFromFBS(item.Speed()),
|
|
Mass: reportFloatFromFBS(item.Mass()),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportLocalPlanetVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.LocalPlanetLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.LocalPlanet = make([]model.LocalPlanet, length)
|
|
item := new(fbs.LocalPlanet)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.LocalPlanet(item, i) {
|
|
return fmt.Errorf("decode report local planet %d: planet is missing", i)
|
|
}
|
|
|
|
number, err := uint64ToUint(item.Number(), "number")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report local planet %d: %w", i, err)
|
|
}
|
|
|
|
result.LocalPlanet[i] = model.LocalPlanet{
|
|
UninhabitedPlanet: model.UninhabitedPlanet{
|
|
UnidentifiedPlanet: model.UnidentifiedPlanet{
|
|
X: reportFloatFromFBS(item.X()),
|
|
Y: reportFloatFromFBS(item.Y()),
|
|
Number: number,
|
|
},
|
|
Size: reportFloatFromFBS(item.Size()),
|
|
Name: string(item.Name()),
|
|
Resources: reportFloatFromFBS(item.Resources()),
|
|
Capital: reportFloatFromFBS(item.Capital()),
|
|
Material: reportFloatFromFBS(item.Material()),
|
|
},
|
|
Industry: reportFloatFromFBS(item.Industry()),
|
|
Population: reportFloatFromFBS(item.Population()),
|
|
Colonists: reportFloatFromFBS(item.Colonists()),
|
|
Production: string(item.Production()),
|
|
FreeIndustry: reportFloatFromFBS(item.FreeIndustry()),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportShipProductionVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.ShipProductionLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.ShipProduction = make([]model.ShipProduction, length)
|
|
item := new(fbs.ShipProduction)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.ShipProduction(item, i) {
|
|
return fmt.Errorf("decode report ship production %d: production is missing", i)
|
|
}
|
|
|
|
planet, err := uint64ToUint(item.Planet(), "planet")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report ship production %d: %w", i, err)
|
|
}
|
|
|
|
result.ShipProduction[i] = model.ShipProduction{
|
|
Planet: planet,
|
|
Class: string(item.Class()),
|
|
Cost: reportFloatFromFBS(item.Cost()),
|
|
ProdUsed: reportFloatFromFBS(item.ProdUsed()),
|
|
Percent: reportFloatFromFBS(item.Percent()),
|
|
Free: reportFloatFromFBS(item.Free()),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportRouteVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.RouteLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.Route = make([]model.Route, length)
|
|
item := new(fbs.Route)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.Route(item, i) {
|
|
return fmt.Errorf("decode report route %d: route is missing", i)
|
|
}
|
|
|
|
planet, err := uint64ToUint(item.Planet(), "planet")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report route %d: %w", i, err)
|
|
}
|
|
|
|
routeMap, err := decodeReportRouteMap(item, i)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
result.Route[i] = model.Route{
|
|
Planet: planet,
|
|
Route: routeMap,
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportOtherPlanetVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.OtherPlanetLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.OtherPlanet = make([]model.OtherPlanet, length)
|
|
item := new(fbs.OtherPlanet)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.OtherPlanet(item, i) {
|
|
return fmt.Errorf("decode report other planet %d: planet is missing", i)
|
|
}
|
|
|
|
number, err := uint64ToUint(item.Number(), "number")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report other planet %d: %w", i, err)
|
|
}
|
|
|
|
result.OtherPlanet[i] = model.OtherPlanet{
|
|
Owner: string(item.Owner()),
|
|
LocalPlanet: model.LocalPlanet{
|
|
UninhabitedPlanet: model.UninhabitedPlanet{
|
|
UnidentifiedPlanet: model.UnidentifiedPlanet{
|
|
X: reportFloatFromFBS(item.X()),
|
|
Y: reportFloatFromFBS(item.Y()),
|
|
Number: number,
|
|
},
|
|
Size: reportFloatFromFBS(item.Size()),
|
|
Name: string(item.Name()),
|
|
Resources: reportFloatFromFBS(item.Resources()),
|
|
Capital: reportFloatFromFBS(item.Capital()),
|
|
Material: reportFloatFromFBS(item.Material()),
|
|
},
|
|
Industry: reportFloatFromFBS(item.Industry()),
|
|
Population: reportFloatFromFBS(item.Population()),
|
|
Colonists: reportFloatFromFBS(item.Colonists()),
|
|
Production: string(item.Production()),
|
|
FreeIndustry: reportFloatFromFBS(item.FreeIndustry()),
|
|
},
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportUninhabitedPlanetVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.UninhabitedPlanetLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.UninhabitedPlanet = make([]model.UninhabitedPlanet, length)
|
|
item := new(fbs.UninhabitedPlanet)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.UninhabitedPlanet(item, i) {
|
|
return fmt.Errorf("decode report uninhabited planet %d: planet is missing", i)
|
|
}
|
|
|
|
number, err := uint64ToUint(item.Number(), "number")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report uninhabited planet %d: %w", i, err)
|
|
}
|
|
|
|
result.UninhabitedPlanet[i] = model.UninhabitedPlanet{
|
|
UnidentifiedPlanet: model.UnidentifiedPlanet{
|
|
X: reportFloatFromFBS(item.X()),
|
|
Y: reportFloatFromFBS(item.Y()),
|
|
Number: number,
|
|
},
|
|
Size: reportFloatFromFBS(item.Size()),
|
|
Name: string(item.Name()),
|
|
Resources: reportFloatFromFBS(item.Resources()),
|
|
Capital: reportFloatFromFBS(item.Capital()),
|
|
Material: reportFloatFromFBS(item.Material()),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportUnidentifiedPlanetVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.UnidentifiedPlanetLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.UnidentifiedPlanet = make([]model.UnidentifiedPlanet, length)
|
|
item := new(fbs.UnidentifiedPlanet)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.UnidentifiedPlanet(item, i) {
|
|
return fmt.Errorf("decode report unidentified planet %d: planet is missing", i)
|
|
}
|
|
|
|
number, err := uint64ToUint(item.Number(), "number")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report unidentified planet %d: %w", i, err)
|
|
}
|
|
|
|
result.UnidentifiedPlanet[i] = model.UnidentifiedPlanet{
|
|
X: reportFloatFromFBS(item.X()),
|
|
Y: reportFloatFromFBS(item.Y()),
|
|
Number: number,
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportLocalFleetVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.LocalFleetLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.LocalFleet = make([]model.LocalFleet, length)
|
|
item := new(fbs.LocalFleet)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.LocalFleet(item, i) {
|
|
return fmt.Errorf("decode report local fleet %d: fleet is missing", i)
|
|
}
|
|
|
|
groups, err := uint64ToUint(item.Groups(), "groups")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report local fleet %d: %w", i, err)
|
|
}
|
|
destination, err := uint64ToUint(item.Destination(), "destination")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report local fleet %d: %w", i, err)
|
|
}
|
|
|
|
decoded := model.LocalFleet{
|
|
Name: string(item.Name()),
|
|
Groups: groups,
|
|
Destination: destination,
|
|
Speed: reportFloatFromFBS(item.Speed()),
|
|
State: string(item.State()),
|
|
}
|
|
|
|
if origin := item.Origin(); origin != nil {
|
|
decodedOrigin, err := uint64ToUint(*origin, "origin")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report local fleet %d: %w", i, err)
|
|
}
|
|
decoded.Origin = &decodedOrigin
|
|
}
|
|
if range_ := item.Range(); range_ != nil {
|
|
decodedRange := reportFloatFromFBS(*range_)
|
|
decoded.Range = &decodedRange
|
|
}
|
|
|
|
result.LocalFleet[i] = decoded
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportLocalGroupVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.LocalGroupLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.LocalGroup = make([]model.LocalGroup, length)
|
|
item := new(fbs.LocalGroup)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.LocalGroup(item, i) {
|
|
return fmt.Errorf("decode report local group %d: group is missing", i)
|
|
}
|
|
|
|
number, err := uint64ToUint(item.Number(), "number")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report local group %d: %w", i, err)
|
|
}
|
|
destination, err := uint64ToUint(item.Destination(), "destination")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report local group %d: %w", i, err)
|
|
}
|
|
tech, err := decodeReportTechMapFromLocalGroup(item, i)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
id := item.Id(nil)
|
|
if id == nil {
|
|
return fmt.Errorf("decode report local group %d: id is missing", i)
|
|
}
|
|
|
|
decoded := model.LocalGroup{
|
|
OtherGroup: model.OtherGroup{
|
|
Number: number,
|
|
Class: string(item.Class()),
|
|
Tech: tech,
|
|
Cargo: string(item.Cargo()),
|
|
Load: reportFloatFromFBS(item.Load()),
|
|
Destination: destination,
|
|
Speed: reportFloatFromFBS(item.Speed()),
|
|
Mass: reportFloatFromFBS(item.Mass()),
|
|
},
|
|
ID: uuidFromHiLo(id.Hi(), id.Lo()),
|
|
State: string(item.State()),
|
|
}
|
|
|
|
if origin := item.Origin(); origin != nil {
|
|
decodedOrigin, err := uint64ToUint(*origin, "origin")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report local group %d: %w", i, err)
|
|
}
|
|
decoded.Origin = &decodedOrigin
|
|
}
|
|
if range_ := item.Range(); range_ != nil {
|
|
decodedRange := reportFloatFromFBS(*range_)
|
|
decoded.Range = &decodedRange
|
|
}
|
|
if fleet := item.Fleet(); fleet != nil {
|
|
decodedFleet := string(fleet)
|
|
decoded.Fleet = &decodedFleet
|
|
}
|
|
|
|
result.LocalGroup[i] = decoded
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportOtherGroupVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.OtherGroupLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.OtherGroup = make([]model.OtherGroup, length)
|
|
item := new(fbs.OtherGroup)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.OtherGroup(item, i) {
|
|
return fmt.Errorf("decode report other group %d: group is missing", i)
|
|
}
|
|
|
|
number, err := uint64ToUint(item.Number(), "number")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report other group %d: %w", i, err)
|
|
}
|
|
destination, err := uint64ToUint(item.Destination(), "destination")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report other group %d: %w", i, err)
|
|
}
|
|
tech, err := decodeReportTechMapFromOtherGroup(item, i)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
decoded := model.OtherGroup{
|
|
Number: number,
|
|
Class: string(item.Class()),
|
|
Tech: tech,
|
|
Cargo: string(item.Cargo()),
|
|
Load: reportFloatFromFBS(item.Load()),
|
|
Destination: destination,
|
|
Speed: reportFloatFromFBS(item.Speed()),
|
|
Mass: reportFloatFromFBS(item.Mass()),
|
|
}
|
|
|
|
if origin := item.Origin(); origin != nil {
|
|
decodedOrigin, err := uint64ToUint(*origin, "origin")
|
|
if err != nil {
|
|
return fmt.Errorf("decode report other group %d: %w", i, err)
|
|
}
|
|
decoded.Origin = &decodedOrigin
|
|
}
|
|
if range_ := item.Range(); range_ != nil {
|
|
decodedRange := reportFloatFromFBS(*range_)
|
|
decoded.Range = &decodedRange
|
|
}
|
|
|
|
result.OtherGroup[i] = decoded
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportUnidentifiedGroupVector(flatReport *fbs.Report, result *model.Report) error {
|
|
length := flatReport.UnidentifiedGroupLength()
|
|
if length == 0 {
|
|
return nil
|
|
}
|
|
|
|
result.UnidentifiedGroup = make([]model.UnidentifiedGroup, length)
|
|
item := new(fbs.UnidentifiedGroup)
|
|
for i := 0; i < length; i++ {
|
|
if !flatReport.UnidentifiedGroup(item, i) {
|
|
return fmt.Errorf("decode report unidentified group %d: group is missing", i)
|
|
}
|
|
|
|
result.UnidentifiedGroup[i] = model.UnidentifiedGroup{
|
|
X: reportFloatFromFBS(item.X()),
|
|
Y: reportFloatFromFBS(item.Y()),
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func decodeReportRouteMap(flatRoute *fbs.Route, routeIndex int) (map[uint]string, error) {
|
|
length := flatRoute.RouteLength()
|
|
if length == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
result := make(map[uint]string, length)
|
|
item := new(fbs.RouteEntry)
|
|
for i := 0; i < length; i++ {
|
|
if !flatRoute.Route(item, i) {
|
|
return nil, fmt.Errorf("decode report route %d entry %d: route entry is missing", routeIndex, i)
|
|
}
|
|
|
|
key, err := uint64ToUint(item.Key(), "route key")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decode report route %d entry %d: %w", routeIndex, i, err)
|
|
}
|
|
result[key] = string(item.Value())
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func decodeReportTechMapFromOtherGroup(group *fbs.OtherGroup, groupIndex int) (map[string]model.Float, error) {
|
|
length := group.TechLength()
|
|
if length == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
result := make(map[string]model.Float, length)
|
|
item := new(fbs.TechEntry)
|
|
for i := 0; i < length; i++ {
|
|
if !group.Tech(item, i) {
|
|
return nil, fmt.Errorf("decode report other group %d tech entry %d: tech entry is missing", groupIndex, i)
|
|
}
|
|
result[string(item.Key())] = reportFloatFromFBS(item.Value())
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func decodeReportTechMapFromLocalGroup(group *fbs.LocalGroup, groupIndex int) (map[string]model.Float, error) {
|
|
length := group.TechLength()
|
|
if length == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
result := make(map[string]model.Float, length)
|
|
item := new(fbs.TechEntry)
|
|
for i := 0; i < length; i++ {
|
|
if !group.Tech(item, i) {
|
|
return nil, fmt.Errorf("decode report local group %d tech entry %d: tech entry is missing", groupIndex, i)
|
|
}
|
|
result[string(item.Key())] = reportFloatFromFBS(item.Value())
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func encodeReportOffsetVector(
|
|
builder *flatbuffers.Builder,
|
|
length int,
|
|
startVector func(*flatbuffers.Builder, int) flatbuffers.UOffsetT,
|
|
offsets []flatbuffers.UOffsetT,
|
|
) flatbuffers.UOffsetT {
|
|
if length == 0 {
|
|
return 0
|
|
}
|
|
|
|
startVector(builder, length)
|
|
for i := length - 1; i >= 0; i-- {
|
|
builder.PrependUOffsetT(offsets[i])
|
|
}
|
|
return builder.EndVector(length)
|
|
}
|
|
|
|
func encodeReportBattleSummaries(builder *flatbuffers.Builder, summaries []model.BattleSummary) flatbuffers.UOffsetT {
|
|
if len(summaries) == 0 {
|
|
return 0
|
|
}
|
|
|
|
offsets := make([]flatbuffers.UOffsetT, len(summaries))
|
|
for i := range summaries {
|
|
hi, lo := uuidToHiLo(summaries[i].ID)
|
|
fbs.BattleSummaryStart(builder)
|
|
fbs.BattleSummaryAddId(builder, commonfbs.CreateUUID(builder, hi, lo))
|
|
fbs.BattleSummaryAddPlanet(builder, uint64(summaries[i].Planet))
|
|
fbs.BattleSummaryAddShots(builder, uint64(summaries[i].Shots))
|
|
offsets[i] = fbs.BattleSummaryEnd(builder)
|
|
}
|
|
|
|
fbs.ReportStartBattleVector(builder, len(offsets))
|
|
for i := len(offsets) - 1; i >= 0; i-- {
|
|
builder.PrependUOffsetT(offsets[i])
|
|
}
|
|
return builder.EndVector(len(offsets))
|
|
}
|
|
|
|
func encodeReportRouteEntryVector(builder *flatbuffers.Builder, route map[uint]string) flatbuffers.UOffsetT {
|
|
if len(route) == 0 {
|
|
return 0
|
|
}
|
|
|
|
keys := make([]uint, 0, len(route))
|
|
for key := range route {
|
|
keys = append(keys, key)
|
|
}
|
|
sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
|
|
|
|
offsets := make([]flatbuffers.UOffsetT, len(keys))
|
|
for i, key := range keys {
|
|
value := builder.CreateString(route[key])
|
|
fbs.RouteEntryStart(builder)
|
|
fbs.RouteEntryAddKey(builder, uint64(key))
|
|
fbs.RouteEntryAddValue(builder, value)
|
|
offsets[i] = fbs.RouteEntryEnd(builder)
|
|
}
|
|
|
|
fbs.RouteStartRouteVector(builder, len(offsets))
|
|
for i := len(offsets) - 1; i >= 0; i-- {
|
|
builder.PrependUOffsetT(offsets[i])
|
|
}
|
|
return builder.EndVector(len(offsets))
|
|
}
|
|
|
|
func encodeReportTechEntryVector(builder *flatbuffers.Builder, tech map[string]model.Float) flatbuffers.UOffsetT {
|
|
if len(tech) == 0 {
|
|
return 0
|
|
}
|
|
|
|
keys := make([]string, 0, len(tech))
|
|
for key := range tech {
|
|
keys = append(keys, key)
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
offsets := make([]flatbuffers.UOffsetT, len(keys))
|
|
for i, key := range keys {
|
|
encodedKey := builder.CreateString(key)
|
|
fbs.TechEntryStart(builder)
|
|
fbs.TechEntryAddKey(builder, encodedKey)
|
|
fbs.TechEntryAddValue(builder, reportFloatToFBS(tech[key]))
|
|
offsets[i] = fbs.TechEntryEnd(builder)
|
|
}
|
|
|
|
fbs.OtherGroupStartTechVector(builder, len(offsets))
|
|
for i := len(offsets) - 1; i >= 0; i-- {
|
|
builder.PrependUOffsetT(offsets[i])
|
|
}
|
|
return builder.EndVector(len(offsets))
|
|
}
|
|
|
|
func reportFloatToFBS(value model.Float) float32 {
|
|
return float32(value.F())
|
|
}
|
|
|
|
func reportFloatFromFBS(value float32) model.Float {
|
|
return model.Float(float64(value))
|
|
}
|
|
|
|
func uint64ToUint(value uint64, field string) (uint, error) {
|
|
maxUint := uint64(^uint(0))
|
|
if value > maxUint {
|
|
return 0, fmt.Errorf("%s value %d overflows uint", field, value)
|
|
}
|
|
return uint(value), nil
|
|
}
|
|
|
|
// GameReportRequestToPayload converts model.GameReportRequest to
|
|
// FlatBuffers bytes suitable for the authenticated gateway transport.
|
|
func GameReportRequestToPayload(req *model.GameReportRequest) ([]byte, error) {
|
|
if req == nil {
|
|
return nil, errors.New("encode game report request payload: request is nil")
|
|
}
|
|
|
|
builder := flatbuffers.NewBuilder(64)
|
|
|
|
fbs.GameReportRequestStart(builder)
|
|
hi, lo := uuidToHiLo(req.GameID)
|
|
fbs.GameReportRequestAddGameId(builder, commonfbs.CreateUUID(builder, hi, lo))
|
|
fbs.GameReportRequestAddTurn(builder, uint32(req.Turn))
|
|
offset := fbs.GameReportRequestEnd(builder)
|
|
fbs.FinishGameReportRequestBuffer(builder, offset)
|
|
|
|
return builder.FinishedBytes(), nil
|
|
}
|
|
|
|
// PayloadToGameReportRequest converts FlatBuffers payload bytes into
|
|
// model.GameReportRequest.
|
|
func PayloadToGameReportRequest(data []byte) (result *model.GameReportRequest, err error) {
|
|
if len(data) == 0 {
|
|
return nil, errors.New("decode game report request payload: data is empty")
|
|
}
|
|
|
|
defer func() {
|
|
if recovered := recover(); recovered != nil {
|
|
result = nil
|
|
err = fmt.Errorf("decode game report request payload: panic recovered: %v", recovered)
|
|
}
|
|
}()
|
|
|
|
req := fbs.GetRootAsGameReportRequest(data, 0)
|
|
gameID := req.GameId(nil)
|
|
if gameID == nil {
|
|
return nil, errors.New("decode game report request payload: game_id is missing")
|
|
}
|
|
return &model.GameReportRequest{
|
|
GameID: uuidFromHiLo(gameID.Hi(), gameID.Lo()),
|
|
Turn: uint(req.Turn()),
|
|
}, nil
|
|
}
|