-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathSource.cpp
More file actions
172 lines (119 loc) · 5.36 KB
/
Copy pathSource.cpp
File metadata and controls
172 lines (119 loc) · 5.36 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
/*
Primitive example which shows how to use SKSE messaging API and use JContainers functions in your plugin
Plugin obtains JContainers fucntions (JArray_size, JArray_getForm etc)
and registers a function `sortByName` in a script with name `JC_API_Example` which sorts an array of forms by their names
You shall write and compile Papyrus script yourself:
Scriptname JC_API_Example
function sortByName(int jc_object_id) global native
*/
#include "common/IPrefix.h"
#include <ShlObj.h>
#include <assert.h>
#include "jc_interface.h"
#include "skse/PluginAPI.h"
#include "skse/skse_version.h"
#include "skse/GameForms.h"
#include "skse/PapyrusNativeFunctions.h"
#include "skse/PapyrusForm.h"
class VMClassRegistry;
static PluginHandle g_pluginHandle = kPluginHandle_Invalid;
static SKSEPapyrusInterface * g_papyrus = NULL;
static SKSEMessagingInterface *g_messaging = nullptr;
#define PLUGIN_NAME "JC_API_Example"
namespace {
//
void * default_domain = nullptr;
// function pointers which will be obtained:
SInt32(*JArray_size)(void*, SInt32 obj) = nullptr;
TESForm* (*JArray_getForm)(void*, SInt32 obj, SInt32 idx, TESForm* def) = nullptr;
void (*JArray_swap)(void*, SInt32 obj, SInt32 idx, SInt32 idx2) = nullptr;
template<class T>
void obtain_func(const jc::reflection_interface *refl, const char *funcName, const char *className, T& func) {
assert(refl);
func = (T)refl->tes_function_of_class(funcName, className);
assert(func);
}
void OnJCAPIAvailable(const jc::root_interface * root) {
_MESSAGE("OnJCAPIAvailable");
// Current API is not very usable - you'll have to obtain functions manually:
auto refl = root->query_interface<jc::reflection_interface>();
obtain_func(refl, "count", "JArray", JArray_size);
obtain_func(refl, "getForm", "JArray", JArray_getForm);
obtain_func(refl, "swapItems", "JArray", JArray_swap);
default_domain = root->query_interface<jc::domain_interface>()->get_default_domain();
}
void sortByName(StaticFunctionTag*, SInt32 obj) {
auto array_size = JArray_size(default_domain, obj);
// >
auto compare = [obj](int idx, int idx2) {
auto n1 = papyrusForm::GetName(JArray_getForm(default_domain, obj, idx, nullptr));
auto n2 = papyrusForm::GetName(JArray_getForm(default_domain, obj, idx2, nullptr));
return n1.data && n2.data && _stricmp(n1.data, n2.data) > 0;
};
//Bubble Sorting begins
for (int passes = 0; passes < array_size - 1; passes++) {
for (int j = 0; j < array_size - passes - 1; j++) {
if (compare(j, j + 1)) {
JArray_swap(default_domain, obj, j, j + 1);
}
}
} //Bubble Sorting finished
}
bool registerAllFunctions(VMClassRegistry *registry) {
auto funcName = "sortByName";
auto className = PLUGIN_NAME;
registry->RegisterFunction(
new NativeFunction1 <StaticFunctionTag, void, SInt32>(funcName, className, sortByName, registry));
registry->SetFunctionFlags(className, funcName, VMClassRegistry::kFunctionFlag_NoWait);
_MESSAGE("registering functions");
return true;
}
}
extern "C" {
__declspec(dllexport) bool SKSEPlugin_Query(const SKSEInterface * skse, PluginInfo * info)
{
gLog.OpenRelative(CSIDL_MYDOCUMENTS, "\\My Games\\Skyrim\\SKSE\\"PLUGIN_NAME".log");
gLog.SetPrintLevel(IDebugLog::kLevel_Error);
gLog.SetLogLevel(IDebugLog::kLevel_DebugMessage);
// populate info structure
info->infoVersion = PluginInfo::kInfoVersion;
info->name = PLUGIN_NAME;
info->version = 1;
// store plugin handle so we can identify ourselves later
g_pluginHandle = skse->GetPluginHandle();
if (skse->isEditor) {
_MESSAGE("loaded in editor, marking as incompatible");
return false;
}
else if (skse->runtimeVersion != RUNTIME_VERSION_1_9_32_0) {
_MESSAGE("unsupported runtime version %08X", skse->runtimeVersion);
return false;
}
g_papyrus = (SKSEPapyrusInterface *)skse->QueryInterface(kInterface_Papyrus);
if (!g_papyrus) {
_MESSAGE("couldn't get papyrus interface");
return false;
}
g_messaging = (SKSEMessagingInterface *)skse->QueryInterface(kInterface_Messaging);
if (!g_messaging) {
_MESSAGE("messaging api not found");
return false;
}
return true;
}
__declspec(dllexport) bool SKSEPlugin_Load(const SKSEInterface * skse) {
g_papyrus->Register(registerAllFunctions);
g_messaging->RegisterListener(g_pluginHandle, "SKSE", [](SKSEMessagingInterface::Message* msg) {
if (msg && msg->type == SKSEMessagingInterface::kMessage_PostLoad) {
auto loaded = g_messaging->RegisterListener(g_pluginHandle, "JContainers", [](SKSEMessagingInterface::Message* msg) {
// JC publishes its API:
if (msg && msg->type == jc::message_root_interface) {
OnJCAPIAvailable(jc::root_interface::from_void(msg->data));
}
});
}
});
_MESSAGE("plugin loaded");
return true;
}
}