// Copyright 2020-2024 CesiumGS, Inc. and Contributors #include "CesiumIonServer.h" #include "CesiumAsync/AsyncSystem.h" #include "CesiumIonClient/Connection.h" #include "CesiumRuntime.h" #include "CesiumRuntimeSettings.h" #include "UObject/Package.h" #include "UObject/UObjectGlobals.h" #if WITH_EDITOR #include "AssetRegistry/AssetRegistryModule.h" #include "CesiumIonClient/Connection.h" #include "Factories/DataAssetFactory.h" #include "FileHelpers.h" #endif const FString DISPLAY_NAME = TEXT("ion.cesium.com"); const FString SERVER_URL = TEXT("https://ion.cesium.com"); const FString API_URL = TEXT("https://api.cesium.com"); const int64 OAUTH_APP_ID = 190; /*static*/ UCesiumIonServer* UCesiumIonServer::_pDefaultForNewObjects = nullptr; /*static*/ UCesiumIonServer* UCesiumIonServer::GetDefaultServer() { UPackage* Package = CreatePackage( TEXT("/Game/CesiumSettings/CesiumIonServers/CesiumIonSaaS")); Package->FullyLoad(); UCesiumIonServer* Server = Cast(Package->FindAssetInPackage()); #if WITH_EDITOR if (!IsValid(Server)) { UDataAssetFactory* Factory = NewObject(); Server = Cast(Factory->FactoryCreateNew( UCesiumIonServer::StaticClass(), Package, "CesiumIonSaaS", RF_Public | RF_Standalone | RF_Transactional, nullptr, GWarn)); Server->DisplayName = DISPLAY_NAME; Server->ServerUrl = SERVER_URL; Server->ApiUrl = API_URL; Server->OAuth2ApplicationID = OAUTH_APP_ID; FAssetRegistryModule::AssetCreated(Server); Package->FullyLoad(); Package->SetDirtyFlag(true); UEditorLoadingAndSavingUtils::SavePackages({Package}, true); } #else if (!IsValid(Server)) { Server = NewObject( UCesiumIonServer::StaticClass(), "CesiumIonSaaS", RF_Public | RF_Standalone | RF_Transactional); Server->DisplayName = DISPLAY_NAME; Server->ServerUrl = SERVER_URL; Server->ApiUrl = API_URL; Server->OAuth2ApplicationID = OAUTH_APP_ID; } #endif return Server; } /*static*/ UCesiumIonServer* UCesiumIonServer::GetServerForNewObjects() { if (IsValid(_pDefaultForNewObjects)) { return _pDefaultForNewObjects; } else { return GetDefaultServer(); } } /*static*/ void UCesiumIonServer::SetServerForNewObjects(UCesiumIonServer* Server) { _pDefaultForNewObjects = Server; } #if WITH_EDITOR UCesiumIonServer* UCesiumIonServer::GetBackwardCompatibleServer(const FString& apiUrl) { // Return the default server if the API URL is unspecified or if it's the // standard SaaS API URL. if (apiUrl.IsEmpty() || apiUrl.StartsWith(TEXT("https://api.ion.cesium.com")) || apiUrl.StartsWith(TEXT("https://api.cesium.com"))) { return UCesiumIonServer::GetDefaultServer(); } // Find a server with this API URL. TArray CesiumIonServers; FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked("AssetRegistry"); AssetRegistryModule.Get().GetAssetsByClass( UCesiumIonServer::StaticClass()->GetClassPathName(), CesiumIonServers); FAssetData* pFound = CesiumIonServers.FindByPredicate([&apiUrl](const FAssetData& asset) { UCesiumIonServer* pServer = Cast(asset.GetAsset()); return pServer && pServer->ApiUrl == apiUrl; }); if (pFound) { return Cast(pFound->GetAsset()); } // Not found - create a new server asset. UDataAssetFactory* Factory = NewObject(); UPackage* Package = nullptr; FString PackageBasePath = TEXT("/Game/CesiumSettings/CesiumIonServers/"); FString PackageName; FString PackagePath; const int ArbitraryPackageIndexLimit = 10000; for (int i = 0; i < ArbitraryPackageIndexLimit; ++i) { PackageName = TEXT("FromApiUrl") + FString::FromInt(i); PackagePath = PackageBasePath + PackageName; Package = FindPackage(nullptr, *PackagePath); if (Package == nullptr) { Package = CreatePackage(*PackagePath); break; } } if (Package == nullptr) return nullptr; Package->FullyLoad(); UCesiumIonServer* Server = Cast(Factory->FactoryCreateNew( UCesiumIonServer::StaticClass(), Package, FName(PackageName), RF_Public | RF_Standalone | RF_Transactional, nullptr, GWarn)); Server->DisplayName = apiUrl; Server->ServerUrl = apiUrl; Server->ApiUrl = apiUrl; Server->OAuth2ApplicationID = 190; // Adopt the token from the default server, consistent with the behavior in // old versions of Cesium for Unreal. UCesiumIonServer* pDefault = UCesiumIonServer::GetDefaultServer(); Server->DefaultIonAccessTokenId = pDefault->DefaultIonAccessTokenId; Server->DefaultIonAccessToken = pDefault->DefaultIonAccessToken; FAssetRegistryModule::AssetCreated(Server); Package->FullyLoad(); Package->SetDirtyFlag(true); UEditorLoadingAndSavingUtils::SavePackages({Package}, true); return Server; } CesiumAsync::Future UCesiumIonServer::ResolveApiUrl() { if (!this->ApiUrl.IsEmpty()) return getAsyncSystem().createResolvedFuture(); if (this->ServerUrl.IsEmpty()) { // We don't even have a server URL, so use the SaaS defaults. this->ServerUrl = TEXT("https://ion.cesium.com/"); this->ApiUrl = TEXT("https://api.cesium.com/"); this->Modify(); UEditorLoadingAndSavingUtils::SavePackages({this->GetPackage()}, true); return getAsyncSystem().createResolvedFuture(); } TObjectPtr pServer = this; return CesiumIonClient::Connection::getApiUrl( getAsyncSystem(), getAssetAccessor(), TCHAR_TO_UTF8(*this->ServerUrl)) .thenInMainThread([pServer](std::optional&& apiUrl) { if (pServer && pServer->ApiUrl.IsEmpty()) { pServer->ApiUrl = UTF8_TO_TCHAR(apiUrl->c_str()); pServer->Modify(); UEditorLoadingAndSavingUtils::SavePackages( {pServer->GetPackage()}, true); } }); } #endif