Files
Ivazovsky/Source/GraffModule/Private/cppGI.cpp
T
2025-11-21 18:00:43 +05:00

357 lines
11 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "cppGI.h"
#include "Kismet/GameplayStatics.h"
#include "Misc/paths.h"
#include "Engine/levelstreamingdynamic.h"
#include "cppFuncLibrary.h"
#include "Misc/FileHelper.h"
#include "Async/Async.h"
/*for working tarray::Contains*/
static bool operator==(const Fcppcoords& c1, const Fcppcoords& c2) {
return c1.flat == c2.flat &&
c1.floor == c2.floor &&
c1.house == c2.house &&
c1.section == c2.section &&
c1.type == c2.type &&
c1.zone == c2.zone;
}
/*for working tarray::Contains*/
static bool operator==(const FcppLevelStruct& c1, const FcppLevelStruct& c2) {
return c1.anotherLvl == c2.anotherLvl &&
c1.coords == c2.coords &&
c1.dontUnload == c2.dontUnload &&
c1.path == c2.path &&
c1.uniqName == c2.uniqName &&
c1.Z == c2.Z;
}
TArray<ULevelStreaming*> UcppGI::cppLvlManage(UObject* WorldContextObject, Fcppcoords currentCoords, uint8 currentState)
{
TArray<ULevelStreaming*> outStruct;
bool loadthis;
auto is3DTour = currentState == 11;
/*for 3Dtour only*/
if (is3DTour && currentCoords.house < 1) {
cppLoadList.AddUnique(Fcppcoords(-1,0,currentCoords.zone,-2,-2,1));
}
cppLoadList.AddUnique(currentCoords);
for (const auto& lvl : cppLevels)
{
loadthis = 0;
if (cppBlackList.Contains(lvl));
else if (cppWhiteList.Contains(lvl)) loadthis = true;
else {
bool ceq[7];
for (const auto& crd : cppLoadList) // here is filter code
{
cppCoordsEq(crd, lvl.coords, true, false, ceq[0], ceq[1], ceq[2], ceq[3], ceq[4], ceq[5], ceq[6]);
if (
(
(
(ceq[0] || !is3DTour || lvl.coords.flat == -1) && ceq[5]
)
|| (is3DTour ? lvl.anotherLvl >= 1 && lvl.anotherLvl == crd.flat : lvl.anotherLvl >= 1 && lvl.coords.floor < crd.floor)
)
&& ceq[3] && ceq[4] && ceq[2]
) loadthis = true; //load all on floor and under 2-floor flat, and full 2-floor flat in 3d tour
//if (ceq[6]) loadthis = true; //classic load with parallax
}
}
if (loadthis) {
if (cppCreatedList.Contains(lvl.uniqName)) { /*if already created level*/
ULevelStreaming* outlvl_ = nullptr;
if ((outlvl_ = UGameplayStatics::GetStreamingLevel(WorldContextObject, lvl.uniqName)) != nullptr) {
outlvl_->SetShouldBeLoaded(true);
outlvl_->SetShouldBeVisible(true);
cpploadedList.Add(lvl.uniqName);
outStruct.Add(outlvl_);
}
}
else { /*load new level instance*/
bool b;
if (ULevelStreamingDynamic* newlvl = ULevelStreamingDynamic::LoadLevelInstance(WorldContextObject, lvl.path, FVector(0, 0, lvl.Z), FRotator(0), b, lvl.uniqName.ToString())) {
newlvl->SetPriority(lvl.coords.flat == -1 ? 1 : 0);
newlvl->bShouldBlockOnLoad = lvl.dontUnload;
cppCreatedList.Add(lvl.uniqName);
cpploadedList.Add(lvl.uniqName);
outStruct.Add(newlvl);
}
}
}
else if (cppCreatedList.Contains(lvl.uniqName)) {
ULevelStreaming* outlvl_ = nullptr;
if ((outlvl_ = UGameplayStatics::GetStreamingLevel(WorldContextObject, lvl.uniqName)) != nullptr) {
//if (lvl.path.EndsWith("refl")) outlvl_->bShouldBlockOnUnload = true;
outlvl_->SetShouldBeLoaded(lvl.dontUnload);
outlvl_->SetShouldBeVisible(false);
cpploadedList.Remove(lvl.uniqName);
outStruct.Add(outlvl_);
}
}
}
cppWhiteList.Empty();
cppBlackList.Empty();
cppLoadList.Empty();
return outStruct;
}
void UcppGI::cppCoordsEq(Fcppcoords coords, Fcppcoords coords1, bool relevantMinus2, bool fastEq, bool& flat_, bool& type_, bool& zone_, bool& house_, bool& section_, bool& floor_, bool& fullEq)
{
bool* outLvl[6] = { &flat_, &type_, &zone_, &house_, &section_, &floor_ };
int32 c1[6] = { coords.flat,coords.type, coords.zone, coords.house, coords.section, coords.floor };
int32 c2[6] = { coords1.flat,coords1.type, coords1.zone, coords1.house, coords1.section, coords1.floor };
int32 mins[6] = { 0,0,1,1,1,0 };
if (fastEq) {
for (int8 i = 0; i < 6; i++)
{
*outLvl[i] = (c1[i] == c2[i]);
}
}
else {
for (int8 i = 0; i < 6; i++) {
*outLvl[i] = ((c1[i] < mins[i]) && (c2[i] < mins[i])) || (c1[i] == c2[i]) || ((c1[i] == -2) && relevantMinus2) || ((c2[i] == -2) && relevantMinus2);
}
}
fullEq = true;
for (const auto var : outLvl)
{
if (!*var)fullEq = false;
}
}
TArray<FcppflatStruct> UcppGI::getFlatArr_(Fcppcoords coords, int& len)
{
auto output = TArray<FcppflatStruct>();
for (auto& flat : flatArray) {
auto flatcoords = Fcppcoords();
flatcoords.flat = coords.flat < 0 ? -2 : flat.FlatId; //ignore flat
flatcoords.floor = coords.floor < 0 ? -2 : flat.Floor;
flatcoords.house = coords.house < 1 ? -2 : flat.House;
flatcoords.section = coords.section < 1 ? -2 : flat.Section;
flatcoords.type = coords.type < 0 ? -2 : flat.flatType;
flatcoords.zone = coords.zone < 1 ? -2 : flat.Zone;
bool dummy[6];
bool eq;
cppCoordsEq(coords, flatcoords, true, false, dummy[0], dummy[1], dummy[2], dummy[3], dummy[4], dummy[5], eq);
if (eq) output.Add(flat);
}
len = output.Num();
return output;
}
FcppflatStruct UcppGI::findFlatByCoords_(Fcppcoords coords, bool& success)
{
success = false;
if (coords.flat < 0) return FcppflatStruct();
int len;
auto tt = getFlatArr_(coords, len);
if (len > 1) UE_LOG(LogCore, Warning, TEXT("UcppGI::findFlatByCoords: found more than one flat: GP%d-S%d-F%d-A%d"), coords.house, coords.section, coords.floor, coords.flat);
if (len == 0) return FcppflatStruct();
success = true;
return tt[0];
}
FcppflatStruct UcppGI::findFlatByN_(Fcppcoords filter, int num, bool& success)
{
success = false;
filter.flat = -2;
auto output = FcppflatStruct();
auto arr = getFlatArr_(filter, intDummy);
for (auto& flat : arr) {
if (flat.FlatN == num) {
if (!success) output = flat;
else UE_LOG(LogCore, Warning, TEXT("UcppGI::findFlatByN_: found more than one flat"));
success = true;
}
}
return output;
}
void UcppGI::countFreeApartments(Fcppcoords coords, int& free, int& all, float& minPrice)
{
int len;
free = 0;
minPrice = 0;
bool temp = false;
for (auto& flat : getFlatArr_(coords, len)) {
if (flat.available) {
if (!temp&& flat.Price>100) {
minPrice = flat.Price;
temp = true;
}
free++;
if (flat.Price < minPrice&& flat.Price>100) minPrice = flat.Price;
}
}
minPrice /= 1000000;
all = len;
return;
}
void UcppGI::cppFlatTocppCoords(FcppflatStruct flat, Fcppcoords& coords)
{
coords.flat = flat.FlatId;
coords.floor = flat.Floor;
coords.house = flat.House;
coords.section = flat.Section;
coords.type = flat.flatType;
coords.zone = flat.Zone;
}
void UcppGI::cppCoordsToCppFlat(UObject* WorldContextObject, Fcppcoords coords, FcppflatStruct& flat, bool onlyCoords)
{
if (onlyCoords) {
flat.FlatId = coords.flat;
flat.Floor = coords.floor;
flat.House = coords.house;
flat.Section = coords.section;
flat.flatType = coords.type;
flat.Zone = coords.zone;
return;
}
bool dum;
flat = StaticCastPtr<UcppGI, UGameInstance>(UGameplayStatics::GetGameInstance(WorldContextObject))->findFlatByCoords_(coords, dum);
}
void UcppGI::cpp_parseXmlAsync(UObject* WorldContextObject, const TMap<int32, FIntPoint>& houseIds, FLatentActionInfo LatentInfo) {
UWorld* World = WorldContextObject ? WorldContextObject->GetWorld() : nullptr;
if (!World) return;
struct FParseXmlLatent : public FPendingLatentAction {
FName ExecutionFunction;
int32 OutputLink;
FWeakObjectPtr CallbackTarget;
bool bDone = false;
FParseXmlLatent(const FLatentActionInfo& Info)
: ExecutionFunction(Info.ExecutionFunction)
, OutputLink(Info.Linkage)
, CallbackTarget(Info.CallbackTarget) {}
virtual void UpdateOperation(FLatentResponse& Response) override {
Response.FinishAndTriggerIf(bDone, ExecutionFunction, OutputLink, CallbackTarget);
}
};
FParseXmlLatent* Action = new FParseXmlLatent(LatentInfo);
World->GetLatentActionManager().AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, Action);
Async(EAsyncExecution::ThreadPool, [this, houseIds, Action]() {
EEasyXMLParserFound fou;
EEasyXMLParserErrorCode er;
FString er1;
auto xfile = UEasyXMLParseManager::LoadFromFile(FPaths::ProjectSavedDir() + FString("flatdata.xml"), true, er, er1);
if (!xfile) { AsyncTask(ENamedThreads::GameThread, [Action]() { Action->bDone = true; }); return; }
auto offers = xfile->ReadElements(FString("realty-feed.offer"), fou);
if (fou != EEasyXMLParserFound::Found) { AsyncTask(ENamedThreads::GameThread, [Action]() { Action->bDone = true; }); return; }
TMap<FIntPoint, int32> flatKeyToOfferIdx;
flatKeyToOfferIdx.Reserve(offers.Num());
for (int32 i = 0; i < offers.Num(); ++i) {
auto& offer = offers[i];
const int32 houseId = offer->ReadInt(FString("yandex-house-id"), 0);
if (const FIntPoint* housePoint = houseIds.Find(houseId)) {
const int32 apartment = offer->ReadInt(FString("location.apartment"), 0);
flatKeyToOfferIdx.Add({ housePoint->X, apartment }, i);
}
}
struct FFlatUpdate { int32 Index; int32 Price; float Square; bool Available; FIntPoint Deadline; };
TArray<FFlatUpdate> updates;
updates.Reserve(flatArray.Num());
for (int32 idx = 0; idx < flatArray.Num(); ++idx) {
const auto& flat = flatArray[idx];
const int32* xmlFlatIdPtr = flatKeyToOfferIdx.Find({ flat.Zone, flat.FlatN });
if (!xmlFlatIdPtr) continue;
const int32 xmlFlatId = *xmlFlatIdPtr;
auto& xf = offers[xmlFlatId];
FFlatUpdate u;
u.Index = idx;
u.Price = xf->ReadInt(FString("price.value"), 0);
u.Square = xf->ReadFloat(FString("area.value"), 0);
u.Available = true;
u.Deadline = { xf->ReadInt(FString("ready-quarter"), 0), xf->ReadInt(FString("built-year"), 0) };
updates.Add(MoveTemp(u));
}
AsyncTask(ENamedThreads::GameThread, [this, Action, updates = MoveTemp(updates)]() mutable {
for (const auto& u : updates) {
if (!flatArray.IsValidIndex(u.Index)) continue;
auto& flat = flatArray[u.Index];
flat.Price = u.Price;
if (u.Square) flat.Square = u.Square;
flat.available = u.Available;
flat.deadline = u.Deadline;
flat.price_meter = (flat.Price && flat.Square) ? flat.Price / flat.Square : 0;
}
Action->bDone = true;
});
});
}
void UcppGI::fixXmlAsync(UObject* WorldContextObject, FString xmlPath, FLatentActionInfo LatentInfo) {
UWorld* World = WorldContextObject ? WorldContextObject->GetWorld() : nullptr;
if (!World) return;
struct FFixXmlLatent : public FPendingLatentAction {
FName ExecutionFunction;
int32 OutputLink;
FWeakObjectPtr CallbackTarget;
bool bDone = false;
FFixXmlLatent(const FLatentActionInfo& Info)
: ExecutionFunction(Info.ExecutionFunction)
, OutputLink(Info.Linkage)
, CallbackTarget(Info.CallbackTarget) {}
virtual void UpdateOperation(FLatentResponse& Response) override {
Response.FinishAndTriggerIf(bDone, ExecutionFunction, OutputLink, CallbackTarget);
}
};
FFixXmlLatent* Action = new FFixXmlLatent(LatentInfo);
World->GetLatentActionManager().AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, Action);
Async(EAsyncExecution::ThreadPool, [Action, xmlPath]() {
FString xml;
FFileHelper::LoadFileToString(xml, *xmlPath);
xml.ReplaceInline(L"><!", L">");
xml.ReplaceInline(L"]><", L"]<");
FFileHelper::SaveStringToFile(xml, *xmlPath);
AsyncTask(ENamedThreads::GameThread, [Action]() {
Action->bDone = true;
});
});
}