Cuberite
A lightweight, fast and extensible game server for Minecraft
Root.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 "Root.h"
5 
6 // STD lib hreaders:
7 #include <iostream>
8 
9 // OS-specific headers:
10 #if defined(_WIN32)
11  #include <psapi.h>
12 #elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
13  #include <signal.h>
14  #if defined(__linux__)
15  #include <fstream>
16  #elif defined(__APPLE__)
17  #include <mach/mach.h>
18  #endif
19 #endif
20 
21 #include "Server.h"
22 #include "World.h"
23 #include "WebAdmin.h"
24 #include "BrewingRecipes.h"
25 #include "FurnaceRecipe.h"
26 #include "CraftingRecipes.h"
27 #include "Bindings/PluginManager.h"
28 #include "MonsterConfig.h"
29 #include "Entities/Player.h"
30 #include "Blocks/BlockHandler.h"
31 #include "Items/ItemHandler.h"
32 #include "Chunk.h"
33 #include "Protocol/ProtocolRecognizer.h" // for protocol version constants
34 #include "CommandOutput.h"
35 #include "DeadlockDetect.h"
36 #include "LoggerListeners.h"
37 #include "BuildInfo.h"
38 #include "IniFile.h"
40 #include "Logger.h"
41 #include "ClientHandle.h"
42 #include "BlockTypePalette.h"
44 
45 
46 
47 
48 
49 cRoot * cRoot::s_Root = nullptr;
50 
51 
52 
53 
54 
55 cRoot::cRoot(void) :
56  m_pDefaultWorld(nullptr),
57  m_Server(nullptr),
58  m_MonsterConfig(nullptr),
59  m_CraftingRecipes(nullptr),
60  m_FurnaceRecipe(nullptr),
61  m_BrewingRecipes(nullptr),
62  m_WebAdmin(nullptr),
63  m_PluginManager(nullptr),
64  m_MojangAPI(nullptr)
65 {
67  s_Root = this;
68  m_InputThreadRunFlag.clear();
69 }
70 
71 
72 
73 
74 
76 {
77  s_Root = nullptr;
78 }
79 
80 
81 
82 
83 
84 void cRoot::InputThread(cRoot & a_Params)
85 {
87  AString Command;
88 
89  while (a_Params.m_InputThreadRunFlag.test_and_set() && std::cin.good())
90  {
91  #ifndef _WIN32
92  timeval Timeout{ 0, 0 };
93  Timeout.tv_usec = 100 * 1000; // 100 msec
94 
95  fd_set ReadSet;
96  FD_ZERO(&ReadSet);
97  FD_SET(STDIN_FILENO, &ReadSet);
98 
99  if (select(STDIN_FILENO + 1, &ReadSet, nullptr, nullptr, &Timeout) <= 0)
100  {
101  // Don't call getline because there's nothing to read
102  continue;
103  }
104  #endif
105 
106  std::getline(std::cin, Command);
107 
108  if (!a_Params.m_InputThreadRunFlag.test_and_set())
109  {
110  // Already shutting down, can't execute commands
111  break;
112  }
113 
114  if (!Command.empty())
115  {
116  // Execute and clear command string when submitted
117  a_Params.ExecuteConsoleCommand(TrimString(Command), Output);
118  }
119  }
120 
121  // We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running
122  // Ignore this when running as a service, cin was never opened in that case
123  if (!std::cin.good() && !m_RunAsService)
124  {
125  // Stop the server:
126  a_Params.QueueExecuteConsoleCommand("stop");
127  }
128 }
129 
130 
131 
132 
133 
134 void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo)
135 {
136  #ifdef _WIN32
137  HMENU ConsoleMenu = GetSystemMenu(GetConsoleWindow(), FALSE);
138  EnableMenuItem(ConsoleMenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling
139  #endif
140 
141  auto consoleLogListener = MakeConsoleListener(m_RunAsService);
142  auto consoleAttachment = cLogger::GetInstance().AttachListener(std::move(consoleLogListener));
143 
144  cLogger::cAttachment fileAttachment;
145  if (!a_OverridesRepo->HasValue("Server","DisableLogFile"))
146  {
147  auto fileLogListenerRet = MakeFileListener();
148  if (!fileLogListenerRet.first)
149  {
150  m_TerminateEventRaised = true;
151  LOGERROR("Failed to open log file, aborting");
152  return;
153  }
154  fileAttachment = cLogger::GetInstance().AttachListener(std::move(fileLogListenerRet.second));
155  }
156 
157  LOG("--- Started Log ---");
158 
159  #ifdef BUILD_ID
160  LOG("Cuberite " BUILD_SERIES_NAME " build id: " BUILD_ID);
161  LOG("from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME);
162  #endif
163 
164  cDeadlockDetect dd;
165  auto BeginTime = std::chrono::steady_clock::now();
166 
168 
169  LOG("Creating new server instance...");
170  m_Server = new cServer();
171 
172  LOG("Reading server config...");
173 
174  m_SettingsFilename = "settings.ini";
175  if (a_OverridesRepo->HasValue("Server","ConfigFile"))
176  {
177  m_SettingsFilename = a_OverridesRepo->GetValue("Server","ConfigFile");
178  }
179 
180  auto IniFile = cpp14::make_unique<cIniFile>();
181  bool IsNewIniFile = !IniFile->ReadFile(m_SettingsFilename);
182 
183  if (IsNewIniFile)
184  {
185  LOGWARN("Regenerating settings.ini, all settings will be reset");
186  IniFile->AddHeaderComment(" This is the main server configuration");
187  IniFile->AddHeaderComment(" Most of the settings here can be configured using the webadmin interface, if enabled in webadmin.ini");
188  }
189 
190  auto settingsRepo = cpp14::make_unique<cOverridesSettingsRepository>(std::move(IniFile), std::move(a_OverridesRepo));
191 
192  LOG("Starting server...");
193 
194  // cClientHandle::FASTBREAK_PERCENTAGE = settingsRepo->GetValueSetI("AntiCheat", "FastBreakPercentage", 97) / 100.0f;
195  cClientHandle::FASTBREAK_PERCENTAGE = 0; // AntiCheat disabled due to bugs. We will enabled it once they are fixed. See #3506.
196 
197  LoadPalettes(settingsRepo->GetValueSet("Folders", "ProtocolPalettes", "Protocol"));
198 
199  m_MojangAPI = new cMojangAPI;
200  bool ShouldAuthenticate = settingsRepo->GetValueSetB("Authentication", "Authenticate", true);
201  m_MojangAPI->Start(*settingsRepo, ShouldAuthenticate); // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init
202  if (!m_Server->InitServer(*settingsRepo, ShouldAuthenticate))
203  {
204  settingsRepo->Flush();
205  LOGERROR("Failure starting server, aborting...");
206  return;
207  }
208 
209  m_WebAdmin = new cWebAdmin();
210  m_WebAdmin->Init();
211 
212  LOGD("Loading settings...");
213  m_RankManager.reset(new cRankManager());
214  m_RankManager->Initialize(*m_MojangAPI);
217  m_BrewingRecipes.reset(new cBrewingRecipes());
218 
219  LOGD("Loading worlds...");
220  LoadWorlds(dd, *settingsRepo, IsNewIniFile);
221 
222  LOGD("Loading plugin manager...");
224  m_PluginManager->ReloadPluginsNow(*settingsRepo);
225 
226  LOGD("Loading MonsterConfig...");
228 
229  // This sets stuff in motion
230  LOGD("Starting Authenticator...");
231  m_Authenticator.Start(*settingsRepo);
232 
233  LOGD("Starting worlds...");
234  StartWorlds(dd);
235 
236  if (settingsRepo->GetValueSetB("DeadlockDetect", "Enabled", true))
237  {
238  LOGD("Starting deadlock detector...");
239  dd.Start(settingsRepo->GetValueSetI("DeadlockDetect", "IntervalSec", 20));
240  }
241 
242  settingsRepo->Flush();
243 
244  LOGD("Finalising startup...");
245  if (m_Server->Start())
246  {
247  m_WebAdmin->Start();
248 
249  LOGD("Starting InputThread...");
250  try
251  {
252  m_InputThreadRunFlag.test_and_set();
253  m_InputThread = std::thread(InputThread, std::ref(*this));
254  }
255  catch (std::system_error & a_Exception)
256  {
257  LOGERROR("cRoot::Start (std::thread) error %i: could not construct input thread; %s", a_Exception.code().value(), a_Exception.what());
258  }
259 
260  LOG("Startup complete, took %ldms!", static_cast<long int>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - BeginTime).count()));
261 
262  // Save the current time
263  m_StartTime = std::chrono::steady_clock::now();
264 
265  #ifdef _WIN32
266  EnableMenuItem(ConsoleMenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
267  #endif
268 
269  for (;;)
270  {
271  m_StopEvent.Wait();
272 
273  break;
274  }
275 
276  // Stop the server:
277  m_WebAdmin->Stop();
278 
279  LOG("Shutting down server...");
280  m_Server->Shutdown();
281  } // if (m_Server->Start()
282  else
283  {
285  #ifdef _WIN32
286  EnableMenuItem(ConsoleMenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
287  #endif
288  }
289 
290  delete m_MojangAPI; m_MojangAPI = nullptr;
291 
292  LOGD("Shutting down deadlock detector...");
293  dd.Stop();
294 
295  LOGD("Stopping world threads...");
296  StopWorlds(dd);
297 
298  LOGD("Stopping authenticator...");
300 
301  LOGD("Freeing MonsterConfig...");
302  delete m_MonsterConfig; m_MonsterConfig = nullptr;
303  delete m_WebAdmin; m_WebAdmin = nullptr;
304 
305  LOGD("Unloading recipes...");
306  delete m_FurnaceRecipe; m_FurnaceRecipe = nullptr;
307  delete m_CraftingRecipes; m_CraftingRecipes = nullptr;
308 
309  LOG("Unloading worlds...");
310  UnloadWorlds();
311 
312  LOGD("Stopping plugin manager...");
313  delete m_PluginManager; m_PluginManager = nullptr;
314 
316 
317  LOG("Cleaning up...");
318  delete m_Server; m_Server = nullptr;
319 
320  m_InputThreadRunFlag.clear();
321  #ifdef _WIN32
322  DWORD Length;
323  INPUT_RECORD Record
324  {
325  KEY_EVENT,
326  {
327  {
328  TRUE,
329  1,
330  VK_RETURN,
331  static_cast<WORD>(MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC)),
332  { { VK_RETURN } },
333  0
334  }
335  }
336  };
337 
338  // Can't kill the input thread since it breaks cin (getline doesn't block / receive input on restart)
339  // Apparently no way to unblock getline
340  // Only thing I can think of for now
341  if (WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &Record, 1, &Length) == 0)
342  {
343  LOGWARN("Couldn't notify the input thread; the server will hang before shutdown!");
344  m_TerminateEventRaised = true;
345  m_InputThread.detach();
346  }
347  else
348  {
349  m_InputThread.join();
350  }
351  #else
352  m_InputThread.join();
353  #endif
354 
356  {
357  LOG("Shutdown successful!");
358  }
359  else
360  {
361  LOG("Shutdown successful - restarting...");
362  }
363  LOG("--- Stopped Log ---");
364 }
365 
366 
367 
368 
369 
371 {
372  // Kick all players from the server with custom disconnect message
373 
374  bool SentDisconnect = false;
375  cRoot::Get()->ForEachPlayer([&](cPlayer & a_Player)
376  {
377  a_Player.GetClientHandlePtr()->Kick(m_Server->GetShutdownMessage());
378  SentDisconnect = true;
379  return false;
380  }
381  );
382  if (SentDisconnect)
383  {
384  std::this_thread::sleep_for(std::chrono::seconds(1));
385  }
386  m_TerminateEventRaised = true;
387  m_StopEvent.Set();
388  m_InputThreadRunFlag.clear();
389 }
390 
391 
392 
393 
394 
396 {
397  // Nothing needed yet
398 }
399 
400 
401 
402 
403 
404 void cRoot::LoadPalettes(const AString & aProtocolFolder)
405 {
406  LOG("Loading UpgradeBlockTypePalette...");
407  try
408  {
409  auto paletteStr = cFile::ReadWholeFile(aProtocolFolder + cFile::PathSeparator() + "UpgradeBlockTypePalette.txt");
410  if (paletteStr.empty())
411  {
412  throw std::runtime_error("File is empty");
413  }
415  m_UpgradeBlockTypePalette->loadFromString(paletteStr);
416  }
417  catch (const std::exception & exc)
418  {
419  LOGERROR("Failed to load the Upgrade block type palette from %s/UpgradeBlockTypePalette.txt: %s\nAborting",
420  aProtocolFolder, exc.what()
421  );
422  throw;
423  }
424 
425  // Note: This can take a lot of time in MSVC debug builds
426  // If impatient, edit the settings.ini: [Folders] ProtocolPalettes=DummyDir; copy only one palette to DummyDir
427  LOG("Loading per-protocol palettes...");
429  m_ProtocolPalettes->load(aProtocolFolder);
430  auto versions = m_ProtocolPalettes->protocolVersions();
431  if (versions.empty())
432  {
433  LOGWARNING("No per-protocol palettes were loaded");
434  }
435  else
436  {
437  std::sort(versions.begin(), versions.end());
438  LOG("Loaded palettes for protocol versions: %s", StringJoin(versions, ", "));
439  }
440 }
441 
442 
443 
444 
445 
446 void cRoot::LoadWorlds(cDeadlockDetect & a_dd, cSettingsRepositoryInterface & a_Settings, bool a_IsNewIniFile)
447 {
448  if (a_IsNewIniFile)
449  {
450  a_Settings.AddValue("Worlds", "DefaultWorld", "world");
451  a_Settings.AddValue("Worlds", "World", "world_nether");
452  a_Settings.AddValue("Worlds", "World", "world_the_end");
453  a_Settings.AddValue("WorldPaths", "world", "world");
454  a_Settings.AddValue("WorldPaths", "world_nether", "world_nether");
455  a_Settings.AddValue("WorldPaths", "world_the_end", "world_the_end");
456 
457  AStringVector WorldNames{ "world", "world_nether", "world_the_end" };
458  m_pDefaultWorld = new cWorld("world", "world", a_dd, WorldNames);
459  m_WorldsByName["world"] = m_pDefaultWorld;
460  m_WorldsByName["world_nether"] = new cWorld("world_nether", "world_nether", a_dd, WorldNames, dimNether, "world");
461  m_WorldsByName["world_the_end"] = new cWorld("world_the_end", "world_the_end", a_dd, WorldNames, dimEnd, "world");
462  return;
463  }
464 
465  // Build a list of all world names
466  auto Worlds = a_Settings.GetValues("Worlds");
467  AStringVector WorldNames(Worlds.size());
468  for (const auto & World : Worlds)
469  {
470  WorldNames.push_back(World.second);
471  }
472 
473  // Get the default world
474  AString DefaultWorldName = a_Settings.GetValueSet("Worlds", "DefaultWorld", "world");
475  AString DefaultWorldPath = a_Settings.GetValueSet("WorldPaths", DefaultWorldName, DefaultWorldName);
476  m_pDefaultWorld = new cWorld(DefaultWorldName.c_str(), DefaultWorldPath.c_str(), a_dd, WorldNames);
477  m_WorldsByName[ DefaultWorldName ] = m_pDefaultWorld;
478 
479  // Then load the other worlds
480  if (Worlds.size() <= 0)
481  {
482  return;
483  }
484 
485  /* Here are the world creation rules. Note that these only apply for a world which is in settings.ini but has no world.ini file.
486  If an ini file is present, it overrides the world linkages and the dimension type in cWorld::start()
487  The creation rules are as follows:
488 
489  - If a world exists in settings.ini but has no world.ini, then:
490  - If the world name is x_nether, create a world.ini with the dimension type "nether".
491  - If a world called x exists, set it as x_nether's overworld.
492  - Otherwise set the default world as x_nether's overworld.
493 
494  - If the world name is x_the_end or x_end, create a world.ini with the dimension type "end".
495  - If a world called x exists, set it as x_the_end's overworld.
496  - Otherwise set the default world as x_the_end's overworld.
497 
498  - If the world name is x (and doesn't end with _the_end, _end or _nether)
499  - Create a world.ini with a dimension type of "overworld".
500  - If a world called x_nether exists, set it as x's nether world.
501  - Otherwise set x's nether world to blank.h
502  - If a world called x_the_end or x_end exists, set it as x's end world.
503  - Otherwise set x's nether world to blank.
504 
505  */
506 
507  bool FoundAdditionalWorlds = false;
508  for (auto WorldNameValue : Worlds)
509  {
510  AString ValueName = WorldNameValue.first;
511  if (ValueName.compare("World") != 0)
512  {
513  continue;
514  }
515  AString WorldName = WorldNameValue.second;
516  if (WorldName.empty())
517  {
518  continue;
519  }
520  FoundAdditionalWorlds = true;
521  cWorld * NewWorld;
522  AString LowercaseName = StrToLower(WorldName);
523  AString WorldPath = a_Settings.GetValueSet("WorldPaths", WorldName, WorldName);
524  AString NetherAppend = "_nether";
525  AString EndAppend1 = "_the_end";
526  AString EndAppend2 = "_end";
527 
528  // The default world is an overworld with no links
529  eDimension Dimension = dimOverworld;
530  AString LinkTo = "";
531 
532  // if the world is called x_nether
533  if ((LowercaseName.size() > NetherAppend.size()) && (LowercaseName.substr(LowercaseName.size() - NetherAppend.size()) == NetherAppend))
534  {
535  // The world is called x_nether, see if a world called x exists. If yes, choose it as the linked world,
536  // otherwise, choose the default world as the linked world.
537  // As before, any ini settings will completely override this if an ini is already present.
538 
539  LinkTo = WorldName.substr(0, WorldName.size() - NetherAppend.size());
540  if (GetWorld(LinkTo) == nullptr)
541  {
542  LinkTo = DefaultWorldName;
543  }
544  Dimension = dimNether;
545  }
546  // if the world is called x_the_end
547  else if ((LowercaseName.size() > EndAppend1.size()) && (LowercaseName.substr(LowercaseName.size() - EndAppend1.size()) == EndAppend1))
548  {
549  // The world is called x_the_end, see if a world called x exists. If yes, choose it as the linked world,
550  // otherwise, choose the default world as the linked world.
551  // As before, any ini settings will completely override this if an ini is already present.
552 
553  LinkTo = WorldName.substr(0, WorldName.size() - EndAppend1.size());
554  if (GetWorld(LinkTo) == nullptr)
555  {
556  LinkTo = DefaultWorldName;
557  }
558  Dimension = dimEnd;
559  }
560  // if the world is called x_end
561  else if ((LowercaseName.size() > EndAppend2.size()) && (LowercaseName.substr(LowercaseName.size() - EndAppend2.size()) == EndAppend2))
562  {
563  // The world is called x_end, see if a world called x exists. If yes, choose it as the linked world,
564  // otherwise, choose the default world as the linked world.
565  // As before, any ini settings will completely override this if an ini is already present.
566 
567  LinkTo = WorldName.substr(0, WorldName.size() - EndAppend2.size());
568  if (GetWorld(LinkTo) == nullptr)
569  {
570  LinkTo = DefaultWorldName;
571  }
572  Dimension = dimEnd;
573  }
574  NewWorld = new cWorld(WorldName.c_str(), WorldPath.c_str(), a_dd, WorldNames, Dimension, LinkTo);
575  m_WorldsByName[WorldName] = NewWorld;
576  } // for i - Worlds
577 
578  if (!FoundAdditionalWorlds)
579  {
580  if (a_Settings.GetKeyComment("Worlds", 0) != " World=secondworld")
581  {
582  a_Settings.DeleteKeyComment("Worlds", 0);
583  a_Settings.AddKeyComment("Worlds", " World=secondworld");
584  }
585  }
586 }
587 
588 
589 
590 
591 
592 void cRoot::StartWorlds(cDeadlockDetect & a_DeadlockDetect)
593 {
594  for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
595  {
596  itr->second->Start();
597  itr->second->InitializeSpawn();
598  m_PluginManager->CallHookWorldStarted(*itr->second);
599  }
600 }
601 
602 
603 
604 
605 
606 void cRoot::StopWorlds(cDeadlockDetect & a_DeadlockDetect)
607 {
608  for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
609  {
610  itr->second->Stop(a_DeadlockDetect);
611  }
612 }
613 
614 
615 
616 
617 
619 {
620  m_pDefaultWorld = nullptr;
621  for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
622  {
623  delete itr->second;
624  }
625  m_WorldsByName.clear();
626 }
627 
628 
629 
630 
631 
633 {
634  return m_pDefaultWorld;
635 }
636 
637 
638 
639 
640 
641 cWorld * cRoot::GetWorld(const AString & a_WorldName)
642 {
643  WorldMap::iterator itr = m_WorldsByName.find(a_WorldName);
644  if (itr != m_WorldsByName.end())
645  {
646  return itr->second;
647  }
648 
649  return nullptr;
650 }
651 
652 
653 
654 
655 
657 {
658  for (auto & World : m_WorldsByName)
659  {
660  if (World.second != nullptr)
661  {
662  if (a_Callback(*World.second))
663  {
664  return false;
665  }
666  }
667  }
668  return true;
669 }
670 
671 
672 
673 
674 
676 {
677  // Execute any pending commands:
678  cCommandQueue PendingCommands;
679  {
681  std::swap(PendingCommands, m_PendingCommands);
682  }
683  for (cCommandQueue::iterator itr = PendingCommands.begin(), end = PendingCommands.end(); itr != end; ++itr)
684  {
685  ExecuteConsoleCommand(itr->m_Command, *(itr->m_Output));
686  }
687 }
688 
689 
690 
691 
692 
694 {
695  // Put the command into a queue (Alleviates FS #363):
697  m_PendingCommands.emplace_back(a_Cmd, &a_Output);
698 }
699 
700 
701 
702 
703 
705 {
706  // Put the command into a queue (Alleviates FS #363):
709 }
710 
711 
712 
713 
714 
716 {
717  // Some commands are built-in:
718  if (a_Cmd == "stop")
719  {
720  StopServer();
721  return;
722  }
723  else if (a_Cmd == "restart")
724  {
725  m_StopEvent.Set();
726  m_InputThreadRunFlag.clear();
727  return;
728  }
729 
730  LOG("Executing console command: \"%s\"", a_Cmd.c_str());
731  m_Server->ExecuteConsoleCommand(a_Cmd, a_Output);
732 }
733 
734 
735 
736 
737 
738 void cRoot::KickUser(int a_ClientID, const AString & a_Reason)
739 {
740  m_Server->KickUser(a_ClientID, a_Reason);
741 }
742 
743 
744 
745 
746 
747 void cRoot::AuthenticateUser(int a_ClientID, const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties)
748 {
749  m_Server->AuthenticateUser(a_ClientID, a_Name, a_UUID, a_Properties);
750 }
751 
752 
753 
754 
755 
757 {
758  int res = 0;
759  for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
760  {
761  res += static_cast<int>(itr->second->GetNumChunks());
762  }
763  return res;
764 }
765 
766 
767 
768 
769 
771 {
772  for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
773  {
774  itr->second->QueueSaveAllChunks();
775  }
776 }
777 
778 
779 
780 
781 
782 void cRoot::SetSavingEnabled(bool a_SavingEnabled)
783 {
784  for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
785  {
786  itr->second->SetSavingEnabled(a_SavingEnabled);
787  }
788 }
789 
790 
791 
792 
793 
794 void cRoot::SendPlayerLists(cPlayer * a_DestPlayer)
795 {
796  for (const auto & itr : m_WorldsByName)
797  {
798  itr.second->SendPlayerList(a_DestPlayer);
799  } // for itr - m_WorldsByName[]
800 }
801 
802 
803 
804 
805 
806 void cRoot::BroadcastPlayerListsAddPlayer(const cPlayer & a_Player, const cClientHandle * a_Exclude)
807 {
808  for (const auto & itr : m_WorldsByName)
809  {
810  itr.second->BroadcastPlayerListAddPlayer(a_Player);
811  } // for itr - m_WorldsByName[]
812 }
813 
814 
815 
816 
817 
818 void cRoot::BroadcastPlayerListsRemovePlayer(const cPlayer & a_Player, const cClientHandle * a_Exclude)
819 {
820  for (const auto & itr : m_WorldsByName)
821  {
822  itr.second->BroadcastPlayerListRemovePlayer(a_Player);
823  } // for itr - m_WorldsByName[]
824 }
825 
826 
827 
828 
829 
830 void cRoot::BroadcastChat(const AString & a_Message, eMessageType a_ChatPrefix)
831 {
832  for (WorldMap::iterator itr = m_WorldsByName.begin(), end = m_WorldsByName.end(); itr != end; ++itr)
833  {
834  itr->second->BroadcastChat(a_Message, nullptr, a_ChatPrefix);
835  } // for itr - m_WorldsByName[]
836 }
837 
838 
839 
840 
841 
842 void cRoot::BroadcastChat(const cCompositeChat & a_Message)
843 {
844  for (WorldMap::iterator itr = m_WorldsByName.begin(), end = m_WorldsByName.end(); itr != end; ++itr)
845  {
846  itr->second->BroadcastChat(a_Message);
847  } // for itr - m_WorldsByName[]
848 }
849 
850 
851 
852 
853 
855 {
856  for (WorldMap::iterator itr = m_WorldsByName.begin(), itr2 = itr; itr != m_WorldsByName.end(); itr = itr2)
857  {
858  ++itr2;
859  if (!itr->second->ForEachPlayer(a_Callback))
860  {
861  return false;
862  }
863  }
864  return true;
865 }
866 
867 
868 
869 
870 
871 bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback a_Callback)
872 {
873  class cCallback
874  {
875  size_t m_BestRating;
876  size_t m_NameLength;
877  const AString m_PlayerName;
878 
879  public:
880 
881  bool operator () (cPlayer & a_Player)
882  {
883  size_t Rating = RateCompareString (m_PlayerName, a_Player.GetName());
884  if ((Rating > 0) && (Rating >= m_BestRating))
885  {
886  m_BestMatch = a_Player.GetName();
887  if (Rating > m_BestRating)
888  {
889  m_NumMatches = 0;
890  }
891  m_BestRating = Rating;
892  ++m_NumMatches;
893  }
894  if (Rating == m_NameLength) // Perfect match
895  {
896  return true;
897  }
898  return false;
899  }
900 
901  cCallback (const AString & a_CBPlayerName) :
902  m_BestRating(0),
903  m_NameLength(a_CBPlayerName.length()),
904  m_PlayerName(a_CBPlayerName),
905  m_BestMatch(),
906  m_NumMatches(0)
907  {}
908 
909  AString m_BestMatch;
910  unsigned m_NumMatches;
911  } Callback (a_PlayerName);
912  ForEachPlayer(Callback);
913 
914  if (Callback.m_NumMatches == 1)
915  {
916  return DoWithPlayer(Callback.m_BestMatch, a_Callback);
917  }
918  return false;
919 }
920 
921 
922 
923 
924 
925 bool cRoot::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cPlayerListCallback a_Callback)
926 {
927  for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
928  {
929  if (itr->second->DoWithPlayerByUUID(a_PlayerUUID, a_Callback))
930  {
931  return true;
932  }
933  }
934  return false;
935 }
936 
937 
938 
939 
940 
941 bool cRoot::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback a_Callback)
942 {
943  for (auto World : m_WorldsByName)
944  {
945  if (World.second->DoWithPlayer(a_PlayerName, a_Callback))
946  {
947  return true;
948  }
949  }
950  return false;
951 }
952 
953 
954 
955 
956 
958 {
959  return cProtocolRecognizer::GetVersionTextFromInt(a_ProtocolVersion);
960 }
961 
962 
963 
964 
965 
967 {
968  #ifdef _WIN32
969  PROCESS_MEMORY_COUNTERS_EX pmc;
970  if (GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS *)&pmc, sizeof(pmc)))
971  {
972  return (int)(pmc.PrivateUsage / 1024);
973  }
974  return -1;
975  #elif defined(__linux__)
976  // Code adapted from https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
977  std::ifstream StatFile("/proc/self/status");
978  if (!StatFile.good())
979  {
980  return -1;
981  }
982  while (StatFile.good())
983  {
984  AString Line;
985  std::getline(StatFile, Line);
986  if (strncmp(Line.c_str(), "VmSize:", 7) == 0)
987  {
988  int res = atoi(Line.c_str() + 8);
989  return (res == 0) ? -1 : res; // If parsing failed, return -1
990  }
991  }
992  return -1;
993  #elif defined (__APPLE__)
994  // Code adapted from https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
995  struct task_basic_info t_info;
996  mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
997 
998  if (KERN_SUCCESS == task_info(
999  mach_task_self(),
1000  TASK_BASIC_INFO,
1001  reinterpret_cast<task_info_t>(&t_info),
1002  &t_info_count
1003  ))
1004  {
1005  return static_cast<int>(t_info.virtual_size / 1024);
1006  }
1007  return -1;
1008  #else
1009  LOGINFO("%s: Unknown platform, cannot query memory usage", __FUNCTION__);
1010  return -1;
1011  #endif
1012 }
1013 
1014 
1015 
1016 
1017 
1019 {
1020  #ifdef _WIN32
1021  PROCESS_MEMORY_COUNTERS pmc;
1022  if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
1023  {
1024  return (int)(pmc.WorkingSetSize / 1024);
1025  }
1026  return -1;
1027  #elif defined(__linux__)
1028  // Code adapted from https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
1029  std::ifstream StatFile("/proc/self/status");
1030  if (!StatFile.good())
1031  {
1032  return -1;
1033  }
1034  while (StatFile.good())
1035  {
1036  AString Line;
1037  std::getline(StatFile, Line);
1038  if (strncmp(Line.c_str(), "VmRSS:", 6) == 0)
1039  {
1040  int res = atoi(Line.c_str() + 7);
1041  return (res == 0) ? -1 : res; // If parsing failed, return -1
1042  }
1043  }
1044  return -1;
1045  #elif defined (__APPLE__)
1046  // Code adapted from https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
1047  struct task_basic_info t_info;
1048  mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
1049 
1050  if (KERN_SUCCESS == task_info(
1051  mach_task_self(),
1052  TASK_BASIC_INFO,
1053  reinterpret_cast<task_info_t>(&t_info),
1054  &t_info_count
1055  ))
1056  {
1057  return static_cast<int>(t_info.resident_size / 1024);
1058  }
1059  return -1;
1060  #else
1061  LOGINFO("%s: Unknown platform, cannot query memory usage", __FUNCTION__);
1062  return -1;
1063  #endif
1064 }
1065 
1066 
1067 
1068 
1069 
1071 {
1072  int SumNumValid = 0;
1073  int SumNumDirty = 0;
1074  int SumNumInLighting = 0;
1075  int SumNumInGenerator = 0;
1076  int SumMem = 0;
1077  for (WorldMap::iterator itr = m_WorldsByName.begin(), end = m_WorldsByName.end(); itr != end; ++itr)
1078  {
1079  cWorld * World = itr->second;
1080  int NumInGenerator = World->GetGeneratorQueueLength();
1081  int NumInSaveQueue = static_cast<int>(World->GetStorageSaveQueueLength());
1082  int NumInLoadQueue = static_cast<int>(World->GetStorageLoadQueueLength());
1083  int NumValid = 0;
1084  int NumDirty = 0;
1085  int NumInLighting = 0;
1086  World->GetChunkStats(NumValid, NumDirty, NumInLighting);
1087  a_Output.Out("World %s:", World->GetName().c_str());
1088  a_Output.Out(" Num loaded chunks: %d", NumValid);
1089  a_Output.Out(" Num dirty chunks: %d", NumDirty);
1090  a_Output.Out(" Num chunks in lighting queue: %d", NumInLighting);
1091  a_Output.Out(" Num chunks in generator queue: %d", NumInGenerator);
1092  a_Output.Out(" Num chunks in storage load queue: %d", NumInLoadQueue);
1093  a_Output.Out(" Num chunks in storage save queue: %d", NumInSaveQueue);
1094  int Mem = NumValid * static_cast<int>(sizeof(cChunk));
1095  a_Output.Out(" Memory used by chunks: %d KiB (%d MiB)", (Mem + 1023) / 1024, (Mem + 1024 * 1024 - 1) / (1024 * 1024));
1096  a_Output.Out(" Per-chunk memory size breakdown:");
1097  a_Output.Out(" block types: %6zu bytes (%3zu KiB)", sizeof(cChunkDef::BlockTypes), (sizeof(cChunkDef::BlockTypes) + 1023) / 1024);
1098  a_Output.Out(" block metadata: %6zu bytes (%3zu KiB)", sizeof(cChunkDef::BlockNibbles), (sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
1099  a_Output.Out(" block lighting: %6zu bytes (%3zu KiB)", 2 * sizeof(cChunkDef::BlockNibbles), (2 * sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
1100  a_Output.Out(" heightmap: %6zu bytes (%3zu KiB)", sizeof(cChunkDef::HeightMap), (sizeof(cChunkDef::HeightMap) + 1023) / 1024);
1101  a_Output.Out(" biomemap: %6zu bytes (%3zu KiB)", sizeof(cChunkDef::BiomeMap), (sizeof(cChunkDef::BiomeMap) + 1023) / 1024);
1102  SumNumValid += NumValid;
1103  SumNumDirty += NumDirty;
1104  SumNumInLighting += NumInLighting;
1105  SumNumInGenerator += NumInGenerator;
1106  SumMem += Mem;
1107  }
1108  a_Output.Out("Totals:");
1109  a_Output.Out(" Num loaded chunks: %d", SumNumValid);
1110  a_Output.Out(" Num dirty chunks: %d", SumNumDirty);
1111  a_Output.Out(" Num chunks in lighting queue: %d", SumNumInLighting);
1112  a_Output.Out(" Num chunks in generator queue: %d", SumNumInGenerator);
1113  a_Output.Out(" Memory used by chunks: %d KiB (%d MiB)", (SumMem + 1023) / 1024, (SumMem + 1024 * 1024 - 1) / (1024 * 1024));
1114 }
1115 
1116 
1117 
1118 
1119 
1121 {
1122  cFurnaceRecipe * FR = Get()->GetFurnaceRecipe();
1123  return FR->GetBurnTime(a_Fuel);
1124 }
1125 
1126 
1127 
1128 
1129 
1131 {
1132  AStringVector Results;
1133  ForEachWorld([&](cWorld & a_World)
1134  {
1135  a_World.TabCompleteUserName(a_Text, Results);
1136  return false;
1137  }
1138  );
1139  return Results;
1140 }
void Shutdown(void)
Definition: Server.cpp:628
cAuthenticator m_Authenticator
Definition: Root.h:235
BlockTypeRegistry m_BlockTypeRegistry
The storage for all registered block types.
Definition: Root.h:243
cCriticalSection m_CSPendingCommands
Definition: Root.h:220
std::unique_ptr< cRankManager > m_RankManager
Definition: Root.h:238
void Set(void)
Sets the event - releases one thread that has been waiting in Wait().
Definition: Event.cpp:53
void ExecuteConsoleCommand(const AString &a_Cmd, cCommandOutputCallback &a_Output)
Executes a console command through the cServer class; does special handling for "stop" and "restart"...
Definition: Root.cpp:715
void ExecuteConsoleCommand(const AString &a_Cmd, cCommandOutputCallback &a_Output)
Executes the console command, sends output through the specified callback.
Definition: Server.cpp:444
eDimension
Dimension of a world.
Definition: BlockID.h:1127
void LogChunkStats(cCommandOutputCallback &a_Output)
Writes chunkstats, for each world and totals, to the output callback.
Definition: Root.cpp:1070
cMonsterConfig * m_MonsterConfig
Definition: Root.h:228
void BroadcastChat(const AString &a_Message, eMessageType a_ChatPrefix=mtCustom)
Sends a chat message to all connected clients (in all worlds)
Definition: Root.cpp:830
cPluginManager * m_PluginManager
Definition: Root.h:234
int GetTotalChunkCount(void)
Returns the number of chunks loaded.
Definition: Root.cpp:756
static int GetPhysicalRAMUsage(void)
Returns the amount of virtual RAM used, in KiB.
Definition: Root.cpp:1018
std::vector< cCommand > cCommandQueue
Definition: Root.h:215
BLOCKTYPE BlockTypes[NumBlocks]
The type used for block type operations and storage, AXIS_ORDER ordering.
Definition: ChunkDef.h:150
bool Start(void)
Definition: Server.cpp:403
AString StringJoin(const AStringVector &a_Strings, const AString &a_Delimeter)
Join a list of strings with the given delimiter between entries.
cClientHandlePtr GetClientHandlePtr(void) const
Returns the SharedPtr to client handle associated with the player.
Definition: Player.h:259
virtual bool AddKeyComment(const AString &keyname, const AString &comment)=0
Add a key comment, will always fail if the repository does not support comments.
AString m_SettingsFilename
which ini file to load settings from, default is settings.ini
Definition: Root.h:58
#define LOGWARN
Definition: LoggerSimple.h:43
static float FASTBREAK_PERCENTAGE
The percentage how much a block has to be broken.
Definition: ClientHandle.h:62
bool ForEachWorld(cWorldListCallback a_Callback)
Calls the callback for each world; returns true if the callback didn&#39;t abort (return true) ...
Definition: Root.cpp:656
cAttachment AttachListener(std::unique_ptr< cListener > a_Listener)
Definition: Logger.cpp:84
bool Start(int a_IntervalSec)
Starts the detection.
Definition: Player.h:27
static AString ReadWholeFile(const AString &a_FileName)
Returns the entire contents of the specified file as a string.
Definition: File.cpp:573
void Start(cSettingsRepositoryInterface &a_Settings, bool a_ShouldAuth)
Initializes the API; reads the settings from the specified ini file.
Definition: MojangAPI.cpp:301
cEvent m_StopEvent
Definition: Root.h:224
cWebAdmin * m_WebAdmin
Definition: Root.h:233
void QueueExecuteConsoleCommand(const AString &a_Cmd, cCommandOutputCallback &a_Output)
Queues a console command for execution through the cServer class.
Definition: Root.cpp:693
cWorld * GetWorld(const AString &a_WorldName)
Returns a pointer to the world specified.
Definition: Root.cpp:641
void StopServer()
Stops the server, as if "/stop" was typed in the console.
Definition: Root.cpp:370
static char PathSeparator()
Definition: File.h:42
const AString & GetName(void) const
Definition: Player.h:277
cRoot(void)
Definition: Root.cpp:55
static void InputThread(cRoot &a_Params)
Definition: Root.cpp:84
~cRoot()
Definition: Root.cpp:75
void UnloadWorlds(void)
Unloads all worlds from memory.
Definition: Root.cpp:618
static cRoot * s_Root
Definition: Root.h:273
Definition: Chunk.h:49
void RegisterAllBlockHandlers(BlockTypeRegistry &aRegistry)
Registers all the BlockHandler descendants in the specified registry.
void LOGERROR(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:183
cWorld * m_pDefaultWorld
Definition: Root.h:217
void AuthenticateUser(int a_ClientID, const AString &a_Name, const cUUID &a_UUID, const Json::Value &a_Properties)
Called by cAuthenticator to auth the specified user.
Definition: Root.cpp:747
std::thread m_InputThread
Definition: Root.h:223
void SendPlayerLists(cPlayer *a_DestPlayer)
Send playerlist of all worlds to player.
Definition: Root.cpp:794
Sends all command output to a log, line by line, when the command finishes processing.
Definition: CommandOutput.h:73
void GetChunkStats(int &a_NumValid, int &a_NumDirty, int &a_NumInLightingQueue)
Returns the number of chunks loaded and dirty, and in the lighting queue.
Definition: World.cpp:3121
Holds a palette that maps between block type + state and numbers.
Definition: UUID.h:10
Definition: Server.h:55
static bool m_TerminateEventRaised
If something has told the server to stop; checked periodically in cRoot.
Definition: Root.h:54
std::unique_ptr< cLogger::cListener > MakeConsoleListener(bool a_IsService)
std::vector< AString > AStringVector
Definition: StringUtils.h:14
Utilities to allow casting a cWorld to one of its interfaces without including World.h.
Definition: OpaqueWorld.h:12
static bool m_RunAsService
If set to true, binary will attempt to run as a service on Windows.
Definition: Root.h:55
std::pair< bool, std::unique_ptr< cLogger::cListener > > MakeFileListener()
static cLogger & GetInstance(void)
Definition: Logger.cpp:14
Container for a single chat message composed of multiple functional parts.
Definition: CompositeChat.h:31
void LoadWorlds(cDeadlockDetect &a_dd, cSettingsRepositoryInterface &a_Settings, bool a_IsNewIniFile)
Loads the worlds from settings.ini, creates the worldmap.
Definition: Root.cpp:446
void Wait(void)
Waits until the event has been set.
Definition: Event.cpp:24
bool ForEachPlayer(cPlayerListCallback a_Callback)
Calls the callback for each player in all worlds.
Definition: Root.cpp:854
void KickUser(int a_ClientID, const AString &a_Reason)
Kicks the user, no matter in what world they are.
Definition: Root.cpp:738
void Out(const char *a_Fmt, fmt::ArgList)
Syntax sugar function, calls Out() with Printf()-ed parameters; appends a newline".
void KickUser(int a_ClientID, const AString &a_Reason)
Definition: Server.cpp:656
Definition: World.h:65
void Stop(void)
Stops the HTTP server, if it was started.
Definition: WebAdmin.cpp:128
cFurnaceRecipe * m_FurnaceRecipe
Definition: Root.h:231
cCraftingRecipes * m_CraftingRecipes
Definition: Root.h:230
Loads the protocol-specific palettes on startup and provides them to the individual protocol instance...
static void Deinit()
void SaveAllChunks(void)
Saves all chunks in all worlds.
Definition: Root.cpp:770
void StartWorlds(cDeadlockDetect &a_DeadlockDetect)
Starts each world&#39;s life.
Definition: Root.cpp:592
void LOGINFO(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:165
int GetBurnTime(const cItem &a_Fuel) const
Returns the amount of time that the specified fuel burns, in ticks.
virtual AString GetKeyComment(const AString &keyname, const int commentID) const =0
Return a key comment, returns "" for repositories that do not return comments.
void LOGWARNING(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:174
bool DoWithPlayerByUUID(const cUUID &a_PlayerUUID, cPlayerListCallback a_Callback)
Finds the player over his uuid and calls the callback.
Definition: Root.cpp:925
#define LOGD(...)
Definition: LoggerSimple.h:40
virtual void AddValue(const AString &a_KeyName, const AString &a_ValueName, const AString &a_Value)=0
Adds a new value to the specified key.
bool FindAndDoWithPlayer(const AString &a_PlayerName, cPlayerListCallback a_Callback)
Finds a player from a partial or complete player name and calls the callback - case-insensitive.
Definition: Root.cpp:871
void ReloadPluginsNow(void)
Reloads all plugins, defaulting to settings.ini for settings location.
virtual AString GetValueSet(const AString &keyname, const AString &valuename, const AString &defValue="")=0
Gets the value; if not found, write the default to the repository.
size_t GetStorageSaveQueueLength(void)
Definition: World.h:952
void Stop(void)
Signals the thread to terminate and waits until it&#39;s finished.
Definition: IsThread.cpp:110
void Stop(void)
Stops the authenticator thread.
void BroadcastPlayerListsAddPlayer(const cPlayer &a_Player, const cClientHandle *a_Exclude=nullptr)
Broadcast playerlist addition through all worlds.
Definition: Root.cpp:806
The root of the object hierarchy.
Definition: Root.h:48
AString TrimString(const AString &str)
Trims whitespace at both ends of the string.
bool InitServer(cSettingsRepositoryInterface &a_Settings, bool a_ShouldAuth)
Definition: Server.cpp:166
bool CallHookWorldStarted(cWorld &a_World)
cWorld * GetDefaultWorld(void)
Definition: Root.cpp:632
std::atomic_flag m_InputThreadRunFlag
Definition: Root.h:225
cMojangAPI * m_MojangAPI
Definition: Root.h:236
void TickCommands(void)
Executes commands queued in the command queue.
Definition: Root.cpp:675
std::string AString
Definition: StringUtils.h:13
std::chrono::steady_clock::time_point m_StartTime
The current time where the startup of the server has been completed.
Definition: Root.h:111
void BroadcastPlayerListsRemovePlayer(const cPlayer &a_Player, const cClientHandle *a_Exclude=nullptr)
Broadcast playerlist removal through all worlds.
Definition: Root.cpp:818
const AString & GetName(void) const
Returns the name of the world.
Definition: World.h:874
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
static int GetFurnaceFuelBurnTime(const cItem &a_Fuel)
Returns the number of ticks for how long the item would fuel a furnace.
Definition: Root.cpp:1120
Sends all command output to a log, line by line; deletes self when command finishes processing...
Definition: CommandOutput.h:86
WorldMap m_WorldsByName
Definition: Root.h:218
std::unique_ptr< ProtocolPalettes > m_ProtocolPalettes
The per-protocol palettes manager.
Definition: Root.h:249
bool DoWithPlayer(const AString &a_PlayerName, cPlayerListCallback a_Callback)
Finds the player using it&#39;s complete username and calls the callback.
Definition: Root.cpp:941
static cRoot * Get()
Definition: Root.h:51
void LOG(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:156
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
int GetGeneratorQueueLength(void)
Definition: World.h:949
void SetSavingEnabled(bool a_SavingEnabled)
Sets whether saving chunks is enabled in all worlds (overrides however the worlds were already set) ...
Definition: Root.cpp:782
virtual bool DeleteKeyComment(const AString &keyname, const int commentID)=0
Delete a key comment, will always fail if the repository does not support comments.
NIBBLETYPE BlockNibbles[NumBlocks/2]
The type used for block data in nibble format, AXIS_ORDER ordering.
Definition: ChunkDef.h:153
cFurnaceRecipe * GetFurnaceRecipe(void)
Definition: Root.h:91
eMessageType
Definition: Defines.h:976
static AString GetProtocolVersionTextFromInt(int a_ProtocolVersionNum)
Returns the textual description of the protocol version: 49 -> "1.4.4".
Definition: Root.cpp:957
static AString GetVersionTextFromInt(int a_ProtocolVersion)
Translates protocol version number into protocol version text: 49 -> "1.4.4".
void TabCompleteUserName(const AString &a_Text, AStringVector &a_Results)
Appends all usernames starting with a_Text (case-insensitive) into Results.
Definition: World.cpp:3280
void Start(std::unique_ptr< cSettingsRepositoryInterface > a_OverridesRepo)
Definition: Root.cpp:134
cServer * m_Server
Definition: Root.h:227
bool Init(void)
Initializes the object.
Definition: WebAdmin.cpp:81
void StopWorlds(cDeadlockDetect &a_DeadlockDetect)
Stops each world&#39;s threads, so that it&#39;s safe to unload them.
Definition: Root.cpp:606
void LoadPalettes(const AString &aProtocolFolder)
Loads the upgrade palette and the per-protocol palettes.
Definition: Root.cpp:404
static int GetVirtualRAMUsage(void)
Returns the amount of virtual RAM used, in KiB.
Definition: Root.cpp:966
size_t RateCompareString(const AString &s1, const AString &s2)
Case-insensitive string comparison that returns a rating of equal-ness between [0 - s1...
HEIGHTTYPE HeightMap[Width *Width]
The type used for any heightmap operations and storage; idx = x + Width * z; Height points to the hig...
Definition: ChunkDef.h:142
size_t GetStorageLoadQueueLength(void)
Definition: World.h:951
std::unique_ptr< cBrewingRecipes > m_BrewingRecipes
Definition: Root.h:232
void LoadGlobalSettings()
Definition: Root.cpp:395
bool Start(void)
Starts the HTTP server taking care of the webadmin.
Definition: WebAdmin.cpp:110
Interface for a callback that receives command output The Out() function is called for any output the...
Definition: CommandOutput.h:13
AString StrToLower(const AString &s)
Returns a lower-cased copy of the string.
AStringVector GetPlayerTabCompletionMultiWorld(const AString &a_Text)
Returns the completions for a player name across all worlds.
Definition: Root.cpp:1130
EMCSBiome BiomeMap[Width *Width]
The type used for any biomemap operations and storage inside Cuberite, using Cuberite biomes (need no...
Definition: ChunkDef.h:147
std::unique_ptr< BlockTypePalette > m_UpgradeBlockTypePalette
The upgrade palette for pre-1.13 blocks.
Definition: Root.h:246
Definition: Item.h:36
const AString & GetShutdownMessage(void) const
Definition: Server.h:67
cCommandQueue m_PendingCommands
Definition: Root.h:221
void AuthenticateUser(int a_ClientID, const AString &a_Name, const cUUID &a_UUID, const Json::Value &a_Properties)
Authenticates the specified user, called by cAuthenticator.
Definition: Server.cpp:672
void Start(cSettingsRepositoryInterface &a_Settings)
Starts the authenticator thread.