require('../Thing.Extend/BundleLoader/CustomBundleLoader');
const ThingBlueprint = require('../Thing.UE/ThingBlueprint');
const Package = require("../Thing.UE/Package");
const path = require("path");
const fs = require("fs");
const { UQualityLevel } = require("../Thing.UE/UDef");
/**
* @description ThingUE拓展App接口
* @class App
*/
class App extends THING.App {
#bundle = "";
#uApp = null;
#complete = null;
#progress = null;
#exit = null;
#qualityLevel = UQualityLevel.Epic;
constructor(param) {
super(param);
this._transitionTypes = ["Default", "Wireframe", "Fire", "Mosaic"];
this.#complete = param.complete;
this.#progress = param.progress;
this.#exit = param.exit;
// this._initThingBlueprint();
this.#initApp();
//兼容旧版接口
global.app = this;
global.ueApp = this;
// spr1ngd : redefine object propery conflicts with Proxy inside constructor
Object.defineProperty(this, 'maxFPS', {
enumerable: false,
configurable: true,
set(value) {
this.renderFrameRate = value;
},
get() {
return this.renderFrameRate;
}
});
}
get appIni() {
return this.#uApp.appIni;
}
get pakIndex() {
if (this.#uApp.appIni.pakIndexString) {
return JSON.parse(this.#uApp.appIni.pakIndexString);
}
return null;
}
get currentBundle() {
return this.#uApp.LoadedPakName;
}
set renderFrameRate(frameRate) {
// spr1ngd: if bDefaultFPS is true , application would resume to this fps after calling rendering = true, otherwise fps would be -1
const bDefaultFPS = true;
this.#uApp.setMaxFPS(frameRate, bDefaultFPS);
}
get renderFrameRate() {
return this.#uApp.getMaxFPS();
}
/**
* @description 控制UE是否渲染\n 当UE处于页面后台时,可设置为false让UE不执行渲染,以降低GPU消耗,或者通过app.maxFPS控制渲染帧率来实现GPU消耗控制
* @param {Boolean} value - 默认为true
*/
set rendering(value) {
if (this.#uApp) {
value ? this.#uApp.ResumeRendering() : this.#uApp.PauseRendering();
}
}
/**
* get unreal engine current render quality level.\n The default level is 'Epic'
* @return
*/
get qualityLevel() {
return this.#qualityLevel;
}
/**
* set global render quality level.\n Do not supports to set quality level setting in sepcific scene, such as setting different quality level in exterior and interior
* @param {UQualityLevel} value - new quality level
*/
set qualityLevel(value) {
this.#qualityLevel = value;
this.#uApp.SetScalabilityLevel(value);
}
get bundleName() {
return this.appIni.BundleName;
}
get bundlePath() {
return this.#bundle;
}
#initApp() {
if (!this.#uApp) {
this.#uApp = UE4.World.GetActorByTag(UE4.App, '__App__');
}
this.#uApp.OnApplicationQuit = () => {
if (this.#exit) {
this.#exit();
}
};
this.#uApp.OnLoading = (progress) => {
this.updateProgress(Math.min(Math.max(progress, 0), 1));
}
this.#uApp.OnNodeHotReload = () => {
this.#complete && this.#complete(this);
}
this.#uApp.LoadCompleted_Internal = () => {
this.#complete && this.#complete(this);
this.rendering = true;
};
}
find(condition) {
let object = this.root.find(condition);
if (!object) {
return condition.startsWith('.') ? condition.slice(1) : condition;
}
return super.find(condition);
}
query(condition, options) {
let object = this.root.query(condition, options);
if (!object) {
return condition.startsWith('.') ? condition.slice(1) : condition;
}
return super.query(condition, options);
}
updateProgress(value = 0) {
this.#progress && this.#progress(value)
}
loadPakBundle(bundle, complete = null) {
this.renderFrameRate = 60;
this.updateProgress();
this.#bundle = this.#uApp.appIni.bPakPath || "";
if (bundle) {
this.#bundle = bundle;
}
this.#uApp.loadPak(this.#bundle, () => {
complete && complete();
});
return true;
}
mount(pakFullPath, mountPoint, projectName) {
this.#uApp.mount(pakFullPath, mountPoint, projectName);
}
unmount(projectName) {
this.#uApp.Unmount(projectName);
}
/**
* @description Force to restart nodejs inside ThingUE. (Not recommanded)
* @description 强制重启ThingUE中nodejs模块(不推荐调用)
*/
hotReload() {
this.#uApp.HotReload();
}
preLoad() {
this.#uApp.PreLoad();
}
load(groupName) {
this.#uApp.Load(groupName);
}
progressPanelShow(show) {
this.#uApp.ProgressPanelShow(show);
}
progressPanelChange(fileName) {
this.#uApp.ProgressPanelChange(fileName);
}
printOnScreen(message) {
this.#uApp.AddScreenMessage(message);
}
_initThingBlueprint() {
new ThingBlueprint({ app: app });
}
loadPatches() {
const patchPath = path.resolve(__dirname, '../../../Patches');
let res = new Array();
if (!fs.existsSync(patchPath))
return res;
const dirList = fs.readdirSync(patchPath);
for (let index = 0; index < dirList.length; index++) {
const folder = dirList[index];
const pakPath = path.join('Patches', folder);
const pak = this.loadPackage(pakPath);
res.push(pak);
}
return res;
}
loadPackage(param) {
const uePackage = new Package(this);
//pa路径要放在ThingUE目录下
const loadPath = path.resolve(__dirname, `../../../${param}`);
uePackage.load(loadPath, true);
return uePackage;
}
}
THING.App = App;
module.exports = App;