Cuberite
A lightweight, fast and extensible game server for Minecraft
PluginManager.cpp
Go to the documentation of this file.
1 
2 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
3 
4 #include "PluginManager.h"
5 #include "Plugin.h"
6 #include "PluginLua.h"
7 #include "../Item.h"
8 #include "../Root.h"
9 #include "../Server.h"
10 #include "../CommandOutput.h"
11 
12 #include "../IniFile.h"
13 #include "../Entities/Player.h"
14 
15 
16 
17 
18 
20 {
21  return cRoot::Get()->GetPluginManager();
22 }
23 
24 
25 
26 
27 
29  m_bReloadPlugins(false),
30  m_DeadlockDetect(a_DeadlockDetect)
31 {
32 }
33 
34 
35 
36 
37 
39 {
41 }
42 
43 
44 
45 
46 
48 {
49  m_bReloadPlugins = true;
50 }
51 
52 
53 
54 
55 
57 {
58  // Get a list of currently available folders:
59  AString PluginsPath = GetPluginsPath() + "/";
60  AStringVector Contents = cFile::GetFolderContents(PluginsPath);
61  AStringVector Folders;
62  for (auto & item: Contents)
63  {
64  if (!cFile::IsFolder(PluginsPath + item))
65  {
66  // We only want folders, and don't want "." or ".."
67  continue;
68  }
69  Folders.push_back(item);
70  } // for item - Contents[]
71 
72  // Set all plugins with invalid folders as psNotFound:
73  for (auto & plugin: m_Plugins)
74  {
75  if (std::find(Folders.cbegin(), Folders.cend(), plugin->GetFolderName()) == Folders.end())
76  {
77  plugin->m_Status = psNotFound;
78  }
79  } // for plugin - m_Plugins[]
80 
81  // Add all newly discovered plugins:
82  for (auto & folder: Folders)
83  {
84  bool hasFound = false;
85  for (auto & plugin: m_Plugins)
86  {
87  if (plugin->GetFolderName() == folder)
88  {
89  hasFound = true;
90  break;
91  }
92  } // for plugin - m_Plugins[]
93  if (!hasFound)
94  {
95  m_Plugins.push_back(std::make_shared<cPluginLua>(folder, m_DeadlockDetect));
96  }
97  } // for folder - Folders[]
98 }
99 
100 
101 
102 
103 
105 {
106  cIniFile a_SettingsIni;
107  a_SettingsIni.ReadFile(cRoot::Get()->m_SettingsFilename);
108  ReloadPluginsNow(a_SettingsIni);
109 }
110 
111 
112 
113 
114 
116 {
117  LOG("-- Loading Plugins --");
118 
119  // Unload any existing plugins:
120  m_bReloadPlugins = false;
122 
123  // Refresh the list of plugins to load new ones from disk / remove the deleted ones:
125 
126  // Load the plugins:
127  AStringVector ToLoad = GetFoldersToLoad(a_Settings);
128  for (auto & pluginFolder: ToLoad)
129  {
130  LoadPlugin(pluginFolder);
131  } // for pluginFolder - ToLoad[]
132 
133  // Log a report of the loading process
134  size_t NumLoadedPlugins = GetNumLoadedPlugins();
135  if (NumLoadedPlugins == 0)
136  {
137  LOG("-- No Plugins Loaded --");
138  }
139  else if (NumLoadedPlugins == 1)
140  {
141  LOG("-- Loaded 1 Plugin --");
142  }
143  else
144  {
145  LOG("-- Loaded %u Plugins --", static_cast<unsigned>(NumLoadedPlugins));
146  }
148 }
149 
150 
151 
152 
153 
155 {
156  a_Settings.AddKeyName("Plugins");
157  a_Settings.AddValue("Plugins", "Core", "1");
158  a_Settings.AddValue("Plugins", "ChatLog", "1");
159  a_Settings.AddValue("Plugins", "ProtectionAreas", "0");
160 }
161 
162 
163 
164 
165 
166 void cPluginManager::Tick(float a_Dt)
167 {
168  decltype(m_PluginsNeedAction) PluginsNeedAction;
169  {
171  std::swap(m_PluginsNeedAction, PluginsNeedAction);
172  }
173 
174  // Process deferred actions:
175  for (auto & CurrentPlugin : PluginsNeedAction)
176  {
177  auto & Action = CurrentPlugin.first;
178  auto & Folder = CurrentPlugin.second;
179 
180  bool WasLoaded = false;
181  bool WasFound = false;
182  for (auto & Plugin: m_Plugins)
183  {
184  if (Plugin->GetFolderName() == Folder)
185  {
186  WasFound = true;
187  if (Plugin->IsLoaded())
188  {
189  switch (Action)
190  {
191  case PluginAction::Reload :
192  {
193  // Reload plugins by unloading, then loading:
194  Plugin->Unload();
195  Plugin->Load();
196  break;
197  }
198  case PluginAction::Unload :
199  {
200  // Unload plugins that have been scheduled for unloading:
201  Plugin->Unload();
202  break;
203  }
204  }
205  WasLoaded = true;
206  }
207  }
208  }
209  if (!WasFound)
210  {
211  LOG("Cannot act on plugin in folder \"%s\", there's no such plugin folder", Folder.c_str());
212  }
213  else if (!WasLoaded)
214  {
215  LOG("Cannot act on plugin in folder \"%s\", it has not been loaded.", Folder.c_str());
216  }
217  } // for plugin - m_Plugins[]
218 
219  // If a plugin reload has been scheduled, reload now:
220  if (m_bReloadPlugins)
221  {
223  }
224 
225  auto Plugins = m_Hooks.find(HOOK_TICK);
226  if (Plugins == m_Hooks.end())
227  {
228  return;
229  }
230 
231  for (auto * Plugin : Plugins->second)
232  {
233  Plugin->Tick(a_Dt);
234  }
235 }
236 
237 
238 
239 
240 
241 template <typename HookFunction>
242 bool cPluginManager::GenericCallHook(PluginHook a_HookName, HookFunction a_HookFunction)
243 {
244  auto Plugins = m_Hooks.find(a_HookName);
245  if (Plugins == m_Hooks.end())
246  {
247  return false;
248  }
249 
250  return std::any_of(Plugins->second.begin(), Plugins->second.end(), a_HookFunction);
251 }
252 
253 
254 
255 
256 
258 {
259  return GenericCallHook(HOOK_BLOCK_SPREAD, [&](cPlugin * a_Plugin)
260  {
261  return a_Plugin->OnBlockSpread(a_World, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Source);
262  }
263  );
264 }
265 
266 
267 
268 
269 
271  cWorld & a_World,
272  Vector3i a_BlockPos,
273  BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
274  const cBlockEntity * a_BlockEntity,
275  const cEntity * a_Digger,
276  const cItem * a_Tool,
277  cItems & a_Pickups
278 )
279 {
280  return GenericCallHook(HOOK_BLOCK_TO_PICKUPS, [&](cPlugin * a_Plugin)
281  {
282  return a_Plugin->OnBlockToPickups(a_World, a_BlockPos, a_BlockType, a_BlockMeta, a_BlockEntity, a_Digger, a_Tool, a_Pickups);
283  }
284  );
285 }
286 
287 
288 
289 
290 
292 {
293  return GenericCallHook(HOOK_BREWING_COMPLETED, [&](cPlugin * a_Plugin)
294  {
295  return a_Plugin->OnBrewingCompleted(a_World, a_Brewingstand);
296  }
297  );
298 }
299 
300 
301 
302 
303 
305 {
306  return GenericCallHook(HOOK_BREWING_COMPLETING, [&](cPlugin * a_Plugin)
307  {
308  return a_Plugin->OnBrewingCompleting(a_World, a_Brewingstand);
309  }
310  );
311 }
312 
313 
314 
315 
316 
317 bool cPluginManager::CallHookChat(cPlayer & a_Player, AString & a_Message)
318 {
319  // Check if the message contains a command, execute it:
320  switch (HandleCommand(a_Player, a_Message, true))
321  {
322  case crExecuted:
323  {
324  // The command has executed successfully
325  return true;
326  }
327 
328  case crBlocked:
329  {
330  // The command was blocked by a plugin using HOOK_EXECUTE_COMMAND
331  // The plugin has most likely sent a message to the player already
332  return true;
333  }
334 
335  case crError:
336  {
337  // An error in the plugin has prevented the command from executing. Report the error to the player:
338  a_Player.SendMessageFailure(fmt::format(FMT_STRING("Something went wrong while executing command \"{}\""), a_Message));
339  return true;
340  }
341 
342  case crNoPermission:
343  {
344  // The player is not allowed to execute this command
345  a_Player.SendMessageFailure(fmt::format(FMT_STRING("Forbidden command; insufficient privileges: \"{}\""), a_Message));
346  return true;
347  }
348 
349  case crUnknownCommand:
350  {
351  // This was not a known command, keep processing as a message
352  break;
353  }
354  }
355 
356  // Check if the message is a command (starts with a slash). If it is, we know that it wasn't recognised:
357  if (!a_Message.empty() && (a_Message[0] == '/'))
358  {
359  AStringVector Split(StringSplit(a_Message, " "));
360  ASSERT(!Split.empty()); // This should not happen - we know there's at least one char in the message so the split needs to be at least one item long
361  a_Player.SendMessageInfo(fmt::format(FMT_STRING("Unknown command: \"{}\""), a_Message));
362  LOGINFO("Player %s issued an unknown command: \"%s\"", a_Player.GetName(), a_Message);
363  return true; // Cancel sending
364  }
365 
366  return GenericCallHook(HOOK_CHAT, [&](cPlugin * a_Plugin)
367  {
368  return a_Plugin->OnChat(a_Player, a_Message);
369  }
370  );
371 }
372 
373 
374 
375 
376 
377 bool cPluginManager::CallHookChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
378 {
379  return GenericCallHook(HOOK_CHUNK_AVAILABLE, [&](cPlugin * a_Plugin)
380  {
381  return a_Plugin->OnChunkAvailable(a_World, a_ChunkX, a_ChunkZ);
382  }
383  );
384 }
385 
386 
387 
388 
389 
390 bool cPluginManager::CallHookChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc)
391 {
392  return GenericCallHook(HOOK_CHUNK_GENERATED, [&](cPlugin * a_Plugin)
393  {
394  return a_Plugin->OnChunkGenerated(a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc);
395  }
396  );
397 }
398 
399 
400 
401 
402 
403 bool cPluginManager::CallHookChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc)
404 {
405  return GenericCallHook(HOOK_CHUNK_GENERATING, [&](cPlugin * a_Plugin)
406  {
407  return a_Plugin->OnChunkGenerating(a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc);
408  }
409  );
410 }
411 
412 
413 
414 
415 
416 bool cPluginManager::CallHookChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
417 {
418  return GenericCallHook(HOOK_CHUNK_UNLOADED, [&](cPlugin * a_Plugin)
419  {
420  return a_Plugin->OnChunkUnloaded(a_World, a_ChunkX, a_ChunkZ);
421  }
422  );
423 }
424 
425 
426 
427 
428 
429 bool cPluginManager::CallHookChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
430 {
431  return GenericCallHook(HOOK_CHUNK_UNLOADING, [&](cPlugin * a_Plugin)
432  {
433  return a_Plugin->OnChunkUnloading(a_World, a_ChunkX, a_ChunkZ);
434  }
435  );
436 }
437 
438 
439 
440 
441 
443 {
444  return GenericCallHook(HOOK_COLLECTING_PICKUP, [&](cPlugin * a_Plugin)
445  {
446  return a_Plugin->OnCollectingPickup(a_Player, a_Pickup);
447  }
448  );
449 }
450 
451 
452 
453 
454 
456 {
457  return GenericCallHook(HOOK_CRAFTING_NO_RECIPE, [&](cPlugin * a_Plugin)
458  {
459  return a_Plugin->OnCraftingNoRecipe(a_Player, a_Grid, a_Recipe);
460  }
461  );
462 }
463 
464 
465 
466 
467 
468 bool cPluginManager::CallHookDisconnect(cClientHandle & a_Client, const AString & a_Reason)
469 {
470  return GenericCallHook(HOOK_DISCONNECT, [&](cPlugin * a_Plugin)
471  {
472  return a_Plugin->OnDisconnect(a_Client, a_Reason);
473  }
474  );
475 }
476 
477 
478 
479 
480 
481 bool cPluginManager::CallHookEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier)
482 {
483  return GenericCallHook(HOOK_ENTITY_ADD_EFFECT, [&](cPlugin * a_Plugin)
484  {
485  return a_Plugin->OnEntityAddEffect(a_Entity, a_EffectType, a_EffectDurationTicks, a_EffectIntensity, a_DistanceModifier);
486  }
487  );
488 }
489 
490 
491 
492 
493 
494 bool cPluginManager::CallHookEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition)
495 {
496  return GenericCallHook(HOOK_ENTITY_TELEPORT, [&](cPlugin * a_Plugin)
497  {
498  return a_Plugin->OnEntityTeleport(a_Entity, a_OldPosition, a_NewPosition);
499  }
500  );
501 }
502 
503 
504 
505 
506 
508 {
509  return GenericCallHook(HOOK_ENTITY_CHANGING_WORLD, [&](cPlugin * a_Plugin)
510  {
511  return a_Plugin->OnEntityChangingWorld(a_Entity, a_World);
512  }
513  );
514 }
515 
516 
517 
518 
519 
521 {
522  return GenericCallHook(HOOK_ENTITY_CHANGED_WORLD, [&](cPlugin * a_Plugin)
523  {
524  return a_Plugin->OnEntityChangedWorld(a_Entity, a_World);
525  }
526  );
527 }
528 
529 
530 
531 
532 
533 bool cPluginManager::CallHookExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, CommandResult & a_Result)
534 {
535  // Output the command being executed to log (for troubleshooting deadlocks-in-commands):
536  if (a_Player != nullptr)
537  {
538  auto world = a_Player->GetWorld();
539  AString worldName;
540  Int64 worldAge;
541  if (world != nullptr)
542  {
543  worldName = world->GetName();
544  worldAge = world->GetWorldAge().count();
545  }
546  else
547  {
548  worldName = "<no world>";
549  worldAge = 0;
550  }
551  LOG("Player %s is executing command \"%s\" in world \"%s\" at world age %lld.",
552  a_Player->GetName().c_str(),
553  a_EntireCommand.c_str(),
554  worldName.c_str(),
555  worldAge
556  );
557  }
558 
559  return GenericCallHook(HOOK_EXECUTE_COMMAND, [&](cPlugin * a_Plugin)
560  {
561  return a_Plugin->OnExecuteCommand(a_Player, a_Split, a_EntireCommand, a_Result);
562  }
563  );
564 }
565 
566 
567 
568 
569 
570 bool cPluginManager::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)
571 {
572  return GenericCallHook(HOOK_EXPLODED, [&](cPlugin * a_Plugin)
573  {
574  return a_Plugin->OnExploded(a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData);
575  }
576  );
577 }
578 
579 
580 
581 
582 
583 bool cPluginManager::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)
584 {
585  return GenericCallHook(HOOK_EXPLODING, [&](cPlugin * a_Plugin)
586  {
587  return a_Plugin->OnExploding(a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData);
588  }
589  );
590 }
591 
592 
593 
594 
595 
596 bool cPluginManager::CallHookHandshake(cClientHandle & a_ClientHandle, const AString & a_Username)
597 {
598  return GenericCallHook(HOOK_HANDSHAKE, [&](cPlugin * a_Plugin)
599  {
600  return a_Plugin->OnHandshake(a_ClientHandle, a_Username);
601  }
602  );
603 }
604 
605 
606 
607 
608 
609 bool cPluginManager::CallHookHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_DstSlotNum, cBlockEntityWithItems & a_SrcEntity, int a_SrcSlotNum)
610 {
611  return GenericCallHook(HOOK_HOPPER_PULLING_ITEM, [&](cPlugin * a_Plugin)
612  {
613  return a_Plugin->OnHopperPullingItem(a_World, a_Hopper, a_DstSlotNum, a_SrcEntity, a_SrcSlotNum);
614  }
615  );
616 }
617 
618 
619 
620 
621 
622 bool cPluginManager::CallHookHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems & a_DstEntity, int a_DstSlotNum)
623 {
624  return GenericCallHook(HOOK_HOPPER_PUSHING_ITEM, [&](cPlugin * a_Plugin)
625  {
626  return a_Plugin->OnHopperPushingItem(a_World, a_Hopper, a_SrcSlotNum, a_DstEntity, a_DstSlotNum);
627  }
628  );
629 }
630 
631 
632 
633 
634 
635 bool cPluginManager::CallHookDropSpense(cWorld & a_World, cDropSpenserEntity & a_DropSpenser, int a_SlotNum)
636 {
637  return GenericCallHook(HOOK_DROPSPENSE, [&](cPlugin * a_Plugin)
638  {
639  return a_Plugin->OnDropSpense(a_World, a_DropSpenser, a_SlotNum);
640  }
641  );
642 }
643 
644 
645 
646 
647 
648 bool cPluginManager::CallHookKilled(cEntity & a_Victim, TakeDamageInfo & a_TDI, AString & a_DeathMessage)
649 {
650  return GenericCallHook(HOOK_KILLED, [&](cPlugin * a_Plugin)
651  {
652  return a_Plugin->OnKilled(a_Victim, a_TDI, a_DeathMessage);
653  }
654  );
655 }
656 
657 
658 
659 
660 
661 bool cPluginManager::CallHookKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI)
662 {
663  return GenericCallHook(HOOK_KILLING, [&](cPlugin * a_Plugin)
664  {
665  return a_Plugin->OnKilling(a_Victim, a_Killer, a_TDI);
666  }
667  );
668 }
669 
670 
671 
672 
673 
674 bool cPluginManager::CallHookLogin(cClientHandle & a_Client, UInt32 a_ProtocolVersion, const AString & a_Username)
675 {
676  return GenericCallHook(HOOK_LOGIN, [&](cPlugin * a_Plugin)
677  {
678  return a_Plugin->OnLogin(a_Client, a_ProtocolVersion, a_Username);
679  }
680  );
681 }
682 
683 
684 
685 
686 
688 {
689  return GenericCallHook(HOOK_LOGIN_FORGE, [&](cPlugin * a_Plugin)
690  {
691  return a_Plugin->OnLoginForge(a_Client, a_Mods);
692  }
693  );
694 }
695 
696 
697 
698 
699 
700 bool cPluginManager::CallHookPlayerAnimation(cPlayer & a_Player, int a_Animation)
701 {
702  return GenericCallHook(HOOK_PLAYER_ANIMATION, [&](cPlugin * a_Plugin)
703  {
704  return a_Plugin->OnPlayerAnimation(a_Player, a_Animation);
705  }
706  );
707 }
708 
709 
710 
711 
712 
713 bool cPluginManager::CallHookPlayerBreakingBlock(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
714 {
715  return GenericCallHook(HOOK_PLAYER_BREAKING_BLOCK, [&](cPlugin * a_Plugin)
716  {
717  return a_Plugin->OnPlayerBreakingBlock(a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_BlockFace, a_BlockType, a_BlockMeta);
718  }
719  );
720 }
721 
722 
723 
724 
725 
726 bool cPluginManager::CallHookPlayerBrokenBlock(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
727 {
728  return GenericCallHook(HOOK_PLAYER_BROKEN_BLOCK, [&](cPlugin * a_Plugin)
729  {
730  return a_Plugin->OnPlayerBrokenBlock(a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_BlockFace, a_BlockType, a_BlockMeta);
731  }
732  );
733 }
734 
735 
736 
737 
738 
740 {
741  return GenericCallHook(HOOK_PLAYER_DESTROYED, [&](cPlugin * a_Plugin)
742  {
743  return a_Plugin->OnPlayerDestroyed(a_Player);
744  }
745  );
746 }
747 
748 
749 
750 
751 
753 {
754  return GenericCallHook(HOOK_PLAYER_EATING, [&](cPlugin * a_Plugin)
755  {
756  return a_Plugin->OnPlayerEating(a_Player);
757  }
758  );
759 }
760 
761 
762 
763 
764 
765 bool cPluginManager::CallHookPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel)
766 {
768  {
769  return a_Plugin->OnPlayerFoodLevelChange(a_Player, a_NewFoodLevel);
770  }
771  );
772 }
773 
774 
775 
776 
777 
778 bool cPluginManager::CallHookPlayerFished(cPlayer & a_Player, const cItems & a_Reward, const int ExperienceAmount)
779 {
780  return GenericCallHook(HOOK_PLAYER_FISHED, [&](cPlugin * a_Plugin)
781  {
782  return a_Plugin->OnPlayerFished(a_Player, a_Reward, ExperienceAmount);
783  }
784  );
785 }
786 
787 
788 
789 
790 
791 bool cPluginManager::CallHookPlayerFishing(cPlayer & a_Player, cItems & a_Reward, int & ExperienceAmount)
792 {
793  return GenericCallHook(HOOK_PLAYER_FISHING, [&](cPlugin * a_Plugin)
794  {
795  return a_Plugin->OnPlayerFishing(a_Player, a_Reward, ExperienceAmount);
796  }
797  );
798 }
799 
800 
801 
802 
803 
805 {
806  return GenericCallHook(HOOK_PLAYER_JOINED, [&](cPlugin * a_Plugin)
807  {
808  return a_Plugin->OnPlayerJoined(a_Player);
809  }
810  );
811 }
812 
813 
814 
815 
816 
817 bool cPluginManager::CallHookPlayerLeftClick(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, char a_Status)
818 {
819  return GenericCallHook(HOOK_PLAYER_LEFT_CLICK, [&](cPlugin * a_Plugin)
820  {
821  return a_Plugin->OnPlayerLeftClick(a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_BlockFace, a_Status);
822  }
823  );
824 }
825 
826 
827 
828 
829 
830 bool cPluginManager::CallHookPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition, bool a_PreviousIsOnGround)
831 {
832  return GenericCallHook(HOOK_PLAYER_MOVING, [&](cPlugin * a_Plugin)
833  {
834  return a_Plugin->OnPlayerMoving(a_Player, a_OldPosition, a_NewPosition, a_PreviousIsOnGround);
835  }
836  );
837 }
838 
839 
840 
841 
842 
844 {
845  return GenericCallHook(HOOK_PLAYER_OPENING_WINDOW, [&](cPlugin * a_Plugin)
846  {
847  return a_Plugin->OnPlayerOpeningWindow(a_Player, a_Window);
848  }
849  );
850 }
851 
852 
853 
854 
855 
856 bool cPluginManager::CallHookPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
857 {
858  return GenericCallHook(HOOK_PLAYER_PLACED_BLOCK, [&](cPlugin * a_Plugin)
859  {
860  return a_Plugin->OnPlayerPlacedBlock(a_Player, a_BlockChange);
861  }
862  );
863 }
864 
865 
866 
867 
868 
869 bool cPluginManager::CallHookPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
870 {
871  return GenericCallHook(HOOK_PLAYER_PLACING_BLOCK, [&](cPlugin * a_Plugin)
872  {
873  return a_Plugin->OnPlayerPlacingBlock(a_Player, a_BlockChange);
874  }
875  );
876 }
877 
878 
879 
880 
881 
883 {
884  return GenericCallHook(HOOK_PLAYER_CROUCHED, [&](cPlugin * a_Plugin)
885  {
886  return a_Plugin->OnPlayerCrouched(a_Player);
887  }
888  );
889 }
890 
891 
892 
893 
894 
895 bool cPluginManager::CallHookPlayerRightClick(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos)
896 {
897  return GenericCallHook(HOOK_PLAYER_RIGHT_CLICK, [&](cPlugin * a_Plugin)
898  {
899  return a_Plugin->OnPlayerRightClick(a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_BlockFace, a_CursorPos.x, a_CursorPos.y, a_CursorPos.z);
900  }
901  );
902 }
903 
904 
905 
906 
907 
909 {
911  {
912  return a_Plugin->OnPlayerRightClickingEntity(a_Player, a_Entity);
913  }
914  );
915 }
916 
917 
918 
919 
920 
922 {
923  return GenericCallHook(HOOK_PLAYER_SHOOTING, [&](cPlugin * a_Plugin)
924  {
925  return a_Plugin->OnPlayerShooting(a_Player);
926  }
927  );
928 }
929 
930 
931 
932 
933 
935 {
936  return GenericCallHook(HOOK_PLAYER_SPAWNED, [&](cPlugin * a_Plugin)
937  {
938  return a_Plugin->OnPlayerSpawned(a_Player);
939  }
940  );
941 }
942 
943 
944 
945 
946 
948 {
949  return GenericCallHook(HOOK_PLAYER_TOSSING_ITEM, [&](cPlugin * a_Plugin)
950  {
951  return a_Plugin->OnPlayerTossingItem(a_Player);
952  }
953  );
954 }
955 
956 
957 
958 
959 
960 bool cPluginManager::CallHookPlayerUsedBlock(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
961 {
962  return GenericCallHook(HOOK_PLAYER_USED_BLOCK, [&](cPlugin * a_Plugin)
963  {
964  return a_Plugin->OnPlayerUsedBlock(a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_BlockFace, a_CursorPos.x, a_CursorPos.y, a_CursorPos.z, a_BlockType, a_BlockMeta);
965  }
966  );
967 }
968 
969 
970 
971 
972 
973 bool cPluginManager::CallHookPlayerUsedItem(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos)
974 {
975  return GenericCallHook(HOOK_PLAYER_USED_ITEM, [&](cPlugin * a_Plugin)
976  {
977  return a_Plugin->OnPlayerUsedItem(a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_BlockFace, a_CursorPos.x, a_CursorPos.y, a_CursorPos.z);
978  }
979  );
980 }
981 
982 
983 
984 
985 
986 bool cPluginManager::CallHookPlayerUsingBlock(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
987 {
988  return GenericCallHook(HOOK_PLAYER_USING_BLOCK, [&](cPlugin * a_Plugin)
989  {
990  return a_Plugin->OnPlayerUsingBlock(a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_BlockFace, a_CursorPos.x, a_CursorPos.y, a_CursorPos.z, a_BlockType, a_BlockMeta);
991  }
992  );
993 }
994 
995 
996 
997 
998 
999 bool cPluginManager::CallHookPlayerUsingItem(cPlayer & a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos)
1000 {
1001  return GenericCallHook(HOOK_PLAYER_USING_ITEM, [&](cPlugin * a_Plugin)
1002  {
1003  return a_Plugin->OnPlayerUsingItem(a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_BlockFace, a_CursorPos.x, a_CursorPos.y, a_CursorPos.z);
1004  }
1005  );
1006 }
1007 
1008 
1009 
1010 
1011 
1012 bool cPluginManager::CallHookPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const ContiguousByteBufferView a_Message)
1013 {
1014  return GenericCallHook(HOOK_PLUGIN_MESSAGE, [&](cPlugin * a_Plugin)
1015  {
1016  return a_Plugin->OnPluginMessage(a_Client, a_Channel, a_Message);
1017  }
1018  );
1019 }
1020 
1021 
1022 
1023 
1024 
1026 {
1027  auto Plugins = m_Hooks.find(HOOK_PLUGINS_LOADED);
1028  if (Plugins == m_Hooks.end())
1029  {
1030  return false;
1031  }
1032 
1033  bool res = false;
1034  for (auto * Plugin : Plugins->second)
1035  {
1036  if (!Plugin->OnPluginsLoaded())
1037  {
1038  res = true;
1039  }
1040  }
1041  return res;
1042 }
1043 
1044 
1045 
1046 
1047 
1049 {
1050  return GenericCallHook(HOOK_POST_CRAFTING, [&](cPlugin * a_Plugin)
1051  {
1052  return a_Plugin->OnPostCrafting(a_Player, a_Grid, a_Recipe);
1053  }
1054  );
1055 }
1056 
1057 
1058 
1059 
1060 
1062 {
1063  return GenericCallHook(HOOK_PRE_CRAFTING, [&](cPlugin * a_Plugin)
1064  {
1065  return a_Plugin->OnPreCrafting(a_Player, a_Grid, a_Recipe);
1066  }
1067  );
1068 }
1069 
1070 
1071 
1072 
1073 
1074 bool cPluginManager::CallHookProjectileHitBlock(cProjectileEntity & a_Projectile, Vector3i a_BlockPos, eBlockFace a_Face, const Vector3d & a_BlockHitPos)
1075 {
1076  return GenericCallHook(HOOK_PROJECTILE_HIT_BLOCK, [&](cPlugin * a_Plugin)
1077  {
1078  return a_Plugin->OnProjectileHitBlock(a_Projectile, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Face, a_BlockHitPos);
1079  }
1080  );
1081 }
1082 
1083 
1084 
1085 
1086 
1088 {
1089  return GenericCallHook(HOOK_PROJECTILE_HIT_ENTITY, [&](cPlugin * a_Plugin)
1090  {
1091  return a_Plugin->OnProjectileHitEntity(a_Projectile, a_HitEntity);
1092  }
1093  );
1094 }
1095 
1096 
1097 
1098 
1099 
1100 bool cPluginManager::CallHookServerPing(cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon)
1101 {
1102  return GenericCallHook(HOOK_SERVER_PING, [&](cPlugin * a_Plugin)
1103  {
1104  return a_Plugin->OnServerPing(a_ClientHandle, a_ServerDescription, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon);
1105  }
1106  );
1107 }
1108 
1109 
1110 
1111 
1112 
1114 {
1115  return GenericCallHook(HOOK_SPAWNED_ENTITY, [&](cPlugin * a_Plugin)
1116  {
1117  return a_Plugin->OnSpawnedEntity(a_World, a_Entity);
1118  }
1119  );
1120 }
1121 
1122 
1123 
1124 
1125 
1127 {
1128  return GenericCallHook(HOOK_SPAWNED_MONSTER, [&](cPlugin * a_Plugin)
1129  {
1130  return a_Plugin->OnSpawnedMonster(a_World, a_Monster);
1131  }
1132  );
1133 }
1134 
1135 
1136 
1137 
1138 
1140 {
1141  return GenericCallHook(HOOK_SPAWNING_ENTITY, [&](cPlugin * a_Plugin)
1142  {
1143  return a_Plugin->OnSpawningEntity(a_World, a_Entity);
1144  }
1145  );
1146 }
1147 
1148 
1149 
1150 
1151 
1153 {
1154  return GenericCallHook(HOOK_SPAWNING_MONSTER, [&](cPlugin * a_Plugin)
1155  {
1156  return a_Plugin->OnSpawningMonster(a_World, a_Monster);
1157  }
1158  );
1159 }
1160 
1161 
1162 
1163 
1164 
1166 {
1167  return GenericCallHook(HOOK_TAKE_DAMAGE, [&](cPlugin * a_Plugin)
1168  {
1169  return a_Plugin->OnTakeDamage(a_Receiver, a_TDI);
1170  }
1171  );
1172 }
1173 
1174 
1175 
1176 
1177 
1178 bool cPluginManager::CallHookUpdatingSign(cWorld & a_World, Vector3i a_BlockPos, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player)
1179 {
1180  return GenericCallHook(HOOK_UPDATING_SIGN, [&](cPlugin * a_Plugin)
1181  {
1182  return a_Plugin->OnUpdatingSign(a_World, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Line1, a_Line2, a_Line3, a_Line4, a_Player);
1183  }
1184  );
1185 }
1186 
1187 
1188 
1189 
1190 
1191 bool cPluginManager::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)
1192 {
1193  return GenericCallHook(HOOK_UPDATED_SIGN, [&](cPlugin * a_Plugin)
1194  {
1195  return a_Plugin->OnUpdatedSign(a_World, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Line1, a_Line2, a_Line3, a_Line4, a_Player);
1196  }
1197  );
1198 }
1199 
1200 
1201 
1202 
1203 
1205 {
1206  return GenericCallHook(HOOK_WEATHER_CHANGED, [&](cPlugin * a_Plugin)
1207  {
1208  return a_Plugin->OnWeatherChanged(a_World);
1209  }
1210  );
1211 }
1212 
1213 
1214 
1215 
1216 
1218 {
1219  return GenericCallHook(HOOK_WEATHER_CHANGING, [&](cPlugin * a_Plugin)
1220  {
1221  return a_Plugin->OnWeatherChanging(a_World, a_NewWeather);
1222  }
1223  );
1224 }
1225 
1226 
1227 
1228 
1229 
1231 {
1232  return GenericCallHook(HOOK_WORLD_STARTED, [&](cPlugin * a_Plugin)
1233  {
1234  return a_Plugin->OnWorldStarted(a_World);
1235  }
1236  );
1237 }
1238 
1239 
1240 
1241 
1242 
1243 bool cPluginManager::CallHookWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
1244 {
1245  return GenericCallHook(HOOK_WORLD_TICK, [&](cPlugin * a_Plugin)
1246  {
1247  return a_Plugin->OnWorldTick(a_World, a_Dt, a_LastTickDurationMSec);
1248  }
1249  );
1250 }
1251 
1252 
1253 
1254 
1255 
1256 cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer & a_Player, const AString & a_Command, bool a_ShouldCheckPermissions)
1257 {
1258  AStringVector Split(StringSplit(a_Command, " "));
1259  if (Split.empty())
1260  {
1261  return crUnknownCommand;
1262  }
1263 
1264  CommandMap::iterator cmd = m_Commands.find(Split[0]);
1265  if (cmd == m_Commands.end())
1266  {
1267  // Command not found
1268  // If it started with a slash, ask the plugins if they still want to handle it:
1269  if (!a_Command.empty() && (a_Command[0] == '/'))
1270  {
1272  CallHookExecuteCommand(&a_Player, Split, a_Command, Result);
1273  return Result;
1274  }
1275  return crUnknownCommand;
1276  }
1277 
1278  // Ask plugins first if a command is okay to execute the command:
1279  CommandResult Result = crBlocked;
1280  if (CallHookExecuteCommand(&a_Player, Split, a_Command, Result))
1281  {
1282  if (Result == crBlocked)
1283  {
1284  LOGINFO("Player %s tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player.GetName().c_str(), Split[0].c_str());
1285  }
1286  return Result;
1287  }
1288 
1289  if (
1290  a_ShouldCheckPermissions &&
1291  !cmd->second.m_Permission.empty() &&
1292  !a_Player.HasPermission(cmd->second.m_Permission)
1293  )
1294  {
1295  LOGINFO("Player %s tried to execute forbidden command: \"%s\"", a_Player.GetName().c_str(), Split[0].c_str());
1296  return crNoPermission;
1297  }
1298 
1299  ASSERT(cmd->second.m_Handler != nullptr);
1300 
1301  if (!cmd->second.m_Handler->ExecuteCommand(Split, &a_Player, a_Command, nullptr))
1302  {
1303  return crError;
1304  }
1305 
1306  return crExecuted;
1307 }
1308 
1309 
1310 
1311 
1312 
1314 {
1315  // Remove all bindings:
1316  m_Hooks.clear();
1317  m_Commands.clear();
1318  m_ConsoleCommands.clear();
1319 
1320  // Re-bind built-in console commands:
1322 
1323  // Unload all loaded plugins:
1324  for (auto & plugin: m_Plugins)
1325  {
1326  if (plugin->IsLoaded())
1327  {
1328  plugin->Unload();
1329  }
1330  }
1331 }
1332 
1333 
1334 
1335 
1336 
1337 void cPluginManager::UnloadPlugin(const AString & a_PluginFolder)
1338 {
1340  m_PluginsNeedAction.emplace_back(PluginAction::Unload, a_PluginFolder);
1341 }
1342 
1343 
1344 
1345 
1346 
1347 void cPluginManager::ReloadPlugin(const AString & a_PluginFolder)
1348 {
1350  m_PluginsNeedAction.emplace_back(PluginAction::Reload, a_PluginFolder);
1351 }
1352 
1353 
1354 
1355 
1356 
1357 bool cPluginManager::LoadPlugin(const AString & a_FolderName)
1358 {
1359  for (auto & plugin: m_Plugins)
1360  {
1361  if (plugin->GetFolderName() == a_FolderName)
1362  {
1363  if (!plugin->IsLoaded())
1364  {
1365  return plugin->Load();
1366  }
1367  return true;
1368  }
1369  } // for plugin - m_Plugins[]
1370 
1371  // Plugin not found
1372  LOG("Cannot load plugin, folder \"%s\" not found.", a_FolderName.c_str());
1373  return false;
1374 }
1375 
1376 
1377 
1378 
1379 
1381 {
1382  for (auto & Hook : m_Hooks)
1383  {
1384  Hook.second.remove(a_Plugin);
1385  }
1386 }
1387 
1388 
1389 
1390 
1391 
1393 {
1394  for (CommandMap::iterator itr = m_Commands.begin(); itr != m_Commands.end();)
1395  {
1396  if (itr->second.m_Plugin == a_Plugin)
1397  {
1398  CommandMap::iterator EraseMe = itr; // Stupid GCC doesn't have a std::map::erase() that would return the next iterator
1399  ++itr;
1400  m_Commands.erase(EraseMe);
1401  }
1402  else
1403  {
1404  ++itr;
1405  }
1406  } // for itr - m_Commands[]
1407 }
1408 
1409 
1410 
1411 
1412 
1413 bool cPluginManager::IsPluginLoaded(const AString & a_PluginName)
1414 {
1415  for (auto & plugin: m_Plugins)
1416  {
1417  if (plugin->GetName() == a_PluginName)
1418  {
1419  return true;
1420  }
1421  }
1422  return false;
1423 }
1424 
1425 
1426 
1427 
1428 
1430  const AString & a_Command,
1431  cPlugin * a_Plugin,
1432  cCommandHandlerPtr a_Handler,
1433  const AString & a_Permission,
1434  const AString & a_HelpString
1435 )
1436 {
1437  CommandMap::iterator cmd = m_Commands.find(a_Command);
1438  if (cmd != m_Commands.end())
1439  {
1440  LOGWARNING("Command \"%s\" is already bound to plugin \"%s\".", a_Command.c_str(), cmd->second.m_Plugin->GetName().c_str());
1441  return false;
1442  }
1443 
1444  auto & reg = m_Commands[a_Command];
1445  reg.m_Plugin = a_Plugin;
1446  reg.m_Handler = std::move(a_Handler);
1447  reg.m_Permission = a_Permission;
1448  reg.m_HelpString = a_HelpString;
1449  return true;
1450 }
1451 
1452 
1453 
1454 
1455 
1457 {
1458  for (auto & itr : m_Commands)
1459  {
1460  if (a_Callback.Command(itr.first, itr.second.m_Plugin, itr.second.m_Permission, itr.second.m_HelpString))
1461  {
1462  return false;
1463  }
1464  } // for itr - m_Commands[]
1465  return true;
1466 }
1467 
1468 
1469 
1470 
1471 
1473 {
1474  return (m_Commands.find(a_Command) != m_Commands.end());
1475 }
1476 
1477 
1478 
1479 
1480 
1482 {
1483  CommandMap::iterator cmd = m_Commands.find(a_Command);
1484  return (cmd == m_Commands.end()) ? "" : cmd->second.m_Permission;
1485 }
1486 
1487 
1488 
1489 
1490 
1492 {
1493  return HandleCommand(a_Player, a_Command, true);
1494 }
1495 
1496 
1497 
1498 
1499 
1501 {
1502  return HandleCommand(a_Player, a_Command, false);
1503 }
1504 
1505 
1506 
1507 
1508 
1510 {
1511  for (CommandMap::iterator itr = m_ConsoleCommands.begin(); itr != m_ConsoleCommands.end();)
1512  {
1513  if (itr->second.m_Plugin == a_Plugin)
1514  {
1515  CommandMap::iterator EraseMe = itr; // Stupid GCC doesn't have a std::map::erase() that would return the next iterator
1516  ++itr;
1517  m_ConsoleCommands.erase(EraseMe);
1518  }
1519  else
1520  {
1521  ++itr;
1522  }
1523  } // for itr - m_Commands[]
1524 }
1525 
1526 
1527 
1528 
1529 
1531  const AString & a_Command,
1532  cPlugin * a_Plugin,
1533  cCommandHandlerPtr a_Handler,
1534  const AString & a_HelpString
1535 )
1536 {
1537  CommandMap::iterator cmd = m_ConsoleCommands.find(a_Command);
1538  if (cmd != m_ConsoleCommands.end())
1539  {
1540  if (cmd->second.m_Plugin == nullptr)
1541  {
1542  LOGWARNING("Console command \"%s\" is already bound internally by Cuberite, cannot bind in plugin \"%s\".", a_Command.c_str(), a_Plugin->GetName().c_str());
1543  }
1544  else
1545  {
1546  LOGWARNING("Console command \"%s\" is already bound to plugin \"%s\", cannot bind in plugin \"%s\".", a_Command.c_str(), cmd->second.m_Plugin->GetName().c_str(), a_Plugin->GetName().c_str());
1547  }
1548  return false;
1549  }
1550 
1551  auto & reg = m_ConsoleCommands[a_Command];
1552  reg.m_Plugin = a_Plugin;
1553  reg.m_Handler = std::move(a_Handler);
1554  reg.m_Permission = "";
1555  reg.m_HelpString = a_HelpString;
1556  return true;
1557 }
1558 
1559 
1560 
1561 
1562 
1564 {
1565  for (auto & itr : m_ConsoleCommands)
1566  {
1567  if (a_Callback.Command(itr.first, itr.second.m_Plugin, "", itr.second.m_HelpString))
1568  {
1569  return false;
1570  }
1571  } // for itr - m_Commands[]
1572  return true;
1573 }
1574 
1575 
1576 
1577 
1578 
1580 {
1581  return (m_ConsoleCommands.find(a_Command) != m_ConsoleCommands.end());
1582 }
1583 
1584 
1585 
1586 
1587 
1588 bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_Command)
1589 {
1590  if (a_Split.empty())
1591  {
1592  return false;
1593  }
1594 
1595  CommandMap::iterator cmd = m_ConsoleCommands.find(a_Split[0]);
1596  if (cmd == m_ConsoleCommands.end())
1597  {
1598  // Command not found
1599  // Still notify the plugins (so that plugins such as Aliases can intercept unknown commands).
1600  CommandResult res = crBlocked;
1601  CallHookExecuteCommand(nullptr, a_Split, a_Command, res);
1602  return (res == crExecuted);
1603  }
1604 
1605  if (cmd->second.m_Plugin == nullptr)
1606  {
1607  // This is a built-in command
1608  return false;
1609  }
1610 
1611  // Ask plugins first if a command is okay to execute the console command:
1612  CommandResult res = crBlocked;
1613  if (CallHookExecuteCommand(nullptr, a_Split, a_Command, res))
1614  {
1615  return (res == crExecuted);
1616  }
1617 
1618  return cmd->second.m_Handler->ExecuteCommand(a_Split, nullptr, a_Command, &a_Output);
1619 }
1620 
1621 
1622 
1623 
1624 
1625 void cPluginManager::TabCompleteCommand(const AString & a_Text, AStringVector & a_Results, cPlayer * a_Player)
1626 {
1627  for (auto & Command : m_Commands)
1628  {
1629  if (NoCaseCompare(Command.first.substr(0, a_Text.length()), a_Text) != 0)
1630  {
1631  // Command name doesn't match
1632  continue;
1633  }
1634  if ((a_Player != nullptr) && !a_Player->HasPermission(Command.second.m_Permission))
1635  {
1636  // Player doesn't have permission for the command
1637  continue;
1638  }
1639 
1640  /* Client expects to only get back the last part of a space separated command.
1641  Find the position of the beginning of the last part:
1642  Position of last space + 1 for space separated commands
1643  string::npos + 1 = 0 for commands that are not separated
1644 
1645  Then skip all commands that have too many subcommands.
1646  When the client asks for suggestions for "/time s"
1647  the server must skip all commands that consist of more than 2 words just as
1648  "/time set day". Or in other words, the position of the last space (separator)
1649  in the strings must be equal or string::npos for both. */
1650  size_t LastSpaceInText = a_Text.find_last_of(' ') + 1;
1651  size_t LastSpaceInSuggestion = Command.first.find_last_of(' ') + 1;
1652 
1653  if (LastSpaceInText != LastSpaceInSuggestion)
1654  {
1655  // Suggestion has more subcommands than a_Text
1656  continue;
1657  }
1658 
1659  a_Results.push_back(Command.first.substr(LastSpaceInSuggestion));
1660  }
1661 }
1662 
1663 
1664 
1665 
1666 
1668 {
1669  return ((a_HookType >= 0) && (a_HookType <= HOOK_MAX));
1670 }
1671 
1672 
1673 
1674 
1675 
1676 bool cPluginManager::DoWithPlugin(const AString & a_PluginName, cPluginCallback a_Callback)
1677 {
1678  // TODO: Implement locking for plugins
1679  for (auto & plugin: m_Plugins)
1680  {
1681  if (plugin->GetName() == a_PluginName)
1682  {
1683  return a_Callback(*plugin);
1684  }
1685  }
1686  return false;
1687 }
1688 
1689 
1690 
1691 
1692 
1694 {
1695  // TODO: Implement locking for plugins
1696  for (auto & plugin: m_Plugins)
1697  {
1698  if (a_Callback(*plugin))
1699  {
1700  return false;
1701  }
1702  }
1703  return true;
1704 }
1705 
1706 
1707 
1708 
1709 
1711 {
1712  // TODO: Implement locking for plugins
1713  for (auto & plugin: m_Plugins)
1714  {
1715  if (plugin->GetName() == a_PluginName)
1716  {
1717  return plugin->GetFolderName();
1718  }
1719  }
1720  return AString();
1721 }
1722 
1723 
1724 
1725 
1726 
1727 void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook)
1728 {
1729  if (a_Plugin == nullptr)
1730  {
1731  LOGWARN("Called cPluginManager::AddHook() with a_Plugin == nullptr");
1732  return;
1733  }
1734  PluginList & Plugins = m_Hooks[a_Hook];
1735  if (std::find(Plugins.cbegin(), Plugins.cend(), a_Plugin) == Plugins.cend())
1736  {
1737  Plugins.push_back(a_Plugin);
1738  }
1739 }
1740 
1741 
1742 
1743 
1744 
1746 {
1747  return m_Plugins.size();
1748 }
1749 
1750 
1751 
1752 
1753 
1755 {
1756  size_t res = 0;
1757  for (auto & plugin: m_Plugins)
1758  {
1759  if (plugin->IsLoaded())
1760  {
1761  res += 1;
1762  }
1763  }
1764  return res;
1765 }
1766 
1767 
1768 
1769 
1770 
1772 {
1773  // Check if the Plugins section exists.
1774  if (!a_Settings.KeyExists("Plugins"))
1775  {
1776  InsertDefaultPlugins(a_Settings);
1777  }
1778 
1779  AStringVector res;
1780 
1781  // Get the old format plugin list, and migrate it.
1782  // Upgrade path added on 2020-03-27
1783  auto OldValues = a_Settings.GetValues("Plugins");
1784  for (const auto & NameValue : OldValues)
1785  {
1786  AString ValueName = NameValue.first;
1787  if (ValueName.compare("Plugin") == 0)
1788  {
1789  AString PluginFile = NameValue.second;
1790  if (
1791  !PluginFile.empty() &&
1792  (PluginFile != "0") &&
1793  (PluginFile != "1")
1794  )
1795  {
1796  a_Settings.DeleteValue("Plugins", ValueName);
1797  a_Settings.SetValue("Plugins", PluginFile, "1");
1798  }
1799  }
1800  } // for i - ini values
1801 
1802  // Get the list of plugins to load:
1803  auto Values = a_Settings.GetValues("Plugins");
1804  for (const auto & NameValue : Values)
1805  {
1806  AString Enabled = NameValue.second;
1807  if (Enabled == "1")
1808  {
1809  res.push_back(NameValue.first);
1810  }
1811  } // for i - ini values
1812 
1813  return res;
1814 }
1815 
1816 
1817 
1818 
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
eWeather
Definition: Defines.h:160
eExplosionSource
The source of an explosion.
Definition: Defines.h:309
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc.
Definition: Defines.h:38
eSpreadSource
Definition: Defines.h:339
unsigned int UInt32
Definition: Globals.h:157
signed long long Int64
Definition: Globals.h:151
std::basic_string_view< std::byte > ContiguousByteBufferView
Definition: Globals.h:376
#define ASSERT(x)
Definition: Globals.h:276
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
void LOG(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:55
#define LOGWARN
Definition: LoggerSimple.h:88
void LOGINFO(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:61
AStringVector StringSplit(const AString &str, const AString &delim)
Split the string at any of the listed delimiters.
Definition: StringUtils.cpp:55
int NoCaseCompare(const AString &s1, const AString &s2)
Case-insensitive string comparison.
std::vector< AString > AStringVector
Definition: StringUtils.h:12
std::string AString
Definition: StringUtils.h:11
std::map< AString, AString > AStringMap
A string dictionary, used for key-value pairs.
Definition: StringUtils.h:16
bool Enabled(const BlockState Block)
Definition: Plugin.h:20
virtual bool OnPostCrafting(cPlayer &a_Player, cCraftingGrid &a_Grid, cCraftingRecipe &a_Recipe)=0
virtual bool OnSpawningMonster(cWorld &a_World, cMonster &a_Monster)=0
virtual bool OnEntityAddEffect(cEntity &a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier)=0
virtual bool OnPlayerBreakingBlock(cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)=0
virtual bool OnPlayerPlacedBlock(cPlayer &a_Player, const sSetBlock &a_BlockChange)=0
virtual bool OnPlayerEating(cPlayer &a_Player)=0
virtual bool OnPlayerFishing(cPlayer &a_Player, cItems &a_Reward, int &ExperienceAmount)=0
virtual bool OnWorldStarted(cWorld &a_World)=0
virtual bool OnPlayerFished(cPlayer &a_Player, const cItems &a_Reward, const int ExperienceAmount)=0
virtual bool OnEntityTeleport(cEntity &a_Entity, const Vector3d &a_OldPosition, const Vector3d &a_NewPosition)=0
virtual bool OnPlayerBrokenBlock(cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)=0
virtual bool OnChunkUnloading(cWorld &a_World, int a_ChunkX, int a_ChunkZ)=0
virtual bool OnChunkGenerating(cWorld &a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc *a_ChunkDesc)=0
virtual bool OnEntityChangingWorld(cEntity &a_Entity, cWorld &a_World)=0
virtual bool OnPlayerUsingItem(cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)=0
virtual bool OnBrewingCompleting(cWorld &a_World, cBrewingstandEntity &a_BrewingstandEntity)=0
virtual bool OnServerPing(cClientHandle &a_ClientHandle, AString &a_ServerDescription, int &a_OnlinePlayersCount, int &a_MaxPlayersCount, AString &a_Favicon)=0
virtual bool OnProjectileHitBlock(cProjectileEntity &a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d &a_BlockHitPos)=0
virtual bool OnPlayerUsedItem(cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)=0
virtual bool OnPlayerCrouched(cPlayer &a_Player)=0
virtual bool OnUpdatedSign(cWorld &a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString &a_Line1, const AString &a_Line2, const AString &a_Line3, const AString &a_Line4, cPlayer *a_Player)=0
virtual bool OnExploding(cWorld &a_World, double &a_ExplosionSize, bool &a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void *a_SourceData)=0
const AString & GetName(void) const
Definition: Plugin.h:118
virtual bool OnCollectingPickup(cPlayer &a_Player, cPickup &a_Pickup)=0
virtual bool OnEntityChangedWorld(cEntity &a_Entity, cWorld &a_World)=0
virtual bool OnPlayerSpawned(cPlayer &a_Player)=0
virtual bool OnSpawningEntity(cWorld &a_World, cEntity &a_Entity)=0
virtual bool OnSpawnedEntity(cWorld &a_World, cEntity &a_Entity)=0
virtual bool OnPlayerOpeningWindow(cPlayer &a_Player, cWindow &a_Window)=0
virtual bool OnHopperPullingItem(cWorld &a_World, cHopperEntity &a_Hopper, int a_DstSlotNum, cBlockEntityWithItems &a_SrcEntity, int a_SrcSlotNum)=0
virtual bool OnExecuteCommand(cPlayer *a_Player, const AStringVector &a_Split, const AString &a_EntireCommand, cPluginManager::CommandResult &a_Result)=0
virtual bool OnWorldTick(cWorld &a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)=0
virtual bool OnPluginMessage(cClientHandle &a_Client, const AString &a_Channel, ContiguousByteBufferView a_Message)=0
virtual bool OnChunkGenerated(cWorld &a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc *a_ChunkDesc)=0
virtual bool OnPlayerAnimation(cPlayer &a_Player, int a_Animation)=0
virtual bool OnBlockSpread(cWorld &a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)=0
Calls the specified hook with the params given.
virtual bool OnPlayerRightClickingEntity(cPlayer &a_Player, cEntity &a_Entity)=0
virtual bool OnCraftingNoRecipe(cPlayer &a_Player, cCraftingGrid &a_Grid, cCraftingRecipe &a_Recipe)=0
virtual bool OnTakeDamage(cEntity &a_Receiver, TakeDamageInfo &a_TakeDamageInfo)=0
virtual bool OnPlayerPlacingBlock(cPlayer &a_Player, const sSetBlock &a_BlockChange)=0
virtual bool OnPlayerUsingBlock(cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)=0
virtual bool OnKilled(cEntity &a_Victim, TakeDamageInfo &a_TDI, AString &a_DeathMessage)=0
virtual bool OnBrewingCompleted(cWorld &a_World, cBrewingstandEntity &a_BrewingstandEntity)=0
virtual bool OnDropSpense(cWorld &a_World, cDropSpenserEntity &a_DropSpenser, int a_SlotNum)=0
virtual bool OnPlayerMoving(cPlayer &a_Player, const Vector3d &a_OldPosition, const Vector3d &a_NewPosition, bool a_PreviousIsOnGround)=0
virtual bool OnKilling(cEntity &a_Victim, cEntity *a_Killer, TakeDamageInfo &a_TDI)=0
virtual bool OnPlayerRightClick(cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)=0
virtual bool OnLogin(cClientHandle &a_Client, UInt32 a_ProtocolVersion, const AString &a_Username)=0
virtual bool OnPlayerDestroyed(cPlayer &a_Player)=0
virtual bool OnPlayerLeftClick(cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status)=0
virtual bool OnHandshake(cClientHandle &a_Client, const AString &a_Username)=0
virtual bool OnProjectileHitEntity(cProjectileEntity &a_Projectile, cEntity &a_HitEntity)=0
virtual bool OnPlayerTossingItem(cPlayer &a_Player)=0
virtual bool OnLoginForge(cClientHandle &a_Client, const AStringMap &a_Mods)=0
virtual bool OnExploded(cWorld &a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void *a_SourceData)=0
virtual bool OnWeatherChanged(cWorld &a_World)=0
virtual bool OnPlayerJoined(cPlayer &a_Player)=0
virtual bool OnChat(cPlayer &a_Player, AString &a_Message)=0
virtual bool OnDisconnect(cClientHandle &a_Client, const AString &a_Reason)=0
virtual bool OnWeatherChanging(cWorld &a_World, eWeather &a_NewWeather)=0
virtual bool OnPlayerUsedBlock(cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)=0
virtual bool OnPreCrafting(cPlayer &a_Player, cCraftingGrid &a_Grid, cCraftingRecipe &a_Recipe)=0
virtual bool OnUpdatingSign(cWorld &a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString &a_Line1, AString &a_Line2, AString &a_Line3, AString &a_Line4, cPlayer *a_Player)=0
virtual bool OnHopperPushingItem(cWorld &a_World, cHopperEntity &a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems &a_DstEntity, int a_DstSlotNum)=0
virtual bool OnChunkAvailable(cWorld &a_World, int a_ChunkX, int a_ChunkZ)=0
virtual bool OnSpawnedMonster(cWorld &a_World, cMonster &a_Monster)=0
virtual bool OnPlayerShooting(cPlayer &a_Player)=0
virtual bool OnChunkUnloaded(cWorld &a_World, int a_ChunkX, int a_ChunkZ)=0
virtual bool OnBlockToPickups(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)=0
virtual bool OnPlayerFoodLevelChange(cPlayer &a_Player, int a_NewFoodLevel)=0
void InsertDefaultPlugins(cSettingsRepositoryInterface &a_Settings)
Handles writing default plugins if 'Plugins' key not found using a settings repo expected to be intia...
cPluginManager(cDeadlockDetect &a_DeadlockDetect)
bool CallHookPlayerAnimation(cPlayer &a_Player, int a_Animation)
bool CallHookChunkGenerated(cWorld &a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc *a_ChunkDesc)
AString GetCommandPermission(const AString &a_Command)
Returns the permission needed for the specified command; empty string if command not found.
bool CallHookEntityAddEffect(cEntity &a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier)
CommandMap m_Commands
bool CallHookSpawnedEntity(cWorld &a_World, cEntity &a_Entity)
bool CallHookChunkGenerating(cWorld &a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc *a_ChunkDesc)
bool CallHookPlayerRightClickingEntity(cPlayer &a_Player, cEntity &a_Entity)
bool CallHookPlayerRightClick(cPlayer &a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos)
static bool IsValidHookType(int a_HookType)
Returns true if the specified hook type is within the allowed range.
AStringVector GetFoldersToLoad(cSettingsRepositoryInterface &a_Settings)
Returns the folders that are specified in the settings ini to load plugins from.
bool CallHookChunkAvailable(cWorld &a_World, int a_ChunkX, int a_ChunkZ)
cDeadlockDetect & m_DeadlockDetect
The deadlock detect in which all plugins should track their CSs.
bool ForEachPlugin(cPluginCallback a_Callback)
Calls the specified callback for each plugin in m_Plugins.
bool CallHookPlayerFishing(cPlayer &a_Player, cItems &a_Reward, int &ExperienceAmount)
bool CallHookPlayerFoodLevelChange(cPlayer &a_Player, int a_NewFoodLevel)
bool CallHookPlayerShooting(cPlayer &a_Player)
bool ExecuteConsoleCommand(const AStringVector &a_Split, cCommandOutputCallback &a_Output, const AString &a_Command)
Executes the command split into a_Split, as if it was given on the console.
bool CallHookPlayerEating(cPlayer &a_Player)
bool CallHookHandshake(cClientHandle &a_ClientHandle, const AString &a_Username)
bool LoadPlugin(const AString &a_PluginFolder)
Loads the plugin from the specified plugin folder.
static cPluginManager * Get(void)
Returns the instance of the Plugin Manager (there is only ever one)
void RemovePluginCommands(cPlugin *a_Plugin)
Removes all command bindings that the specified plugin has made.
bool CallHookPlayerUsingItem(cPlayer &a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos)
bool CallHookPlayerTossingItem(cPlayer &a_Player)
bool CallHookServerPing(cClientHandle &a_ClientHandle, AString &a_ServerDescription, int &a_OnlinePlayersCount, int &a_MaxPlayersCount, AString &a_Favicon)
bool CallHookPlayerLeftClick(cPlayer &a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, char a_Status)
CommandMap m_ConsoleCommands
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 CallHookCollectingPickup(cPlayer &a_Player, cPickup &a_Pickup)
bool CallHookSpawnedMonster(cWorld &a_World, cMonster &a_Monster)
void ReloadPluginsNow(void)
Reloads all plugins, defaulting to settings.ini for settings location.
bool CallHookSpawningEntity(cWorld &a_World, cEntity &a_Entity)
bool CallHookLogin(cClientHandle &a_Client, UInt32 a_ProtocolVersion, const AString &a_Username)
bool CallHookDropSpense(cWorld &a_World, cDropSpenserEntity &a_DropSpenser, int a_SlotNum)
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)
void RemoveHooks(cPlugin *a_Plugin)
Removes all hooks the specified plugin has registered.
std::list< cPlugin * > PluginList
bool CallHookPlayerCrouched(cPlayer &a_Player)
size_t GetNumLoadedPlugins(void) const
Returns the number of plugins that are psLoaded.
bool CallHookChunkUnloaded(cWorld &a_World, int a_ChunkX, int a_ChunkZ)
void RefreshPluginList()
Refreshes the m_Plugins list based on the current contents of the Plugins folder.
bool CallHookPluginsLoaded(void)
bool CallHookPlayerPlacingBlock(cPlayer &a_Player, const sSetBlock &a_BlockChange)
void AddHook(cPlugin *a_Plugin, int a_HookType)
Adds the plugin to the list of plugins called for the specified hook type.
void UnloadPlugin(const AString &a_PluginFolder)
Queues the specified plugin to be unloaded in the next call to Tick().
bool CallHookPlayerSpawned(cPlayer &a_Player)
bool CallHookPlayerJoined(cPlayer &a_Player)
void RemovePluginConsoleCommands(cPlugin *a_Plugin)
Removes all console command bindings that the specified plugin has made.
bool ForEachConsoleCommand(cCommandEnumCallback &a_Callback)
Calls a_Callback for each bound console command, returns true if all commands were enumerated.
void Tick(float a_Dt)
Called each tick, calls the plugins' OnTick hook, as well as processes plugin events (addition,...
bool CallHookEntityChangingWorld(cEntity &a_Entity, cWorld &a_World)
bool CallHookPlayerDestroyed(cPlayer &a_Player)
bool CallHookPlayerOpeningWindow(cPlayer &a_Player, cWindow &a_Window)
bool CallHookWorldStarted(cWorld &a_World)
void TabCompleteCommand(const AString &a_Text, AStringVector &a_Results, cPlayer *a_Player)
Appends all commands beginning with a_Text (case-insensitive) into a_Results.
void ReloadPlugins()
Schedules a reload of the plugins to happen within the next call to Tick().
void UnloadPluginsNow(void)
Unloads all plugins.
bool CallHookPlayerUsingBlock(cPlayer &a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
bool CallHookProjectileHitEntity(cProjectileEntity &a_Projectile, cEntity &a_HitEntity)
bool m_bReloadPlugins
If set to true, all the plugins will be reloaded within the next call to Tick().
bool CallHookPlayerMoving(cPlayer &a_Player, const Vector3d &a_OldPosition, const Vector3d &a_NewPosition, bool a_PreviousIsOnGround)
bool CallHookProjectileHitBlock(cProjectileEntity &a_Projectile, Vector3i a_BlockPos, eBlockFace a_Face, const Vector3d &a_BlockHitPos)
bool CallHookPostCrafting(cPlayer &a_Player, cCraftingGrid &a_Grid, cCraftingRecipe &a_Recipe)
cCriticalSection m_CSPluginsNeedAction
Protects m_PluginsToUnload against multithreaded access.
bool CallHookEntityTeleport(cEntity &a_Entity, const Vector3d &a_OldPosition, const Vector3d &a_NewPosition)
cPluginPtrs m_Plugins
All plugins that have been found in the Plugins folder.
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 CallHookPlayerUsedBlock(cPlayer &a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
bool CallHookHopperPullingItem(cWorld &a_World, cHopperEntity &a_Hopper, int a_DstSlotNum, cBlockEntityWithItems &a_SrcEntity, int a_SrcSlotNum)
bool DoWithPlugin(const AString &a_PluginName, cPluginCallback a_Callback)
Calls the specified callback with the plugin object of the specified plugin.
bool ForEachCommand(cCommandEnumCallback &a_Callback)
Calls a_Callback for each bound command, returns true if all commands were enumerated.
bool CallHookKilled(cEntity &a_Victim, TakeDamageInfo &a_TDI, AString &a_DeathMessage)
static AString GetPluginsPath(void)
Returns the path where individual plugins' folders are expected.
bool CallHookBrewingCompleting(cWorld &a_World, cBrewingstandEntity &a_Brewingstand)
bool CallHookChunkUnloading(cWorld &a_World, int a_ChunkX, int a_ChunkZ)
CommandResult ForceExecuteCommand(cPlayer &a_Player, const AString &a_Command)
Executes the command, as if it was requested by a_Player.
bool CallHookSpawningMonster(cWorld &a_World, cMonster &a_Monster)
bool CallHookEntityChangedWorld(cEntity &a_Entity, cWorld &a_World)
bool BindCommand(const AString &a_Command, cPlugin *a_Plugin, cCommandHandlerPtr a_Handler, const AString &a_Permission, const AString &a_HelpString)
Binds a command to the specified handler.
bool CallHookWeatherChanged(cWorld &a_World)
bool CallHookPlayerBrokenBlock(cPlayer &a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
bool IsCommandBound(const AString &a_Command)
Returns true if the command is in the command map.
bool CallHookDisconnect(cClientHandle &a_Client, const AString &a_Reason)
bool CallHookLoginForge(cClientHandle &a_Client, AStringMap &a_Mods)
bool CallHookPlayerPlacedBlock(cPlayer &a_Player, const sSetBlock &a_BlockChange)
bool IsConsoleCommandBound(const AString &a_Command)
Returns true if the console command is in the command map.
bool CallHookKilling(cEntity &a_Victim, cEntity *a_Killer, TakeDamageInfo &a_TDI)
bool CallHookUpdatingSign(cWorld &a_World, Vector3i a_BlockPos, AString &a_Line1, AString &a_Line2, AString &a_Line3, AString &a_Line4, cPlayer *a_Player)
CommandResult HandleCommand(cPlayer &a_Player, const AString &a_Command, bool a_ShouldCheckPermissions)
Tries to match a_Command to the internal table of commands, if a match is found, the corresponding pl...
@ HOOK_ENTITY_CHANGING_WORLD
Definition: PluginManager.h:97
@ HOOK_PLAYER_RIGHT_CLICKING_ENTITY
@ HOOK_PLAYER_FOOD_LEVEL_CHANGE
bool CallHookPluginMessage(cClientHandle &a_Client, const AString &a_Channel, ContiguousByteBufferView a_Message)
bool CallHookChat(cPlayer &a_Player, AString &a_Message)
bool CallHookBlockSpread(cWorld &a_World, Vector3i a_BlockPos, eSpreadSource a_Source)
std::vector< std::pair< PluginAction, AString > > m_PluginsNeedAction
FolderNames of plugins that need an action (unload, reload, ...).
bool GenericCallHook(PluginHook a_HookName, HookFunction a_HookFunction)
Calls a_HookFunction on each plugin registered to the hook HookName.
bool CallHookHopperPushingItem(cWorld &a_World, cHopperEntity &a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems &a_DstEntity, int a_DstSlotNum)
bool CallHookWorldTick(cWorld &a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
bool CallHookPreCrafting(cPlayer &a_Player, cCraftingGrid &a_Grid, cCraftingRecipe &a_Recipe)
size_t GetNumPlugins() const
Returns the number of all plugins in m_Plugins (includes disabled, unloaded and errored plugins).
bool CallHookBrewingCompleted(cWorld &a_World, cBrewingstandEntity &a_Brewingstand)
virtual ~cPluginManager()
std::shared_ptr< cCommandHandler > cCommandHandlerPtr
CommandResult ExecuteCommand(cPlayer &a_Player, const AString &a_Command)
Executes the command, as if it was requested by a_Player.
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 CallHookCraftingNoRecipe(cPlayer &a_Player, cCraftingGrid &a_Grid, cCraftingRecipe &a_Recipe)
bool CallHookTakeDamage(cEntity &a_Receiver, TakeDamageInfo &a_TDI)
void ReloadPlugin(const AString &a_PluginFolder)
Queues the specified plugin to be reloaded in the next call to Tick().
bool CallHookPlayerUsedItem(cPlayer &a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_CursorPos)
bool IsPluginLoaded(const AString &a_PluginName)
Returns true if the specified plugin is loaded.
bool CallHookExecuteCommand(cPlayer *a_Player, const AStringVector &a_Split, const AString &a_EntireCommand, CommandResult &a_Result)
bool CallHookWeatherChanging(cWorld &a_World, eWeather &a_NewWeather)
bool CallHookPlayerFished(cPlayer &a_Player, const cItems &a_Reward, const int ExperienceAmount)
AString GetPluginFolderName(const AString &a_PluginName)
Returns the name of the folder (cPlugin::GetFolderName()) from which the specified plugin was loaded.
bool CallHookPlayerBreakingBlock(cPlayer &a_Player, Vector3i a_BlockPos, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
@ psNotFound
The plugin has been loaded before, but after a folder refresh it is no longer present.
Definition: PluginManager.h:76
bool BindConsoleCommand(const AString &a_Command, cPlugin *a_Plugin, cCommandHandlerPtr a_Handler, const AString &a_HelpString)
Binds a console command to the specified handler.
Used as a callback for enumerating bound commands.
virtual bool Command(const AString &a_Command, const cPlugin *a_Plugin, const AString &a_Permission, const AString &a_HelpString)=0
Called for each command; return true to abort enumeration For console commands, a_Permission is not u...
Interface for a callback that receives command output The Out() function is called for any output the...
Definition: CommandOutput.h:16
Definition: Entity.h:76
cWorld * GetWorld(void) const
Definition: Entity.h:190
Definition: Pickup.h:20
Definition: Player.h:29
const AString & GetName(void) const
Definition: Player.cpp:1299
void SendMessageInfo(const AString &a_Message)
Definition: Player.cpp:1191
void SendMessageFailure(const AString &a_Message)
Definition: Player.cpp:1200
bool HasPermission(const AString &a_Permission) const
Definition: Player.cpp:1586
bool ReadFile(const AString &a_FileName, bool a_AllowExampleRedirect=true)
Reads the contents of the specified ini file If the file doesn't exist and a_AllowExampleRedirect is ...
Definition: IniFile.cpp:50
Definition: Item.h:37
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
static bool IsFolder(const AString &a_Path)
Returns true if the specified path is a folder.
Definition: File.cpp:410
static AStringVector GetFolderContents(const AString &a_Folder)
Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there).
Definition: File.cpp:498
static cRoot * Get()
Definition: Root.h:52
cPluginManager * GetPluginManager(void)
Definition: Root.h:111
static void BindBuiltInConsoleCommands(void)
Binds the built-in console commands with the plugin manager.
Definition: Server.cpp:636
virtual bool DeleteValue(const AString &keyname, const AString &valuename)=0
Deletes the specified key, value pair.
virtual int AddKeyName(const AString &keyname)=0
Add a key name.
virtual std::vector< std::pair< AString, AString > > GetValues(AString a_keyName)=0
returns a vector containing a name, value pair for each value under the key
virtual bool KeyExists(const AString keyname) const =0
Returns true iff the specified key exists.
virtual void AddValue(const AString &a_KeyName, const AString &a_ValueName, const AString &a_Value)=0
Adds a new value to the specified key.
virtual bool SetValue(const AString &a_KeyName, const AString &a_ValueName, const AString &a_Value, const bool a_CreateIfNotExists=true)=0
Overwrites the value of the key, value pair Specify the optional parameter as false if you do not wan...
Represents a UI window.
Definition: Window.h:54
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17
Definition: World.h:53
const AString & GetName(void) const
Returns the name of the world.
Definition: World.h:691