-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
161 lines (145 loc) · 6.88 KB
/
Copy pathmain.cpp
File metadata and controls
161 lines (145 loc) · 6.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <QApplication>
#include <QCommandLineParser>
#include <QDir>
#include <QStandardPaths>
#include <QStringList>
#include <QSurfaceFormat>
#include "ai_types.h"
#include "entity/pet.h"
#include "ui/petwindow.h"
#include "ui/theme_manager.h"
#include "core/configLoader/config_manager.h"
#include "statistic_manager.h"
#include "ai/runtime/profile_resolver.h"
namespace {
QString resolveResourceRoot()
{
const QString appDir = QCoreApplication::applicationDirPath();
const QStringList candidates = {
QDir::currentPath(),
appDir,
QDir(appDir).absoluteFilePath(QStringLiteral("..")),
QDir(appDir).absoluteFilePath(QStringLiteral("../..")),
};
for (const QString& candidate : candidates) {
const QDir directory(candidate);
if (directory.exists(QStringLiteral("assets"))
&& directory.exists(QStringLiteral("config"))) {
return directory.absolutePath();
}
}
return QDir(appDir).absoluteFilePath(QStringLiteral(".."));
}
} // namespace
int main(int argc, char *argv[])
{
// qputenv("QT_DEBUG_PLUGINS", "1"); // 临时打开插件日志
// 要求 OpenGL 3.3 Core,上下文需在 QApplication 创建前设置
QSurfaceFormat fmt;
fmt.setVersion(3, 3);
fmt.setProfile(QSurfaceFormat::CoreProfile);
fmt.setDepthBufferSize(24);
fmt.setStencilBufferSize(8);
fmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
QSurfaceFormat::setDefaultFormat(fmt);
QApplication app(argc, argv);
app.setApplicationName("Desktop Pet");
app.setOrganizationName("Desktop Pet Team");
app.setApplicationVersion("1.0.0");
ThemeManager::instance().applyTo(&app);
QDir::setCurrent(resolveResourceRoot());
// 命令行参数(供 Python launcher 调用):
// --config <file> 指定启动配置文件(建议绝对路径)
// --pet <name> 指定启动角色
// --profile-id <uuid> 指定不可变的角色身份
// --owner-diary-bootstrap <file> launcher 私有日记一次性凭据
// --launcher-chat-bootstrap <file> launcher 聊天一次性凭据
// 主题不走命令行,由 ThemeManager 经同名 QSettings(键 ui/theme)读取,见前端修改计划 §3.1。
QCommandLineParser parser;
parser.setApplicationDescription("Desktop Pet Application");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption configOption("config",
"Path to launch configuration file (absolute path recommended)", "config-file");
QCommandLineOption petOption("pet",
"Pet name to auto-start (must exist in pets.json registry)", "pet-name");
QCommandLineOption profileIdOption("profile-id",
"Immutable profile UUID (resolved from pets.json when omitted)", "profile-id");
QCommandLineOption ownerDiaryBootstrapOption("owner-diary-bootstrap",
"Path to the one-time owner diary bootstrap file", "bootstrap-file");
QCommandLineOption launcherChatBootstrapOption("launcher-chat-bootstrap",
"Path to the one-time launcher chat bootstrap file", "bootstrap-file");
parser.addOption(configOption);
parser.addOption(petOption);
parser.addOption(profileIdOption);
parser.addOption(ownerDiaryBootstrapOption);
parser.addOption(launcherChatBootstrapOption);
parser.process(app);
const QString configPath = parser.value(configOption);
// —— 直接承载桌宠窗口(原控制面板 MainWindow 已由 Python launcher 取代)——
// 角色来源:--pet 入参;未指定时退回注册表首个角色;都没有则提示用 launcher 启动。
// 注意:Pet 注册表不会在 instance() 构造时自动载入 pets.json,必须显式 load()
// (原由 MainWindow::loadPetList() 触发,移除面板后改由 main 直接调用)。
QString registryError;
if (!Pet::instance().load(®istryError)) {
qCritical() << "[main] PROFILE_ID_INVALID: failed to load pets.json:" << registryError;
return 1;
}
const QString requestedPetName = parser.value(petOption);
const std::optional<QString> requestedProfileId = parser.isSet(profileIdOption)
? std::optional<QString>{parser.value(profileIdOption)}
: std::nullopt;
const QList<PetProfile> profiles = Pet::instance().getProfiles();
const ProfileResolutionResult profileResult =
ProfileResolver(profiles).resolve(requestedPetName, requestedProfileId);
if (!profileResult.isResolved()) {
qCritical() << "[main] PROFILE_ID_INVALID:" << profileResult.diagnostic;
return 1;
}
const PetProfile profile = *profileResult.profile;
const QString petName = profile.name;
QStringList registeredProfileIds;
registeredProfileIds.reserve(profiles.size());
for (const PetProfile& registeredProfile : profiles) {
registeredProfileIds.append(registeredProfile.profileId);
}
ProfileMigrationRequest profileMigration;
profileMigration.profileId = profile.profileId;
profileMigration.registeredProfileIds = registeredProfileIds;
profileMigration.confirmedLegacyOwnerProfileId = std::nullopt;
profileMigration.appDataRoot =
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
profileMigration.legacyDatabasePath = QStringLiteral("runtime/memory/memory.db");
profileMigration.legacyJsonPath = QStringLiteral("log/ai_memory.json");
// 身份匹配完成后才读取运行配置或打开其他持久化服务。
if (!configPath.isEmpty()) {
ConfigManager::instance().loadConfig(configPath);
}
StatisticManager::getInstance().initialize();
// 配置全由 ConfigManager 提供(launcher 写入 launch_config.json 后经 loadConfig 载入),
// 不再依赖任何 UI 控件读取——等价于原 MainWindow::OnStartPet 的核心逻辑。
auto &cfg = ConfigManager::instance();
const int sizePercent = cfg.getPetScalePercent();
const bool alwaysOnTop = cfg.isPetAlwaysOnTop();
const bool clickThrough = cfg.isPetClickThrough();
const bool aiEnabled = cfg.getLlmConfig().enabled;
const ScreenChatConfig screenChat = cfg.getScreenChatConfig();
const VoiceConfig voice = cfg.getVoiceConfig();
cfg.setLlmEnabled(aiEnabled);
cfg.setVoiceConfig(voice);
PetWindow *pet = new PetWindow(
profile, profileMigration,
parser.value(ownerDiaryBootstrapOption),
parser.value(launcherChatBootstrapOption), nullptr);
QObject::connect(pet, &PetWindow::aboutToClose,
&app, &QCoreApplication::quit);
StatisticManager::getInstance().recordPetStart(petName);
QObject::connect(&app, &QCoreApplication::aboutToQuit, &app, [petName]() {
StatisticManager::getInstance().recordPetStop(petName);
StatisticManager::getInstance().saveStatistics();
});
pet->applySettings(sizePercent, alwaysOnTop, clickThrough, aiEnabled,
screenChat, voice);
pet->show();
return app.exec();
}