summaryrefslogtreecommitdiffstats
path: root/src/Bindings/PluginManager.h
blob: 4973f89dc563f36a1ee74ba35358891732582657 (plain) (blame)
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
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602

#pragma once


#include "../BlockType.h"
#include "../Defines.h"
#include "../FunctionRef.h"





// fwd:
class cBlockEntityWithItems;
class cBrewingstandEntity;
class cChunkDesc;
class cClientHandle;
class cCommandOutputCallback;
class cCraftingGrid;
class cCraftingRecipe;
class cDropSpenserEntity;
class cEntity;
class cHopperEntity;
class cItems;
class cMonster;
class cPickup;
class cPlayer;
class cPlugin;
class cProjectileEntity;
class cWindow;
class cWorld;
class cSettingsRepositoryInterface;
class cDeadlockDetect;
struct TakeDamageInfo;

typedef std::shared_ptr<cPlugin> cPluginPtr;
typedef std::vector<cPluginPtr> cPluginPtrs;





// tolua_begin
class cPluginManager
{
  public:
	enum CommandResult
	{
		crExecuted,
		crUnknownCommand,
		crError,
		crBlocked,
		crNoPermission,
	};


	/** Defines the status of a single plugin - whether it is loaded, disabled or errored. */
	enum ePluginStatus
	{
		/** The plugin has been loaded successfully. */
		psLoaded,

		/** The plugin is disabled in settings.ini. */
		psDisabled,

		/** The plugin is enabled in settings.ini but has been unloaded (by a command). */
		psUnloaded,

		/** The plugin is enabled in settings.ini but has failed to load.
		m_LoadError is the description of the error. */
		psError,

		/** The plugin has been loaded before, but after a folder refresh it is no longer present.
		The plugin will be unloaded in the next call to ReloadPlugins(). */
		psNotFound,
	};


	enum PluginHook
	{
		HOOK_BLOCK_SPREAD,
		HOOK_BLOCK_TO_PICKUPS,
		HOOK_BREWING_COMPLETING,
		HOOK_BREWING_COMPLETED,
		HOOK_CHAT,
		HOOK_CHUNK_AVAILABLE,
		HOOK_CHUNK_GENERATED,
		HOOK_CHUNK_GENERATING,
		HOOK_CHUNK_UNLOADED,
		HOOK_CHUNK_UNLOADING,
		HOOK_COLLECTING_PICKUP,
		HOOK_CRAFTING_NO_RECIPE,
		HOOK_DISCONNECT,
		HOOK_PLAYER_ANIMATION,
		HOOK_ENTITY_ADD_EFFECT,
		HOOK_ENTITY_CHANGING_WORLD,
		HOOK_ENTITY_CHANGED_WORLD,
		HOOK_EXECUTE_COMMAND,
		HOOK_EXPLODED,
		HOOK_EXPLODING,
		HOOK_HANDSHAKE,
		HOOK_HOPPER_PULLING_ITEM,
		HOOK_HOPPER_PUSHING_ITEM,
		HOOK_DROPSPENSE,
		HOOK_KILLED,
		HOOK_KILLING,
		HOOK_LOGIN,
		HOOK_LOGIN_FORGE,
		HOOK_PLAYER_BREAKING_BLOCK,
		HOOK_PLAYER_BROKEN_BLOCK,
		HOOK_PLAYER_DESTROYED,
		HOOK_PLAYER_EATING,
		HOOK_PLAYER_FISHED,
		HOOK_PLAYER_FISHING,
		HOOK_PLAYER_FOOD_LEVEL_CHANGE,
		HOOK_PLAYER_JOINED,
		HOOK_PLAYER_LEFT_CLICK,
		HOOK_PLAYER_MOVING,
		HOOK_PLAYER_OPENING_WINDOW,
		HOOK_PLAYER_PLACED_BLOCK,
		HOOK_PLAYER_PLACING_BLOCK,
		HOOK_PLAYER_CROUCHED,
		HOOK_PLAYER_RIGHT_CLICK,
		HOOK_PLAYER_RIGHT_CLICKING_ENTITY,
		HOOK_PLAYER_SHOOTING,
		HOOK_PLAYER_SPAWNED,
		HOOK_ENTITY_TELEPORT,
		HOOK_PLAYER_TOSSING_ITEM,
		HOOK_PLAYER_USED_BLOCK,
		HOOK_PLAYER_USED_ITEM,
		HOOK_PLAYER_USING_BLOCK,
		HOOK_PLAYER_USING_ITEM,
		HOOK_PLUGIN_MESSAGE,
		HOOK_PLUGINS_LOADED,
		HOOK_POST_CRAFTING,
		HOOK_PRE_CRAFTING,
		HOOK_PROJECTILE_HIT_BLOCK,
		HOOK_PROJECTILE_HIT_ENTITY,
		HOOK_SERVER_PING,
		HOOK_SPAWNED_ENTITY,
		HOOK_SPAWNED_MONSTER,
		HOOK_SPAWNING_ENTITY,
		HOOK_SPAWNING_MONSTER,
		HOOK_TAKE_DAMAGE,
		HOOK_TICK,
		HOOK_UPDATED_SIGN,
		HOOK_UPDATING_SIGN,
		HOOK_WEATHER_CHANGED,
		HOOK_WEATHER_CHANGING,
		HOOK_WORLD_STARTED,
		HOOK_WORLD_TICK,

		// tolua_end

		// Note that if a hook type is added, it may need processing in cPlugin::CanAddHook() descendants,
		//   and it definitely needs adding in cPluginLua::GetHookFnName() !

		// Keep these two as the last items, they are used for validity checking and get their values automagically
		HOOK_NUM_HOOKS,
		HOOK_MAX = HOOK_NUM_HOOKS - 1,
	};  // tolua_export


	/** Defines the deferred actions needed for a plugin */
	enum class PluginAction
	{
		Reload,
		Unload
	};


	/** Used as a callback for enumerating bound commands */
	class cCommandEnumCallback
	{
	  public:
		virtual ~cCommandEnumCallback() {}

		/** Called for each command; return true to abort enumeration
		For console commands, a_Permission is not used (set to empty string)
		*/
		virtual bool Command(
			const AString & a_Command,
			const cPlugin * a_Plugin,
			const AString & a_Permission,
			const AString & a_HelpString
		) = 0;
	};


	/** Interface that must be provided by any class that implements a command handler, either in-game or console
	 * command. */
	class cCommandHandler
	{
	  public:
		// Force a virtual destructor in descendants
		virtual ~cCommandHandler() {}

		/** Executes the specified in-game command.
		a_Split is the command string, split at the spaces.
		a_Player is the player executing the command, nullptr in case of the console.
		a_Command is the entire command string.
		a_Output is the sink into which the additional text returned by the command handler should be sent; only used
		for console commands. */
		virtual bool ExecuteCommand(
			const AStringVector & a_Split,
			cPlayer * a_Player,
			const AString & a_Command,
			cCommandOutputCallback * a_Output = nullptr
		) = 0;
	};

	typedef std::shared_ptr<cCommandHandler> cCommandHandlerPtr;


	/** The interface used for enumerating and extern-calling plugins */
	using cPluginCallback = cFunctionRef<bool(cPlugin &)>;

	typedef std::list<cPlugin *> PluginList;


	/** Called each tick, calls the plugins' OnTick hook, as well as processes plugin events (addition, removal) */
	void Tick(float a_Dt);

	/** Returns the instance of the Plugin Manager (there is only ever one) */
	static cPluginManager * Get(void);  // tolua_export

	/** Refreshes the m_Plugins list based on the current contents of the Plugins folder.
	If an active plugin's folder is not found anymore, the plugin is set as psNotFound, but not yet unloaded. */
	void RefreshPluginList();  // tolua_export

	/** Schedules a reload of the plugins to happen within the next call to Tick(). */
	void ReloadPlugins();  // tolua_export

	/** Adds the plugin to the list of plugins called for the specified hook type.
	If a plugin adds multiple handlers for a single hook, it is added only once (ignore-duplicates). */
	void AddHook(cPlugin * a_Plugin, int a_HookType);

	/** Returns the number of all plugins in m_Plugins (includes disabled, unloaded and errored plugins). */
	size_t GetNumPlugins() const;  // tolua_export

	/** Returns the number of plugins that are psLoaded. */
	size_t GetNumLoadedPlugins(void) const;  // tolua_export

	// Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort
	bool CallHookBlockSpread(cWorld & a_World, Vector3i a_BlockPos, eSpreadSource a_Source);
	bool CallHookBlockToPickups(
		cWorld & a_World,
		Vector3i a_BlockPos,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta,
		const cBlockEntity * a_BlockEntity,
		const cEntity * a_Digger,
		const cItem * a_Tool,
		cItems & a_Pickups
	);
	bool CallHookBrewingCompleting(cWorld & a_World, cBrewingstandEntity & a_Brewingstand);
	bool CallHookBrewingCompleted(cWorld & a_World, cBrewingstandEntity & a_Brewingstand);
	bool CallHookChat(cPlayer & a_Player, AString & a_Message);
	bool CallHookChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ);
	bool CallHookChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc);
	bool CallHookChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc);
	bool CallHookChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ);
	bool CallHookChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ);
	bool CallHookCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup);
	bool CallHookCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe);
	bool CallHookDisconnect(cClientHandle & a_Client, const AString & a_Reason);
	bool CallHookEntityAddEffect(
		cEntity & a_Entity,
		int a_EffectType,
		int a_EffectDurationTicks,
		int a_EffectIntensity,
		double a_DistanceModifier
	);
	bool CallHookEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition);
	bool CallHookEntityChangingWorld(cEntity & a_Entity, cWorld & a_World);
	bool CallHookEntityChangedWorld(cEntity & a_Entity, cWorld & a_World);
	bool CallHookExecuteCommand(
		cPlayer * a_Player,
		const AStringVector & a_Split,
		const AString & a_EntireCommand,
		CommandResult & a_Result
	);  // If a_Player == nullptr, it is a console cmd
	bool CallHookExploded(
		cWorld & a_World,
		double a_ExplosionSize,
		bool a_CanCauseFire,
		double a_X,
		double a_Y,
		double a_Z,
		eExplosionSource a_Source,
		void * a_SourceData
	);
	bool CallHookExploding(
		cWorld & a_World,
		double & a_ExplosionSize,
		bool & a_CanCauseFire,
		double a_X,
		double a_Y,
		double a_Z,
		eExplosionSource a_Source,
		void * a_SourceData
	);
	bool CallHookHandshake(cClientHandle & a_ClientHandle, const AString & a_Username);
	bool CallHookHopperPullingItem(
		cWorld & a_World,
		cHopperEntity & a_Hopper,
		int a_DstSlotNum,
		cBlockEntityWithItems & a_SrcEntity,
		int a_SrcSlotNum
	);
	bool CallHookHopperPushingItem(
		cWorld & a_World,
		cHopperEntity & a_Hopper,
		int a_SrcSlotNum,
		cBlockEntityWithItems & a_DstEntity,
		int a_DstSlotNum
	);
	bool CallHookDropSpense(cWorld & a_World, cDropSpenserEntity & a_DropSpenser, int a_SlotNum);
	bool CallHookKilled(cEntity & a_Victim, TakeDamageInfo & a_TDI, AString & a_DeathMessage);
	bool CallHookKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI);
	bool CallHookLogin(cClientHandle & a_Client, UInt32 a_ProtocolVersion, const AString & a_Username);
	bool CallHookLoginForge(cClientHandle & a_Client, AStringMap & a_Mods);
	bool CallHookPlayerAnimation(cPlayer & a_Player, int a_Animation);
	bool CallHookPlayerBreakingBlock(
		cPlayer & a_Player,
		Vector3i a_BlockPos,
		eBlockFace a_BlockFace,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta
	);
	bool CallHookPlayerBrokenBlock(
		cPlayer & a_Player,
		Vector3i a_BlockPos,
		eBlockFace a_BlockFace,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta
	);
	bool CallHookPlayerDestroyed(cPlayer & a_Player);
	bool CallHookPlayerEating(cPlayer & a_Player);
	bool CallHookPlayerFished(cPlayer & a_Player, const cItems & a_Reward, const int ExperienceAmount);
	bool CallHookPlayerFishing(cPlayer & a_Player, cItems & a_Reward, int & ExperienceAmount);
	bool CallHookPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel);
	bool CallHookPlayerJoined(cPlayer & a_Player);
	bool CallHookPlayerLeftClick(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, char a_Status);
	bool CallHookPlayerMoving(
		cPlayer & a_Player,
		const Vector3d & a_OldPosition,
		const Vector3d & a_NewPosition,
		bool a_PreviousIsOnGround
	);
	bool CallHookPlayerOpeningWindow(cPlayer & a_Player, cWindow & a_Window);
	bool CallHookPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange);
	bool CallHookPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange);
	bool CallHookPlayerCrouched(cPlayer & a_Player);
	bool CallHookPlayerRightClick(
		cPlayer & a_Player,
		Vector3i a_BlockPos,
		eBlockFace a_BlockFace,
		Vector3i a_CursorPos
	);
	bool CallHookPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity);
	bool CallHookPlayerShooting(cPlayer & a_Player);
	bool CallHookPlayerSpawned(cPlayer & a_Player);
	bool CallHookPlayerTossingItem(cPlayer & a_Player);
	bool CallHookPlayerUsedBlock(
		cPlayer & a_Player,
		Vector3i a_BlockPos,
		eBlockFace a_BlockFace,
		Vector3i a_CursorPos,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta
	);
	bool CallHookPlayerUsedItem(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos);
	bool CallHookPlayerUsingBlock(
		cPlayer & a_Player,
		Vector3i a_BlockPos,
		eBlockFace a_BlockFace,
		Vector3i a_CursorPos,
		BLOCKTYPE a_BlockType,
		NIBBLETYPE a_BlockMeta
	);
	bool CallHookPlayerUsingItem(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos);
	bool CallHookPluginMessage(cClientHandle & a_Client, const AString & a_Channel, ContiguousByteBufferView a_Message);
	bool CallHookPluginsLoaded(void);
	bool CallHookPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe);
	bool CallHookPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe);
	bool CallHookProjectileHitBlock(
		cProjectileEntity & a_Projectile,
		Vector3i a_BlockPos,
		eBlockFace a_Face,
		const Vector3d & a_BlockHitPos
	);
	bool CallHookProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity);
	bool CallHookServerPing(
		cClientHandle & a_ClientHandle,
		AString & a_ServerDescription,
		int & a_OnlinePlayersCount,
		int & a_MaxPlayersCount,
		AString & a_Favicon
	);
	bool CallHookSpawnedEntity(cWorld & a_World, cEntity & a_Entity);
	bool CallHookSpawnedMonster(cWorld & a_World, cMonster & a_Monster);
	bool CallHookSpawningEntity(cWorld & a_World, cEntity & a_Entity);
	bool CallHookSpawningMonster(cWorld & a_World, cMonster & a_Monster);
	bool CallHookTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI);
	bool CallHookUpdatedSign(
		cWorld & a_World,
		Vector3i a_BlockPos,
		const AString & a_Line1,
		const AString & a_Line2,
		const AString & a_Line3,
		const AString & a_Line4,
		cPlayer * a_Player
	);
	bool CallHookUpdatingSign(
		cWorld & a_World,
		Vector3i a_BlockPos,
		AString & a_Line1,
		AString & a_Line2,
		AString & a_Line3,
		AString & a_Line4,
		cPlayer * a_Player
	);
	bool CallHookWeatherChanged(cWorld & a_World);
	bool CallHookWeatherChanging(cWorld & a_World, eWeather & a_NewWeather);
	bool CallHookWorldStarted(cWorld & a_World);
	bool CallHookWorldTick(
		cWorld & a_World,
		std::chrono::milliseconds a_Dt,
		std::chrono::milliseconds a_LastTickDurationMSec
	);

	/** Queues the specified plugin to be unloaded in the next call to Tick().
	Note that this function returns before the plugin is unloaded, to avoid deadlocks. */
	void UnloadPlugin(const AString & a_PluginFolder);  // tolua_export

	/** Queues the specified plugin to be reloaded in the next call to Tick().
	Note that this function returns before the plugin is unloaded, to avoid deadlocks. */
	void ReloadPlugin(const AString & a_PluginFolder);  // tolua_export

	/** Loads the plugin from the specified plugin folder.
	Returns true if the plugin was loaded successfully or was already loaded before, false otherwise. */
	bool LoadPlugin(const AString & a_PluginFolder);  // tolua_export

	/** Removes all hooks the specified plugin has registered */
	void RemoveHooks(cPlugin * a_Plugin);

	/** Removes the plugin of the specified name from the internal structures and deletes its object. */
	void RemovePlugin(const AString & a_PluginName);

	/** Removes all command bindings that the specified plugin has made */
	void RemovePluginCommands(cPlugin * a_Plugin);

	/** Returns true if the specified plugin is loaded. */
	bool IsPluginLoaded(const AString & a_PluginName);  // tolua_export

	/** Binds a command to the specified handler.
	Returns true if successful, false if command already bound.
	Exported in ManualBindings.cpp. */
	bool BindCommand(
		const AString & a_Command,
		cPlugin * a_Plugin,
		cCommandHandlerPtr a_Handler,
		const AString & a_Permission,
		const AString & a_HelpString
	);

	/** Calls a_Callback for each bound command, returns true if all commands were enumerated */
	bool ForEachCommand(cCommandEnumCallback & a_Callback);  // Exported in ManualBindings.cpp

	/** Returns true if the command is in the command map */
	bool IsCommandBound(const AString & a_Command);  // tolua_export

	/** Returns the permission needed for the specified command; empty string if command not found */
	AString GetCommandPermission(const AString & a_Command);  // tolua_export

	/** Executes the command, as if it was requested by a_Player. Checks permissions first. Returns crExecuted if
	 * executed. */
	CommandResult ExecuteCommand(cPlayer & a_Player, const AString & a_Command);  // tolua_export

	/** Executes the command, as if it was requested by a_Player. Permisssions are not checked. Returns crExecuted if
	 * executed. */
	CommandResult ForceExecuteCommand(cPlayer & a_Player, const AString & a_Command);  // tolua_export

	/** Removes all console command bindings that the specified plugin has made */
	void RemovePluginConsoleCommands(cPlugin * a_Plugin);

	/** Binds a console command to the specified handler.
	Returns true if successful, false if command already bound.
	Exported in ManualBindings.cpp. */
	bool BindConsoleCommand(
		const AString & a_Command,
		cPlugin * a_Plugin,
		cCommandHandlerPtr a_Handler,
		const AString & a_HelpString
	);

	/** Calls a_Callback for each bound console command, returns true if all commands were enumerated */
	bool ForEachConsoleCommand(cCommandEnumCallback & a_Callback);  // Exported in ManualBindings.cpp

	/** Returns true if the console command is in the command map */
	bool IsConsoleCommandBound(const AString & a_Command);  // tolua_export

	/** Executes the command split into a_Split, as if it was given on the console.
	Returns true if executed. Output is sent to the a_Output callback
	Exported in ManualBindings.cpp with a different signature. */
	bool ExecuteConsoleCommand(
		const AStringVector & a_Split,
		cCommandOutputCallback & a_Output,
		const AString & a_Command
	);

	/** Appends all commands beginning with a_Text (case-insensitive) into a_Results.
	If a_Player is not nullptr, only commands for which the player has permissions are added.
	*/
	void TabCompleteCommand(const AString & a_Text, AStringVector & a_Results, cPlayer * a_Player);

	/** Returns true if the specified hook type is within the allowed range */
	static bool IsValidHookType(int a_HookType);

	/** Calls the specified callback with the plugin object of the specified plugin.
	Returns false if plugin not found, otherwise returns the value that the callback has returned. */
	bool DoWithPlugin(const AString & a_PluginName, cPluginCallback a_Callback);

	/** Calls the specified callback for each plugin in m_Plugins.
	Returns true if all plugins have been reported, false if the callback has aborted the enumeration by returning true.
  */
	bool ForEachPlugin(cPluginCallback a_Callback);

	/** Returns the name of the folder (cPlugin::GetFolderName()) from which the specified plugin was loaded. */
	AString GetPluginFolderName(const AString & a_PluginName);  // tolua_export

	/** Returns the path where individual plugins' folders are expected.
	The path doesn't end in a slash. */
	static AString GetPluginsPath(void) { return "Plugins"; }  // tolua_export

  private:
	friend class cRoot;

	class cCommandReg
	{
	  public:
		cPlugin * m_Plugin;
		AString m_Permission;  // Not used for console commands
		AString m_HelpString;
		cCommandHandlerPtr m_Handler;
	};

	typedef std::map<int, cPluginManager::PluginList> HookMap;
	typedef std::map<AString, cCommandReg> CommandMap;


	/** FolderNames of plugins that need an action (unload, reload, ...).
	The plugins will be acted upon within the next call to Tick(), to avoid multithreading issues.
	Protected against multithreaded access by m_CSPluginsNeedAction. */
	std::vector<std::pair<PluginAction, AString>> m_PluginsNeedAction;

	/** Protects m_PluginsToUnload against multithreaded access. */
	mutable cCriticalSection m_CSPluginsNeedAction;

	/** All plugins that have been found in the Plugins folder. */
	cPluginPtrs m_Plugins;

	HookMap m_Hooks;
	CommandMap m_Commands;
	CommandMap m_ConsoleCommands;

	/** If set to true, all the plugins will be reloaded within the next call to Tick(). */
	bool m_bReloadPlugins;

	/** The deadlock detect in which all plugins should track their CSs. */
	cDeadlockDetect & m_DeadlockDetect;


	cPluginManager(cDeadlockDetect & a_DeadlockDetect);
	virtual ~cPluginManager();

	/** Reloads all plugins, defaulting to settings.ini for settings location */
	void ReloadPluginsNow(void);

	/** Reloads all plugins with a settings repo expected to be initialised to settings.ini */
	void ReloadPluginsNow(cSettingsRepositoryInterface & a_Settings);

	/** Unloads all plugins */
	void UnloadPluginsNow(void);

	/** Handles writing default plugins if 'Plugins' key not found using a settings repo expected to be intialised to
	 * settings.ini */
	void InsertDefaultPlugins(cSettingsRepositoryInterface & a_Settings);

	/** Tries to match a_Command to the internal table of commands, if a match is found, the corresponding plugin is
	 * called. Returns crExecuted if the command is executed. */
	CommandResult HandleCommand(cPlayer & a_Player, const AString & a_Command, bool a_ShouldCheckPermissions);

	/** Returns the folders that are specified in the settings ini to load plugins from. */
	AStringVector GetFoldersToLoad(cSettingsRepositoryInterface & a_Settings);

	/** Calls a_HookFunction on each plugin registered to the hook HookName.
	Returns false if the action is to continue or true if the plugin wants to abort.
	Accessible only from within PluginManager.cpp */
	template <typename HookFunction> bool GenericCallHook(PluginHook a_HookName, HookFunction a_HookFunction);
};  // tolua_export