-
Notifications
You must be signed in to change notification settings - Fork 37
/
PluginAPI.h
362 lines (304 loc) · 12.9 KB
/
PluginAPI.h
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
#pragma once
typedef UInt32 PluginHandle; // treat this as an opaque type
class GFxMovieView;
class GFxValue;
class TaskDelegate;
class UIDelegate_v1;
class InventoryEntryData;
class SKSEDelayFunctorManager;
class SKSEObjectRegistry;
class SKSEPersistentObjectStorage;
class BranchTrampoline;
struct PluginInfo
{
enum
{
kInfoVersion = 1
};
UInt32 infoVersion;
const char * name;
UInt32 version;
};
enum
{
kPluginHandle_Invalid = 0xFFFFFFFF
};
enum
{
kInterface_Invalid = 0,
kInterface_Scaleform,
kInterface_Papyrus,
kInterface_Serialization,
kInterface_Task,
kInterface_Messaging,
kInterface_Object,
kInterface_Trampoline,
kInterface_Max,
};
struct SKSEInterface
{
UInt32 skseVersion;
UInt32 runtimeVersion;
UInt32 editorVersion;
UInt32 isEditor;
void * (* QueryInterface)(UInt32 id);
// call during your Query or Load functions to get a PluginHandle uniquely identifying your plugin
// invalid if called at any other time, so call it once and save the result
PluginHandle (* GetPluginHandle)(void);
// returns the SKSE build's release index
UInt32 (* GetReleaseIndex)(void);
// Minimum SKSE version 2.0.18
// returns the plugin info structure for a plugin by name, only valid to be called after PostLoad message
const PluginInfo* (* GetPluginInfo)(const char* name);
};
struct SKSEScaleformInterface
{
enum
{
kInterfaceVersion = 2
};
UInt32 interfaceVersion;
// This callback will be called once for every new menu that is created.
// Create your objects relative to the 'root' GFxValue parameter.
typedef bool (* RegisterCallback)(GFxMovieView * view, GFxValue * root);
typedef void (* RegisterInventoryCallback)(GFxMovieView * view, GFxValue * object, InventoryEntryData * item);
// Register your plugin's scaleform API creation callback here.
// The "name" parameter will be used to create an object with the path:
// "skse.plugins.name" that will be passed to the callback.
// Make sure that the memory it points to is valid from the point the callback
// is registered until the game exits.
bool (* Register)(const char * name, RegisterCallback callback);
// Registers your plugin for when item data is extended to the UI
// either favorites menu, or inventory menu
void (* RegisterForInventory)(RegisterInventoryCallback callback);
};
struct SKSESerializationInterface
{
enum
{
kVersion = 4,
};
typedef void (* EventCallback)(SKSESerializationInterface * intfc);
typedef void (* FormDeleteCallback)(UInt64 handle);
UInt32 version;
void (* SetUniqueID)(PluginHandle plugin, UInt32 uid);
void (* SetRevertCallback)(PluginHandle plugin, EventCallback callback);
void (* SetSaveCallback)(PluginHandle plugin, EventCallback callback);
void (* SetLoadCallback)(PluginHandle plugin, EventCallback callback);
void (* SetFormDeleteCallback)(PluginHandle plugin, FormDeleteCallback callback);
bool (* WriteRecord)(UInt32 type, UInt32 version, const void * buf, UInt32 length);
bool (* OpenRecord)(UInt32 type, UInt32 version);
bool (* WriteRecordData)(const void * buf, UInt32 length);
bool (* GetNextRecordInfo)(UInt32 * type, UInt32 * version, UInt32 * length);
UInt32 (* ReadRecordData)(void * buf, UInt32 length);
bool (* ResolveHandle)(UInt64 handle, UInt64 * handleOut);
bool (* ResolveFormId)(UInt32 formId, UInt32 * formIdOut);
};
struct SKSETaskInterface
{
enum
{
kInterfaceVersion = 2
};
UInt32 interfaceVersion;
// Derive your type from TaskDelegate or UIDelegate
// Allocate before adding
// Define your Run function
// Delete your object in the Dispose call
void (* AddTask)(TaskDelegate * task);
void (* AddUITask)(UIDelegate_v1 * task);
};
class VMClassRegistry;
struct SKSEPapyrusInterface
{
enum
{
kInterfaceVersion = 1
};
UInt32 interfaceVersion;
typedef bool (* RegisterFunctions)(VMClassRegistry * registry);
bool (* Register)(RegisterFunctions callback);
};
/**** Messaging API docs ********************************************************************
*
* Messaging API allows inter-plugin communication at run-time. A plugin may register
* one callback for each plugin from which it wishes to receive messages, specifying
* the sender by name in the call to RegisterListener(). RegisterListener returns false
* if the specified plugin is not loaded, true otherwise. Any messages dispatched by
* the specified plugin will then be forwarded to the listener as they occur. Passing NULL as
* the sender registers the calling plugin as a listener to every loaded plugin.
*
* Messages may be dispatched via Dispatch() to either a specific listener (specified
* by name) or to all listeners (with NULL passed as the receiver). The contents and format of
* messageData are left up to the sender, and the receiver is responsible for casting the message
* to the expected type. If no plugins are registered as listeners for the sender,
* Dispatch() returns false, otherwise it returns true.
*
* Calling RegisterListener() or Dispatch() during plugin load is not advised as the requested plugin
* may not yet be loaded at that point. Instead, if you wish to register as a listener or dispatch a
* message immediately after plugin load, use RegisterListener() during load to register to receive
* messages from SKSE (sender name: "SKSE"). You will then receive a message from SKSE once
* all plugins have been loaded, at which point it is safe to establish communications between
* plugins.
*
* Some plugin authors may wish to use strings instead of integers to denote message type. In
* that case the receiver can pass the address of the string as an integer and require the receiver
* to cast it back to a char* on receipt.
*
*********************************************************************************************/
struct SKSEMessagingInterface
{
struct Message {
const char * sender;
UInt32 type;
UInt32 dataLen;
void * data;
};
typedef void (* EventCallback)(Message* msg);
enum {
kInterfaceVersion = 2
};
// SKSE messages
enum {
kMessage_PostLoad, // sent to registered plugins once all plugins have been loaded (no data)
kMessage_PostPostLoad, // sent right after kMessage_PostLoad to facilitate the correct dispatching/registering of messages/listeners
kMessage_PreLoadGame, // dispatched immediately before savegame is read by Fallout
// dataLen: length of file path, data: char* file path of .ess savegame file
kMessage_PostLoadGame, //dispatched after an attempt to load a saved game has finished (the game's LoadGame() routine
//has returned). You will probably want to handle this event if your plugin uses a Preload callback
//as there is a chance that after that callback is invoked the game will encounter an error
//while loading the saved game (eg. corrupted save) which may require you to reset some of your
//plugin state.
//data: bool, true if game successfully loaded, false otherwise
// plugins may register as listeners during the first callback while deferring dispatches until the next
kMessage_SaveGame,
kMessage_DeleteGame, // sent right before deleting the .skse cosave and the .ess save.
// dataLen: length of file path, data: char* file path of .ess savegame file
kMessage_InputLoaded, // sent right after game input is loaded, right before the main menu initializes
kMessage_NewGame, // sent after a new game is created, before the game has loaded (Sends CharGen TESQuest pointer)
kMessage_DataLoaded // send after the data handler has loaded all its forms
};
UInt32 interfaceVersion;
bool (* RegisterListener)(PluginHandle listener, const char* sender, EventCallback handler);
bool (* Dispatch)(PluginHandle sender, UInt32 messageType, void * data, UInt32 dataLen, const char* receiver);
enum
{
kDispatcher_ModEvent = 0,
kDispatcher_CameraEvent,
kDispatcher_CrosshairEvent,
kDispatcher_ActionEvent,
kDispatcher_NiNodeUpdateEvent
};
// Use this to acquire SKSE's internal EventDispatchers so that you can sink to them
void * (* GetEventDispatcher)(UInt32 dispatcherId);
};
struct SKSEObjectInterface
{
enum
{
kInterfaceVersion = 1
};
UInt32 interfaceVersion;
SKSEDelayFunctorManager & (* GetDelayFunctorManager)();
SKSEObjectRegistry & (* GetObjectRegistry)();
SKSEPersistentObjectStorage & (* GetPersistentObjectStorage)();
};
struct SKSETrampolineInterface
{
enum
{
kInterfaceVersion = 1
};
UInt32 interfaceVersion;
void* (*AllocateFromBranchPool)(PluginHandle plugin, size_t size);
void* (*AllocateFromLocalPool)(PluginHandle plugin, size_t size);
};
typedef bool(*_SKSEPlugin_Load)(const SKSEInterface * skse);
/**** plugin versioning ********************************************************
*
* The AE version of Skyrim SE broke plugin versioning as many were written
* with the assumption that the Address Library would always be valid.
* These always report that they are compatible, then exit on startup because
* they cannot find their address library file.
*
* To work around this problem, version checking has been reimplemented and
* no longer calls any code. Plugins declare their compatibility, and SKSE
* determines whether to load the plugin. Setting this up is simple, just
* add something like this to your project:
*
extern "C" {
__declspec(dllexport) SKSEPluginVersionData SKSEPlugin_Version =
{
SKSEPluginVersionData::kVersion,
1,
"my awesome plugin",
"my name",
"support@example.com",
0, // not version independent (extended field)
0, // not version independent
{ RUNTIME_VERSION_1_6_318, 0 }, // compatible with 1.6.318
0, // works with any version of the script extender. you probably do not need to put anything here
};
};
*
******************************************************************************/
struct SKSEPluginVersionData
{
enum
{
kVersion = 1,
};
enum
{
// set this if you are using a post-AE version of the Address Library
kVersionIndependent_AddressLibraryPostAE = 1 << 0,
// set this if you exclusively use signature matching to find your addresses and have NO HARDCODED ADDRESSES
kVersionIndependent_Signatures = 1 << 1,
// set this if you are using 1.6.629+ compatible structure layout (likely provided by CommonLib/SKSE)
// this also marks you as incompatible with pre-1.6.629. see kVersionIndependentEx_NoStructUse if you have a
// plugin that only does code patches and works across many versions
kVersionIndependent_StructsPost629 = 1 << 2,
};
enum
{
// set this if your plugin either doesn't use any game structures or has put in extraordinary effort
// to work with pre and post 1.6.629 structure layout
kVersionIndependentEx_NoStructUse = 1 << 0,
};
UInt32 dataVersion; // set to kVersion
UInt32 pluginVersion; // version number of your plugin
char name[256]; // null-terminated ASCII plugin name
char author[256]; // null-terminated ASCII plugin author name (can be empty)
char supportEmail[252]; // null-terminated ASCII support email address (can be empty)
// this is not for showing to users, it's in case I need to contact you about
// a compatibility problem with your plugin
// version compatibility
UInt32 versionIndependenceEx; // set to one of the kVersionIndependentEx_ enums or zero
UInt32 versionIndependence; // set to one of the kVersionIndependent_ enums or zero
UInt32 compatibleVersions[16]; // zero-terminated list of RUNTIME_VERSION_ defines your plugin is compatible with
UInt32 seVersionRequired; // minimum version of the script extender required, compared against PACKED_SKSE_VERSION
// you probably should just set this to 0 unless you know what you are doing
};
/**** plugin API docs **********************************************************
*
* The base API is pretty simple. Add version data as shown in the
* SKSEPluginVersionData docs above, and export this function:
*
* bool SKSEPlugin_Load(const SKSEInterface * skse)
*
* In this function, use the interfaces above to register your commands, patch
* memory, generally do whatever you need to for integration with the runtime.
*
* At this time, or at any point forward you can call the QueryInterface
* callback to retrieve an interface structure for the base services provided
* by the SKSE core.
*
* You may optionally return false from this function to unload your plugin,
* but make sure that you DO NOT register any commands if you do.
*
* Note that all structure versions are backwards-compatible, so you only need
* to check against the latest version that you need. New fields will be only
* added to the end, and all old fields will remain compatible with their
* previous implementations.
*
******************************************************************************/