Ejemplo n.º 1
0
TMap<FFlareResourceDescription*, WorldHelper::FlareResourceStats> SectorHelper::ComputeSectorResourceStats(UFlareSimulatedSector* Sector, bool IncludeStorage)
{
	TMap<FFlareResourceDescription*, WorldHelper::FlareResourceStats> WorldStats;

	// Init
	for(int32 ResourceIndex = 0; ResourceIndex < Sector->GetGame()->GetResourceCatalog()->Resources.Num(); ResourceIndex++)
	{
		FFlareResourceDescription* Resource = &Sector->GetGame()->GetResourceCatalog()->Resources[ResourceIndex]->Data;
		WorldHelper::FlareResourceStats ResourceStats;
		ResourceStats.Production = 0;
		ResourceStats.Consumption = 0;
		ResourceStats.Balance = 0;
		ResourceStats.Stock = 0;
		ResourceStats.Capacity = 0;

		WorldStats.Add(Resource, ResourceStats);
	}

	for (int SpacecraftIndex = 0; SpacecraftIndex < Sector->GetSectorSpacecrafts().Num(); SpacecraftIndex++)
	{
		UFlareSimulatedSpacecraft* Spacecraft = Sector->GetSectorSpacecrafts()[SpacecraftIndex];

		if(!IncludeStorage && Spacecraft->HasCapability(EFlareSpacecraftCapability::Storage))
		{
			continue;
		}

		// Stock
		TArray<FFlareCargo>& CargoBaySlots = Spacecraft->GetActiveCargoBay()->GetSlots();
		for (int CargoIndex = 0; CargoIndex < CargoBaySlots.Num(); CargoIndex++)
		{
			FFlareCargo& Cargo = CargoBaySlots[CargoIndex];

			if (!Cargo.Resource)
			{
				continue;
			}

			WorldHelper::FlareResourceStats *ResourceStats = &WorldStats[Cargo.Resource];

			FFlareResourceUsage Usage = Spacecraft->GetResourceUseType(Cargo.Resource);

			if(Usage.HasUsage(EFlareResourcePriceContext::FactoryInput) || Usage.HasUsage(EFlareResourcePriceContext::ConsumerConsumption) || Usage.HasUsage(EFlareResourcePriceContext::MaintenanceConsumption) || Usage.HasUsage(EFlareResourcePriceContext::HubInput))
			{
				ResourceStats->Capacity += Spacecraft->GetActiveCargoBay()->GetSlotCapacity() - Cargo.Quantity;
			}

			if(Usage.HasUsage(EFlareResourcePriceContext::FactoryOutput) || Usage.HasUsage(EFlareResourcePriceContext::MaintenanceConsumption) || Usage.HasUsage(EFlareResourcePriceContext::HubOutput))
			{
				ResourceStats->Stock += Cargo.Quantity;
			}
		}

		for (int32 FactoryIndex = 0; FactoryIndex < Spacecraft->GetFactories().Num(); FactoryIndex++)
		{
			UFlareFactory* Factory = Spacecraft->GetFactories()[FactoryIndex];

			if(Factory->IsShipyard() && !Factory->IsActive())
			{
				const FFlareProductionData* ProductionData = Spacecraft->GetNextOrderShipProductionData(Factory->IsLargeShipyard()? EFlarePartSize::L : EFlarePartSize::S);

				if (ProductionData)
				{
					for(const FFlareFactoryResource& FactoryResource : ProductionData->InputResources)
					{
						const FFlareResourceDescription* Resource = &FactoryResource.Resource->Data;
						WorldHelper::FlareResourceStats *ResourceStats = &WorldStats[Resource];

						int64 ProductionDuration = ProductionData->ProductionTime;

						float Flow = 0;

						if (ProductionDuration == 0)
						{
							Flow = 1;
						}
						else
						{
							Flow = (float) FactoryResource.Quantity / float(ProductionDuration);
						}

						ResourceStats->Consumption += Flow;
					}
				}

				continue;
			}

			if ((!Factory->IsActive() || !Factory->IsNeedProduction()))
			{
				// No resources needed
				continue;
			}

			// Input flow
			for (int32 ResourceIndex = 0; ResourceIndex < Factory->GetInputResourcesCount(); ResourceIndex++)
			{
				FFlareResourceDescription* Resource = Factory->GetInputResource(ResourceIndex);
				WorldHelper::FlareResourceStats *ResourceStats = &WorldStats[Resource];

				int64 ProductionDuration = Factory->GetProductionDuration();

				float Flow = 0;

				if (ProductionDuration == 0)
				{
					Flow = 1;
				}
				else
				{
					Flow = (float) Factory->GetInputResourceQuantity(ResourceIndex) / float(ProductionDuration);
				}

				ResourceStats->Consumption += Flow;
			}

			// Ouput flow
			for (int32 ResourceIndex = 0; ResourceIndex < Factory->GetOutputResourcesCount(); ResourceIndex++)
			{
				FFlareResourceDescription* Resource = Factory->GetOutputResource(ResourceIndex);
				WorldHelper::FlareResourceStats *ResourceStats = &WorldStats[Resource];

				int64 ProductionDuration = Factory->GetProductionDuration();
				if (ProductionDuration == 0)
				{
					ProductionDuration = 10;
				}

				float Flow = (float) Factory->GetOutputResourceQuantity(ResourceIndex) / float(ProductionDuration);
				ResourceStats->Production+= Flow;
			}
		}
	}

	// FS
	FFlareResourceDescription* FleetSupply = Sector->GetGame()->GetScenarioTools()->FleetSupply;
	WorldHelper::FlareResourceStats *FSResourceStats = &WorldStats[FleetSupply];
	FFlareFloatBuffer* Stats = &Sector->GetData()->FleetSupplyConsumptionStats;
	float MeanConsumption = Stats->GetMean(0, Stats->MaxSize-1);
	FSResourceStats->Consumption += MeanConsumption;
	FSResourceStats->Capacity += Stats->GetValue(0);


	// Customer flow
	for (int32 ResourceIndex = 0; ResourceIndex < Sector->GetGame()->GetResourceCatalog()->ConsumerResources.Num(); ResourceIndex++)
	{
		FFlareResourceDescription* Resource = &Sector->GetGame()->GetResourceCatalog()->ConsumerResources[ResourceIndex]->Data;
		WorldHelper::FlareResourceStats *ResourceStats = &WorldStats[Resource];

		ResourceStats->Consumption += Sector->GetPeople()->GetRessourceConsumption(Resource, false);
	}

	// Balance
	for(int32 ResourceIndex = 0; ResourceIndex < Sector->GetGame()->GetResourceCatalog()->Resources.Num(); ResourceIndex++)
	{
		FFlareResourceDescription* Resource = &Sector->GetGame()->GetResourceCatalog()->Resources[ResourceIndex]->Data;
		WorldHelper::FlareResourceStats *ResourceStats = &WorldStats[Resource];

		ResourceStats->Balance = ResourceStats->Production - ResourceStats->Consumption;

		/*FLOGV("World stats for %s: Production=%f Consumption=%f Balance=%f Stock=%d",
			  *Resource->Name.ToString(),
			  ResourceStats->Production,
			  ResourceStats->Consumption,
			  ResourceStats->Balance,
			  ResourceStats->Stock);*/
	}

	return WorldStats;

}
Ejemplo n.º 2
0
UFlareSimulatedSpacecraft*  SectorHelper::FindTradeStation(FlareTradeRequest Request)
{
	//FLOGV("FindTradeStation of %s for %s  (%d)", *Request.Resource->Acronym.ToString(), *Request.Client->GetImmatriculation().ToString(), (Request.Operation + 0));

	if(!Request.Client || !Request.Client->GetCurrentSector())
	{
		FLOG("Invalid find trade query");
		return NULL;
	}

	UFlareCompany* ClientCompany = Request.AllowUseNoTradeForMe ? Request.Client->GetCompany() : nullptr;


	UFlareSimulatedSector* Sector = Request.Client->GetCurrentSector();
	TArray<UFlareSimulatedSpacecraft*>& SectorStations = Sector->GetSectorStations();

	float UnloadQuantityScoreMultiplier = 0;
	float LoadQuantityScoreMultiplier = 0;
	float SellQuantityScoreMultiplier = 0;
	float BuyQuantityScoreMultiplier = 0;
	float FullRatioBonus = 0;
	float EmptyRatioBonus = 0;
	bool  NeedInput = false;
	bool  NeedOutput = false;

	switch(Request.Operation)
	{
		case EFlareTradeRouteOperation::Buy:
			BuyQuantityScoreMultiplier = 10.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::Sell:
			SellQuantityScoreMultiplier = 10.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
		case EFlareTradeRouteOperation::Load:
			LoadQuantityScoreMultiplier = 10.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::Unload:
			UnloadQuantityScoreMultiplier = 10.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
		case EFlareTradeRouteOperation::LoadOrBuy:
			LoadQuantityScoreMultiplier = 10.f;
			BuyQuantityScoreMultiplier = 1.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::UnloadOrSell:
			UnloadQuantityScoreMultiplier = 10.f;
			SellQuantityScoreMultiplier = 1.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
	}

	float BestScore = 0;
	UFlareSimulatedSpacecraft* BestStation = NULL;
	uint32 AvailableQuantity = Request.Client->GetActiveCargoBay()->GetResourceQuantity(Request.Resource, ClientCompany);
	uint32 FreeSpace = Request.Client->GetActiveCargoBay()->GetFreeSpaceForResource(Request.Resource, ClientCompany);

	for (int32 StationIndex = 0; StationIndex < SectorStations.Num(); StationIndex++)
	{
		UFlareSimulatedSpacecraft* Station = SectorStations[StationIndex];
		//FLOGV("   Check trade for %s", *Station->GetImmatriculation().ToString());


		FText Unused;
		if(!Request.Client->CanTradeWith(Station, Unused))
		{
			//FLOG(" cannot trade with");
			continue;
		}

		if(!Request.AllowStorage && Station->HasCapability(EFlareSpacecraftCapability::Storage))
		{
			continue;
		}

		FFlareResourceUsage StationResourceUsage = Station->GetResourceUseType(Request.Resource);


		if(NeedOutput && (!StationResourceUsage.HasUsage(EFlareResourcePriceContext::FactoryOutput) &&
						  !StationResourceUsage.HasUsage(EFlareResourcePriceContext::ConsumerConsumption) &&
						  !StationResourceUsage.HasUsage(EFlareResourcePriceContext::HubOutput)))
		{
			//FLOG(" need output but dont provide it");
			continue;
		}

		if(NeedInput && (!StationResourceUsage.HasUsage(EFlareResourcePriceContext::FactoryInput) &&
						 !StationResourceUsage.HasUsage(EFlareResourcePriceContext::ConsumerConsumption) &&
						 !StationResourceUsage.HasUsage(EFlareResourcePriceContext::MaintenanceConsumption) &&
						 !StationResourceUsage.HasUsage(EFlareResourcePriceContext::HubInput)))
		{
			//FLOG(" need input but dont provide it");
			continue;
		}

		int32 StationFreeSpace = Station->GetActiveCargoBay()->GetFreeSpaceForResource(Request.Resource, ClientCompany);
		int32 StationResourceQuantity = Station->GetActiveCargoBay()->GetResourceQuantity(Request.Resource, ClientCompany);

		if (!Station->IsUnderConstruction() && Station->IsComplex() && !Request.AllowFullStock)
		{
			if(Station->GetActiveCargoBay()->WantBuy(Request.Resource, ClientCompany) && Station->GetActiveCargoBay()->WantSell(Request.Resource, ClientCompany))
			{
				int32 TotalCapacity = Station->GetActiveCargoBay()->GetTotalCapacityForResource(Request.Resource, ClientCompany);
				StationFreeSpace = FMath::Max(0, StationFreeSpace - TotalCapacity / 2);
				StationResourceQuantity = FMath::Max(0, StationResourceQuantity - TotalCapacity / 2);
			}
		}

		if (StationFreeSpace == 0 && StationResourceQuantity == 0)
		{
			//FLOG(" need quantity or resource");
			continue;
		}

		float Score = 0;
		float FullRatio =  (float) StationResourceQuantity / (float) (StationResourceQuantity + StationFreeSpace);
		float EmptyRatio = 1 - FullRatio;
		uint32 UnloadMaxQuantity  = 0;
		uint32 LoadMaxQuantity  = 0;


		if(!Station->IsUnderConstruction())
		{
			// Check cargo limit
			if(NeedOutput && Request.CargoLimit != -1 && FullRatio < Request.CargoLimit / Station->GetLevel())
			{
				continue;
			}

			if(NeedInput && Request.CargoLimit != -1 && FullRatio > (1.f - (1.f - Request.CargoLimit) / Station->GetLevel()))
			{
				continue;
			}
		}
		else if (Station->HasCapability(EFlareSpacecraftCapability::Storage))
		{
			continue;
		}

		if(Station->GetActiveCargoBay()->WantBuy(Request.Resource, ClientCompany))
		{
			UnloadMaxQuantity = StationFreeSpace;
			UnloadMaxQuantity  = FMath::Min(UnloadMaxQuantity , AvailableQuantity);
		}

		if(Station->GetActiveCargoBay()->WantSell(Request.Resource, ClientCompany))
		{
			LoadMaxQuantity = StationResourceQuantity;
			LoadMaxQuantity = FMath::Min(LoadMaxQuantity , FreeSpace);
		}

		if(Station->GetCompany() == Request.Client->GetCompany())
		{
			Score += UnloadMaxQuantity * UnloadQuantityScoreMultiplier;
			Score += LoadMaxQuantity * LoadQuantityScoreMultiplier;
		}
		else
		{
			FFlareResourceUsage ResourceUsage = Station->GetResourceUseType(Request.Resource);

			int32 ResourcePrice = 0;
			if(NeedInput)
			{
				ResourcePrice = Sector->GetTransfertResourcePrice(NULL, Station, Request.Resource);
			}
			else
			{
				ResourcePrice = Sector->GetTransfertResourcePrice(Station, NULL, Request.Resource);
			}



			uint32 MaxBuyableQuantity = Request.Client->GetCompany()->GetMoney() / SectorHelper::GetBuyResourcePrice(Sector, Request.Resource, ResourceUsage);
			LoadMaxQuantity = FMath::Min(LoadMaxQuantity , MaxBuyableQuantity);

			uint32 MaxSellableQuantity = Station->GetCompany()->GetMoney() / SectorHelper::GetSellResourcePrice(Sector, Request.Resource, ResourceUsage);
			UnloadMaxQuantity = FMath::Min(UnloadMaxQuantity , MaxSellableQuantity);

			Score += UnloadMaxQuantity * SellQuantityScoreMultiplier;
			Score += LoadMaxQuantity * BuyQuantityScoreMultiplier;
		}

		Score *= 1 + (FullRatio * FullRatioBonus) + (EmptyRatio * EmptyRatioBonus);

		if(Station->IsUnderConstruction())
		{
			Score *= 10000;
			/*FLOGV("Station %s is under construction. Score %f, BestScore %f",
				  *Station->GetImmatriculation().ToString(),
				  Score,
				  BestScore)*/
		}
		else if(Station->HasCapability(EFlareSpacecraftCapability::Storage))
		{
			Score *= 0.01;
		}

		if(Score > 0 && Score > BestScore)
		{
			BestScore = Score;
			BestStation = Station;
		}
	}

	//FLOGV("FindTradeStation result %p", BestStation);

	return BestStation;
}