From 21c2f02dc50b5e913027d3c254470f2ae80496cd Mon Sep 17 00:00:00 2001 From: Natalie Rose Date: Fri, 28 Aug 2026 13:58:57 +1000 Subject: [PATCH] Add Body get_buildings_resources --- docs/Body.pod | 57 +++++++++++++++++++++++++++++ lib/Lacuna/RPC/Body.pm | 20 +++++++++++ lib/Lacuna/RPC/Role/Building.pm | 63 ++++++++++++++++++++++++++++++++- v2-api/argumentMap.json | 6 ++++ 4 files changed, 145 insertions(+), 1 deletion(-) diff --git a/docs/Body.pod b/docs/Body.pod index 8f204d7c..362e4283 100644 --- a/docs/Body.pod +++ b/docs/Body.pod @@ -165,6 +165,63 @@ A session id. The id of the body you wish to retrieve the buildings on. +=head2 get_buildings_resources ( session_id, body_id ) + +Identical to C, but every building entry additionally carries a C object describing that building's contribution to the planet's economy: its hourly production/consumption and storage capacity for each resource, plus per-food-type and per-ore-type production breakdowns. + +The C object contains the nine always-present aggregate keys shown below (C, C, C, C, C, C, C, C, C), plus C and C. It also contains a C map when the building produces one or more food items, and an C map when the building produces ore; both are omitted entirely when they would be empty. + +The Mining Ministry is a special case: its ore output is driven by its deployed mining platforms and the ships servicing them rather than by the building itself, so C, C and the C map are all omitted for it (computing them would require walking the platforms, their asteroids and the mining fleet). + + { + "buildings" : { + "id-goes-here" : { + "name" : "Wheat Farm", + "x" : 1, + "y" : -1, + "url" : "/wheatfarm", + "level" : 3, + "image" : "wheatfarm3", + "efficiency" : 100, + "resources" : { + "food_hour" : 350, + "food_capacity" : 0, + "ore_hour" : 0, + "ore_capacity" : 0, + "water_hour" : 0, + "water_capacity" : 0, + "waste_hour" : 35, + "waste_capacity" : 0, + "energy_hour" : 0, + "energy_capacity" : 0, + "happiness_hour" : 0, + "food" : { # only included when the building produces food + "wheat" : 350 + }, + "ore" : { # only included when the building produces ore + "rutile" : 0, + "chromite" : 0 + # ...one key per ore type + } + } + } + }, + "body" : { + "surface_image" : "surface-e" + }, + "status" : { ... } + } + +Throws 1002 and 1010. + +=head3 session_id + +A session id. + +=head3 body_id + +The id of the body you wish to retrieve the buildings on. + =head2 repair_list ( session_id, body_id, building_ids) Repairs buildings in order of ids gived in array. diff --git a/lib/Lacuna/RPC/Body.pm b/lib/Lacuna/RPC/Body.pm index f0b02d58..3d0b28dd 100644 --- a/lib/Lacuna/RPC/Body.pm +++ b/lib/Lacuna/RPC/Body.pm @@ -121,6 +121,25 @@ sub get_buildings { }; } +sub get_buildings_resources { + my ($self, $session_id, $body_id) = @_; + my $session = $self->get_session({session_id => $session_id, body_id => $body_id}); + my $empire = $session->current_empire; + my $body = $session->current_body; + if ($body->needs_surface_refresh) { + $body->needs_surface_refresh(0); + $body->update; + } + + return { + buildings => $self->out_buildings($body, { include_resources => 1 }), + body => { + surface_image => $body->surface, + }, + status => $self->format_status($session, $body), + }; +} + sub repair_list { my ($self, $session_id, $body_id, $building_ids) = @_; @@ -592,6 +611,7 @@ __PACKAGE__->register_rpc_method_names(qw( abandon rename get_buildings + get_buildings_resources get_buildable get_buildable_locations get_status diff --git a/lib/Lacuna/RPC/Role/Building.pm b/lib/Lacuna/RPC/Role/Building.pm index 000d85c1..6e3a305a 100644 --- a/lib/Lacuna/RPC/Role/Building.pm +++ b/lib/Lacuna/RPC/Role/Building.pm @@ -1,11 +1,16 @@ package Lacuna::RPC::Role::Building; use Moose::Role; +use Lacuna::Constants qw(ORE_TYPES); # Return a 'buildings' hash suitable for output to the RPC # +# Pass { include_resources => 1 } to attach a 'resources' hash (production, +# storage and per-food/per-ore breakdowns) to each building - see get_buildings_resources. +# sub out_buildings { - my ($self, $body) = @_; + my ($self, $body, $options) = @_; + $options //= {}; my $out; @@ -33,9 +38,65 @@ sub out_buildings { if ($building->efficiency < 100) { $out->{$building->id}{repair_costs} = $building->get_repair_costs; } + if ($options->{include_resources}) { + $out->{$building->id}{resources} = $self->building_resources($building); + } } return $out; } +# Return the hourly production/consumption, storage capacity and per-type +# production breakdown for a single building. +# +sub building_resources { + my ($self, $building) = @_; + my $body = $building->body; + + my %resources = ( + food_hour => 0 + $building->food_hour, + food_capacity => 0 + $building->food_capacity, + water_hour => 0 + $building->water_hour, + water_capacity => 0 + $building->water_capacity, + waste_hour => 0 + $building->waste_hour, + waste_capacity => 0 + $building->waste_capacity, + energy_hour => 0 + $building->energy_hour, + energy_capacity => 0 + $building->energy_capacity, + happiness_hour => 0 + $building->happiness_hour, + ); + + # Per-food-type production, for the food items this building actually makes. + my %food; + foreach my $type (@{$building->produces_food_items}) { + my $method = $type . '_production_hour'; + $food{$type} = 0 + $building->$method; + } + $resources{food} = \%food if %food; + + # The Mining Ministry's ore output comes from its deployed mining platforms + # and the ships servicing them, not from this building's own constants. + # Reproducing that here would mean several extra queries (platforms, their + # asteroids and ore balances, mining ships) plus the full shipping-capacity + # calculation, so we deliberately omit all ore figures for the Ministry. + unless ($building->isa('Lacuna::DB::Result::Building::Ore::Ministry')) { + $resources{ore_hour} = 0 + $building->ore_hour; + $resources{ore_capacity} = 0 + $building->ore_capacity; + + # Per-ore-type production, splitting the building's generic ore output by + # the body's ore concentration - mirrors Planet::recalc_stats' "local + # ore production". + my $ore_production_hour = $building->ore_production_hour; + my $total_concentration = $body->total_ore_concentration; + if ($ore_production_hour && $total_concentration) { + my %ore; + foreach my $type (ORE_TYPES) { + $ore{$type} = 0 + sprintf('%.0f', $body->$type * $ore_production_hour / $total_concentration); + } + $resources{ore} = \%ore; + } + } + + return \%resources; +} + 1; diff --git a/v2-api/argumentMap.json b/v2-api/argumentMap.json index 47668d4c..09f17573 100644 --- a/v2-api/argumentMap.json +++ b/v2-api/argumentMap.json @@ -668,6 +668,12 @@ "required": true } ], + "/body/get_buildings_resources": [ + { + "name": "body_id", + "required": true + } + ], "/body/get_status": [ { "name": "body_id", -- 2.51.2