implement building system

This commit is contained in:
2026-04-19 20:50:42 +02:00
parent c70b5c8f08
commit bf29cc40e3
19 changed files with 1818 additions and 7 deletions

View File

@@ -0,0 +1,88 @@
#pragma once
#include <deque>
#include <functional>
#include <map>
#include <optional>
#include <random>
#include <string>
#include <utility>
#include <vector>
#include <QPoint>
#include "BeltSystem.h"
#include "Building.h"
#include "BuildingType.h"
#include "EntityId.h"
#include "GameConfig.h"
#include "Rotation.h"
#include "Tick.h"
// Manages building placement, construction queuing, and the per-tick
// production loop (belt→building pull, production, building→belt push).
// Belt and Splitter types are forwarded to BeltSystem rather than stored
// as Building instances.
class BuildingSystem
{
public:
BuildingSystem(const GameConfig& config,
BeltSystem& belts,
std::function<EntityId()> allocateId,
std::function<void(int)> addBuildingBlocks,
std::mt19937& rng);
// -- Placement / demolish ------------------------------------------------
// Returns the new entity id. Belt and Splitter register with BeltSystem
// directly; other types enter the construction queue.
EntityId place(BuildingType type, QPoint anchor, Rotation rotation,
Tick currentTick);
// Remove a building or construction site by id. Returns the refund in
// building blocks (floor(cost * refundPercentage / 100)). Returns 0 for
// unknown ids.
int demolish(EntityId id);
// Set the recipe (or blueprint id for shipyard) on a building or queued
// construction site. Clears both buffers on an operational building.
void setRecipe(EntityId id, const std::string& recipeId);
// -- Tick hooks (called from Simulation::tick in the documented order) ---
void tickConstruction(Tick currentTick);
void tickBeltPull();
void tickProduction(Tick currentTick);
void tickBeltPush();
// -- Queries -------------------------------------------------------------
const Building* findBuilding(EntityId id) const;
const ConstructionSite* findSite(EntityId id) const;
std::vector<Building> allBuildings() const;
std::vector<ConstructionSite> allSites() const;
bool isTileOccupied(QPoint tile) const;
private:
struct BeltEntry
{
QPoint tile;
BuildingType type; // Belt or Splitter
};
const BuildingDef* findBuildingDef(BuildingType type) const;
const RecipeDef* findRecipe(const std::string& id, BuildingType type) const;
void initBuffers(Building& b, const RecipeDef& recipe) const;
std::vector<Port> computeInputPorts(const Building& b) const;
std::vector<Item> rollReprocessingOutput(const RecipeDef& recipe);
const GameConfig& m_config;
BeltSystem& m_belts;
std::function<EntityId()> m_allocateId;
std::function<void(int)> m_addBuildingBlocks;
std::mt19937& m_rng;
std::vector<Building> m_buildings;
std::deque<ConstructionSite> m_constructionQueue;
std::map<EntityId, BeltEntry> m_beltEntities;
// Maps every occupied body-cell coordinate to the entity that owns it.
std::map<std::pair<int, int>, EntityId> m_tileOccupancy;
};