-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
179 lines (161 loc) · 6.33 KB
/
Copy pathmain.cpp
File metadata and controls
179 lines (161 loc) · 6.33 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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include "PCH.h" // TO MUSI BYĆ PIERWSZA LINIA
// Lokalne nagłówki (one korzystają już z oczyszczonego środowiska PCH)
#include "API/API_External.h"
#include "Core/PluginCore.h"
#include "Animation/GraphManager.h"
#include "Animation/Face/Manager.h"
#include "Papyrus/SAFScript.h"
#include "Papyrus/EventManager.h"
#include "Tasks/SaveLoadListener.h"
#include <Windows.h>
// SFSE używa GetProcAddress("SFSEPlugin_Version") – symbol MUSI mieć linkage C (bez manglowania)
extern "C" DLLEXPORT constinit const SFSE::PluginVersionData SFSEPlugin_Version = []() noexcept {
SFSE::PluginVersionData v{};
v.PluginVersion({ 1, 0, 0, 0 });
v.PluginName("StarfieldAnimationFramework");
v.AuthorName("mielu91m");
v.UsesSigScanning(false);
v.UsesAddressLibrary(true);
v.HasNoStructUse(true);
v.IsLayoutDependent(false);
v.CompatibleVersions({ SFSE::RUNTIME_LATEST });
return v;
}();
// Nie potrzebujemy tu ponownie definiować MessageHandler ani InitializeLogging
// jeśli są one długie, ale dla kompletności wklejam uproszczoną wersję,
// która korzysta z już załadowanych bibliotek z PCH.
namespace
{
bool g_coreInitialized = false;
bool g_papyrusBound = false;
void TryBindPapyrus()
{
if (g_papyrusBound)
return;
auto* vm = RE::BSScript::Internal::VirtualMachine::GetSingleton();
if (!vm) {
SAF_LOG_WARN("SAF: Papyrus VM not ready yet, will retry on PostDataLoad");
return;
}
if (Papyrus::SAFScript::Bind(vm)) {
g_papyrusBound = true;
SAF_LOG_INFO("SAF: Papyrus SAFScript functions bound successfully");
} else {
SAF_LOG_ERROR("SAF: Failed to bind Papyrus SAFScript functions");
}
}
void LogStartupError(const char* a_message) noexcept
{
OutputDebugStringA(a_message);
OutputDebugStringA("\n");
}
void InitializeLogging()
{
try {
auto path = SFSE::log::log_directory();
if (!path) {
LogStartupError("SAF: log_directory returned null");
return;
}
*path /= "StarfieldAnimationFramework.log";
auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(path->string(), true);
auto log = std::make_shared<spdlog::logger>("global log", std::move(sink));
#ifdef NDEBUG
log->set_level(spdlog::level::info);
log->flush_on(spdlog::level::info);
#else
log->set_level(spdlog::level::trace);
log->flush_on(spdlog::level::trace);
#endif
spdlog::set_default_logger(std::move(log));
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] [%s:%#] %v");
SAF_LOG_INFO("SAF v1.0.0 init...");
} catch (const std::exception& e) {
LogStartupError(e.what());
} catch (...) {
LogStartupError("SAF: unknown exception in InitializeLogging");
}
}
void MessageHandler(SFSE::MessagingInterface::Message* a_msg)
{
try {
switch (a_msg->type) {
case SFSE::MessagingInterface::kPostLoad:
SAF_LOG_INFO("PostLoad");
break;
case SFSE::MessagingInterface::kPostPostLoad:
SAF_LOG_INFO("PostPostLoad");
if (!g_coreInitialized) {
auto* core = SAF::Core::PluginCore::GetSingleton();
if (!core || !core->Initialize()) {
SAF_LOG_ERROR("Failed to initialize core!");
break;
}
g_coreInitialized = true;
}
SAF::Core::PluginCore::GetSingleton()->OnPostPostLoad();
break;
case SFSE::MessagingInterface::kPostDataLoad:
SAF_LOG_INFO("PostDataLoad");
TryBindPapyrus();
if (g_coreInitialized) {
SAF::Core::PluginCore::GetSingleton()->OnPostDataLoad();
}
Tasks::SaveLoadListener::Install();
break;
default:
// UWAGA: sfse::MessagingInterface::kPostDataLoad ma wartość 2 — NIE umieszczaj tu „PreLoadGame”
// z type==2 (byłoby martwym kodem). Przed kolejnym loadem stan SAF czyści
// SaveLoadListener (hook VirtualMachine::DropAllRunningData).
if (a_msg->type == 3) { // PostLoadGame (SFSE; nie ma osobnego enum w CommonLibSF)
SAF_LOG_INFO("PostLoadGame");
if (g_coreInitialized) {
SAF::Core::PluginCore::GetSingleton()->OnPostLoadGame();
}
} else if (a_msg->type == 4) { // kNewGame
SAF_LOG_INFO("NewGame");
} else {
// Loguj wszystkie nieznane message types dla diagnostyki
SAF_LOG_INFO("MessageHandler: unknown type={}", a_msg->type);
}
break;
}
} catch (const std::exception& e) {
LogStartupError(e.what());
} catch (...) {
LogStartupError("SAF: unknown exception in MessageHandler");
}
}
}
extern "C" DLLEXPORT bool SFSEAPI SFSEPlugin_Query(const SFSE::QueryInterface* a_sfse, SFSE::PluginInfo* a_info)
{
a_info->infoVersion = SFSE::PluginInfo::kVersion;
a_info->name = SFSEPlugin_Version.pluginName;
a_info->version = SFSEPlugin_Version.pluginVersion;
if (a_sfse->RuntimeVersion() < SFSE::RUNTIME_LATEST) {
return false;
}
return true;
}
extern "C" DLLEXPORT bool SFSEAPI SFSEPlugin_Load(const SFSE::LoadInterface* a_sfse)
{
try {
InitializeLogging();
SAF_LOG_INFO("SAF Plugin loading...");
SFSE::Init(a_sfse);
// Rejestracja funkcji Papyrus – API init może być za wcześnie (VM null),
// fallback w PostDataLoad gdy VM jest już gotowy
SFSE::RegisterForAPIInitEvent([]() { TryBindPapyrus(); });
if (auto* messaging = SFSE::GetMessagingInterface()) {
messaging->RegisterListener(MessageHandler);
}
SAF_LOG_INFO("SAF Loaded.");
return true;
} catch (const std::exception& e) {
LogStartupError(e.what());
return false;
} catch (...) {
LogStartupError("SAF: unknown exception in SFSEPlugin_Load");
return false;
}
}