Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0bbbacf

Browse files
committed
extend the docs and examples in skeleton.cpp
1 parent 2f9021a commit 0bbbacf

1 file changed

Lines changed: 134 additions & 87 deletions

File tree

plugins/examples/skeleton.cpp

Lines changed: 134 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,71 @@
1-
// This is a generic plugin that does nothing useful apart from acting as an example... of a plugin that does nothing :D
1+
// This is an example plugin that just documents and implements all the plugin
2+
// callbacks and features. You can compile it, load it, run it, and see the
3+
// debug messages get printed to the console.
4+
//
5+
// See the other example plugins in this directory for plugins that are
6+
// configured for specific use cases (but don't come with as many comments as
7+
// this one does).
8+
9+
#include <string>
10+
#include <vector>
11+
12+
#include "df/world.h"
213

3-
// some headers required for a plugin. Nothing special, just the basics.
414
#include "Core.h"
5-
#include <Console.h>
6-
#include <Export.h>
7-
#include <PluginManager.h>
8-
#include <modules/EventManager.h>
9-
// If you need to save data per-world:
10-
//#include "modules/Persistence.h"
15+
#include "Debug.h"
16+
#include "LuaTools.h"
17+
#include "PluginManager.h"
1118

12-
// DF data structure definition headers
13-
#include "DataDefs.h"
14-
//#include "df/world.h"
19+
#include "modules/Persistence.h"
20+
#include "modules/World.h"
1521

16-
// our own, empty header.
17-
#include "skeleton.h"
22+
using std::string;
23+
using std::vector;
1824

1925
using namespace DFHack;
20-
using namespace df::enums;
2126

22-
// Expose the plugin name to the DFHack core, as well as metadata like the DFHack version.
23-
// The name string provided must correspond to the filename -
27+
// Expose the plugin name to the DFHack core, as well as metadata like the
28+
// DFHack version that this plugin was compiled with. This macro provides a
29+
// variable for the plugin name as const char * plugin_name.
30+
// The name provided must correspond to the filename --
2431
// skeleton.plug.so, skeleton.plug.dylib, or skeleton.plug.dll in this case
2532
DFHACK_PLUGIN("skeleton");
2633

27-
// The identifier declared with this macro (ie. enabled) can be specified by the user
28-
// and subsequently used to manage the plugin's operations.
29-
// This will also be tracked by `plug`; when true the plugin will be shown as enabled.
30-
DFHACK_PLUGIN_IS_ENABLED(enabled);
34+
// The identifier declared with this macro (i.e. is_enabled) is used to track
35+
// whether the plugin is in an "enabled" state. If you don't need enablement
36+
// for your plugin, you don't need this line. This variable will also be read
37+
// by the `plug` builtin command; when true the plugin will be shown as enabled.
38+
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
3139

3240
// Any globals a plugin requires (e.g. world) should be listed here.
3341
// For example, this line expands to "using df::global::world" and prevents the
34-
// plugin from being loaded if df::global::world is null (i.e. missing from symbols.xml):
35-
//
42+
// plugin from being loaded if df::global::world is null (i.e. missing from
43+
// symbols.xml).
3644
REQUIRE_GLOBAL(world);
3745

38-
// You may want some compile time debugging options
39-
// one easy system just requires you to cache the color_ostream &out into a global debug variable
40-
//#define P_DEBUG 1
41-
//uint16_t maxTickFreq = 1200; //maybe you want to use some events
46+
// logging levels can be dynamically controlled with the `debugfilter` command.
47+
namespace DFHack {
48+
// for configuration-related logging
49+
DBG_DECLARE(skeleton, status, DebugCategory::LINFO);
50+
// for logging during the periodic scan
51+
DBG_DECLARE(skeleton, cycle, DebugCategory::LINFO);
52+
}
4253

43-
command_result command_callback1(color_ostream &out, std::vector<std::string> &parameters);
54+
command_result command_callback1(color_ostream &out, vector<string> &parameters);
4455

56+
// run when the plugin is loaded
4557
DFhackCExport command_result plugin_init(color_ostream &out, std::vector<PluginCommand> &commands) {
46-
commands.push_back(PluginCommand("skeleton",
47-
"~54 character description of plugin", //to use one line in the ``[DFHack]# ls`` output
48-
command_callback1,
49-
false,
50-
"example usage"
51-
" skeleton <option> <args>\n"
52-
" explanation of plugin/command\n"
53-
"\n"
54-
" skeleton\n"
55-
" what happens when using the command\n"
56-
"\n"
57-
" skeleton option1\n"
58-
" what happens when using the command with option1\n"
59-
"\n"));
58+
// For in-tree plugins, don't use the "usage" parameter of PluginCommand.
59+
// Instead, add an .rst file with the same name as the plugin to the
60+
// docs/plugins/ directory.
61+
commands.push_back(PluginCommand(
62+
"skeleton",
63+
"Short (~54 character) description of command.", // to use one line in the ``[DFHack]# ls`` output
64+
command_callback1));
6065
return CR_OK;
6166
}
6267

68+
// run when the plugin is unloaded
6369
DFhackCExport command_result plugin_shutdown(color_ostream &out) {
6470
// You *MUST* kill all threads you created before this returns.
6571
// If everything fails, just return CR_FAILURE. Your plugin will be
@@ -68,28 +74,20 @@ DFhackCExport command_result plugin_shutdown(color_ostream &out) {
6874

6975
}
7076

77+
// run when the `enable` or `disable` command is run with this plugin name as
78+
// an argument
7179
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) {
72-
namespace EM = EventManager;
73-
if (enable && !enabled) {
74-
//using namespace EM::EventType;
75-
//EM::EventHandler eventHandler(onNewEvent, maxTickFreq);
76-
//EM::registerListener(EventType::JOB_COMPLETED, eventHandler, plugin_self);
77-
//out.print("plugin enabled!\n");
78-
} else if (!enable && enabled) {
79-
EM::unregisterAll(plugin_self);
80-
//out.print("plugin disabled!\n");
81-
}
82-
enabled = enable;
80+
// you have to maintain the state of the is_enabled variable yourself. it
81+
// doesn't happen automatically.
82+
is_enabled = enable;
8383
return CR_OK;
8484
}
8585

86-
87-
/* OPTIONAL *
8886
// Called to notify the plugin about important state changes.
8987
// Invoked with DF suspended, and always before the matching plugin_onupdate.
9088
// More event codes may be added in the future.
9189
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) {
92-
if (enabled) {
90+
if (is_enabled) {
9391
switch (event) {
9492
case SC_UNKNOWN:
9593
break;
@@ -116,9 +114,8 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
116114
return CR_OK;
117115
}
118116

119-
// Whatever you put here will be done in each game step. Don't abuse it.
120-
DFhackCExport command_result plugin_onupdate ( color_ostream &out )
121-
{
117+
// Whatever you put here will be done in each game frame refresh. Don't abuse it.
118+
DFhackCExport command_result plugin_onupdate (color_ostream &out) {
122119
// whetever. You don't need to suspend DF execution here.
123120
return CR_OK;
124121
}
@@ -128,44 +125,94 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
128125
// and plugin_load_data is called whenever a new world is loaded. If the plugin
129126
// is loaded or unloaded while a world is active, plugin_save_data or
130127
// plugin_load_data will be called immediately.
131-
DFhackCExport command_result plugin_save_data (color_ostream &out)
132-
{
128+
DFhackCExport command_result plugin_save_data (color_ostream &out) {
133129
// Call functions in the Persistence module here.
134130
return CR_OK;
135131
}
136132

137-
DFhackCExport command_result plugin_load_data (color_ostream &out)
138-
{
133+
DFhackCExport command_result plugin_load_data (color_ostream &out) {
139134
// Call functions in the Persistence module here.
140135
return CR_OK;
141136
}
142-
* OPTIONAL */
143-
144-
145-
// A command! It sits around and looks pretty. And it's nice and friendly.
146-
command_result command_callback1(color_ostream &out, std::vector<std::string> &parameters) {
147-
// It's nice to print a help message you get invalid options
148-
// from the user instead of just acting strange.
149-
// This can be achieved by adding the extended help string to the
150-
// PluginCommand registration as show above, and then returning
151-
// CR_WRONG_USAGE from the function. The same string will also
152-
// be used by 'help your-command'.
153-
if (!parameters.empty()) {
154-
return CR_WRONG_USAGE; //or maybe you want it to do something else
137+
138+
// define the structure that will represent the possible commandline options
139+
struct command_options {
140+
// whether to display help
141+
bool help = false;
142+
143+
// whether to run a cycle right now
144+
bool now = false;
145+
146+
// how many ticks to wait between cycles when enabled, -1 means unset
147+
int32_t ticks = -1;
148+
149+
// example params of different types
150+
df::coord start;
151+
string format;
152+
vector<string*> list; // note this must be a vector of pointers, not objects
153+
154+
static struct_identity _identity;
155+
};
156+
static const struct_field_info command_options_fields[] = {
157+
{ struct_field_info::PRIMITIVE, "help", offsetof(command_options, help), &df::identity_traits<bool>::identity, 0, 0 },
158+
{ struct_field_info::PRIMITIVE, "now", offsetof(command_options, now), &df::identity_traits<bool>::identity, 0, 0 },
159+
{ struct_field_info::PRIMITIVE, "ticks", offsetof(command_options, ticks), &df::identity_traits<int32_t>::identity, 0, 0 },
160+
{ struct_field_info::SUBSTRUCT, "start", offsetof(command_options, start), &df::coord::_identity, 0, 0 },
161+
{ struct_field_info::PRIMITIVE, "format", offsetof(command_options, format), df::identity_traits<string>::get(), 0, 0 },
162+
{ struct_field_info::STL_VECTOR_PTR, "list", offsetof(command_options, list), df::identity_traits<string>::get(), 0, 0 },
163+
{ struct_field_info::END }
164+
};
165+
struct_identity command_options::_identity(sizeof(command_options), &df::allocator_fn<command_options>, NULL, "command_options", NULL, command_options_fields);
166+
167+
// load the lua module associated with the plugin and parse the commandline
168+
// in lua (which has better facilities than C++ for string parsing). You should
169+
// create a file named after your plugin in the plugins/lua directory. This
170+
// example expects you to define a global function in that file named
171+
// "parse_commandline" that takes the options struct defined above along with
172+
// the commandline parameters. It should parse the parameters and set data in
173+
// the options structure. See plugins/lua/skeleton.lua for an example.
174+
static bool get_options(color_ostream &out,
175+
command_options &opts,
176+
const vector<string> &parameters)
177+
{
178+
auto L = Lua::Core::State;
179+
Lua::StackUnwinder top(L);
180+
181+
if (!lua_checkstack(L, parameters.size() + 2) ||
182+
!Lua::PushModulePublic(
183+
out, L, ("plugins." + string(plugin_name)).c_str(),
184+
"parse_commandline")) {
185+
out.printerr("Failed to load %s Lua code\n", plugin_name);
186+
return false;
155187
}
156-
// Commands are called from threads other than the DF one.
157-
// Suspend this thread until DF has time for us.
158-
// **If you use CoreSuspender** it'll automatically resume DF when
159-
// execution leaves the current scope.
188+
189+
Lua::Push(L, &opts);
190+
for (const string &param : parameters)
191+
Lua::Push(L, param);
192+
193+
if (!Lua::SafeCall(out, L, parameters.size() + 1, 0))
194+
return false;
195+
196+
return true;
197+
}
198+
199+
// This is the callback we registered in plugin_init. Note that while plugin
200+
// callbacks are called with the core suspended, command callbacks are called
201+
// from a different thread and need to explicity suspend the core if they
202+
// interact with Lua or DF game state (most commands do at least one of these).
203+
static command_result command_callback1(color_ostream &out, vector<string> &parameters) {
204+
// I'll say it again: always suspend the core in command callbacks unless
205+
// all your data is local.
160206
CoreSuspender suspend;
161-
// Actually do something here. Yay.
162207

163-
// process parameters
164-
if (parameters.size() == 1 && parameters[0] == "option1") {
165-
// stuff
166-
} else {
167-
return CR_FAILURE;
168-
}
169-
// Give control back to DF.
208+
// Return CR_WRONG_USAGE to print out your help text. The help text is
209+
// sourced from the associated rst file in docs/plugins/. The same help will
210+
// also be returned by 'help your-command'.
211+
command_options opts;
212+
if (!get_options(out, opts, parameters) || opts.help)
213+
return CR_WRONG_USAGE;
214+
215+
// TODO: do something according to the flags set in the options struct
216+
170217
return CR_OK;
171218
}

0 commit comments

Comments
 (0)