Leviathan  0.8.0.0
Leviathan game engine
GameWorld.cpp
Go to the documentation of this file.
1 // ------------------------------------ //
2 #include "GameWorld.h"
3 
5 #include "Components.h"
6 #include "Engine.h"
7 #include "Handlers/IDFactory.h"
14 #include "Physics/PhysicalWorld.h"
17 #include "Rendering/Graphics.h"
18 #include "Rendering/Scene.h"
20 #include "Script/ScriptExecutor.h"
21 #include "ScriptComponentHolder.h"
22 #include "ScriptSystemWrapper.h"
23 #include "Sound/SoundDevice.h"
25 #include "Window.h"
26 
27 // Camera interpolation
28 #include "Generated/ComponentStates.h"
29 #include "StateInterpolator.h"
30 
31 #include "Exceptions.h"
32 
33 #include "bsfCore/Components/BsCCamera.h"
34 #include "bsfCore/Components/BsCLight.h"
35 #include "bsfCore/Components/BsCSkybox.h"
36 #include "bsfCore/Scene/BsSceneObject.h"
37 
38 using namespace Leviathan;
39 // ------------------------------------ //
41 public:
43  {
44  // Check that there are no external references to these
45  for(const auto& tuple : RegisteredScriptComponents) {
46 
47  if(tuple.second->GetRefCount() != 1) {
48 
49  LOG_FATAL("GameWorld: ImplRelease: RegisteredScriptComponent (holder): has "
50  "external refs, count: " +
51  std::to_string(tuple.second->GetRefCount()));
52  }
53  }
54  }
55 
56  std::map<std::string, ScriptComponentHolder::pointer> RegisteredScriptComponents;
57  std::map<std::string, std::unique_ptr<ScriptSystemWrapper>> RegisteredScriptSystems;
58 
60  std::vector<std::tuple<WantedClockType::time_point, ResponseEntityUpdate>>
62 
63  // BSF rendering resources
64  SceneNode::pointer WorldCameraSO;
65  bs::HCamera WorldCamera;
66 
67  bs::HSceneObject SunlightSO;
68  bs::HLight Sunlight;
69  bs::HSceneObject SkyboxSO;
70  bs::HSkybox Skybox;
71 
72  std::shared_ptr<PhysicsDebugDrawer> DebugDraw;
73 
74  Scene::pointer WorldScene;
75 };
76 // ------------------------------------ //
77 DLLEXPORT GameWorld::GameWorld(int32_t worldtype,
78  const std::shared_ptr<PhysicsMaterialManager>& physicsMaterials, int worldid /*= -1*/) :
79  pimpl(std::make_unique<Implementation>()),
80  PhysicsMaterials(physicsMaterials), ID(worldid >= 0 ? worldid : IDFactory::GetID()),
81  WorldType(worldtype)
82 {}
83 
85 {
86  // (*WorldDestroyed) = true;
87 
88  // Assert if all objects haven't been released already.
89  // We can't call virtual methods here anymore
90  // This can be hit in tests quite easily if something throws an exception
92  Entities.empty(), "GameWorld: Entities not empty in destructor. Was Release called?");
93 }
94 // ------------------------------------ //
95 DLLEXPORT bool GameWorld::Init(const WorldNetworkSettings& network, Graphics* graphics)
96 {
97  NetworkSettings = network;
98 
99  // Detecting non-GUI mode //
100  if(graphics) {
101 
102  GraphicalMode = true;
103  // these are always required for worlds //
104  _CreateRenderingResources(graphics);
105  } else {
106 
107  GraphicalMode = false;
108  InBackground = false;
109  }
110 
111  // Acquire physics engine world only if we have been given physical materials indicating
112  // that physics is wanted
113  if(PhysicsMaterials) {
114 
115  _PhysicalWorld = std::make_shared<PhysicalWorld>(this, PhysicsMaterials.get());
116  }
117 
118  _DoSystemsInit();
119  return true;
120 }
121 
123 {
124  // Skip duplicate release
125  if(!pimpl)
126  return;
127 
129 
130  // (*WorldDestroyed) = true;
131 
132  ReceivingPlayers.clear();
133 
134  // release objects //
135  // TODO: allow objects to know that they are about to get killed
136 
137  // As all objects are just pointers to components we can just dump the objects
138  // and once the component pools are released
139  ClearEntities();
140 
141  if(GraphicalMode) {
142  // TODO: notify our window that it no longer has anything rendering on it
143  LinkedToWindow = nullptr;
144 
145  _DestroyRenderingResources();
146  }
147 
148  // This should be relatively cheap if the newton threads don't deadlock while waiting
149  // for each other
150  _PhysicalWorld.reset();
151 
152  // Let go of our these resources
153  pimpl.reset();
154 }
155 // ------------------------------------ //
156 void GameWorld::_CreateRenderingResources(Graphics* graphics)
157 {
158  // // create scene manager //
159  // // Let's do what the Ogre samples do and use a bunch of threads for culling
160  // const auto threads = std::max(2, static_cast<int>(std::thread::hardware_concurrency()));
161 
162  // // TODO: allow configuring scene type (the type was: Ogre::ST_EXTERIOR_FAR before)
163  pimpl->WorldScene = Scene::MakeShared<Scene>();
164 
165  // Camera
166  pimpl->WorldCameraSO = pimpl->WorldScene->CreateSceneNode();
167  pimpl->WorldCamera = pimpl->WorldCameraSO->GetInternal()->addComponent<bs::CCamera>();
168  pimpl->WorldCamera->setHorzFOV(bs::Degree(90));
169 
170  pimpl->WorldCamera->setLayers(1 << pimpl->WorldScene->GetInternal());
171 
172  // TODO: allow changing and setting infinite
173  pimpl->WorldCamera->setFarClipDistance(5000);
174  // // enable infinite far clip distance if supported //
175  // if(ogre->getRenderSystem()->getCapabilities()->hasCapability(
176  // Ogre::RSC_INFINITE_FAR_PLANE)) {
177 
178  // WorldSceneCamera->setFarClipDistance(0); Maybe for bsf this needs to be float::max
179  // }
180 
181  // Custom projection matrix
182  pimpl->WorldCamera->setCustomProjectionMatrix(true,
184  LinkedToWindow ? LinkedToWindow->GetAspectRatio() : 1280 / 720.f, 0.1f, 5000.f));
185 
186 
187  auto values = Engine::Get()->GetDefinition()->GetValues();
188 
189 
190  // TODO: move to a better settings class and realtime updates for settings
191  bool disableIndirectLighting, disableAmbientOcclusion, disableFXAA, disableShadows,
192  disableLighting;
193 
194  ObjectFileProcessor::LoadValueFromNamedVars<bool>(
195  values, "DisableIndirectLighting", disableIndirectLighting, false);
196  ObjectFileProcessor::LoadValueFromNamedVars<bool>(
197  values, "DisableAmbientOcclusion", disableAmbientOcclusion, false);
198  ObjectFileProcessor::LoadValueFromNamedVars<bool>(
199  values, "DisableFXAA", disableFXAA, false);
200  ObjectFileProcessor::LoadValueFromNamedVars<bool>(
201  values, "DisableShadows", disableShadows, false);
202  ObjectFileProcessor::LoadValueFromNamedVars<bool>(
203  values, "DisableLighting", disableLighting, false);
204 
205  int MSAACount;
206 
207  ObjectFileProcessor::LoadValueFromNamedVars<int>(values, "MSAACount", MSAACount, 1);
208 
209 
210  pimpl->WorldCamera->setMSAACount(1);
211 
212  const auto& settings = pimpl->WorldCamera->getRenderSettings();
213 
214  // Needed. non default option
215  if(!disableIndirectLighting) {
216  settings->enableIndirectLighting = true;
217  } else {
218  settings->enableIndirectLighting = false;
219  }
220 
221  if(disableAmbientOcclusion)
222  settings->ambientOcclusion.enabled = false;
223 
224  // settings->autoExposure;
225  // settings->bloom;
226  // settings->bloom.enabled = false;
227  // settings->colorGrading;
228  // settings->depthOfField.enabled = false;
229  // settings->screenSpaceLensFlare;
230  // settings->screenSpaceReflections;
231  // settings->shadowSettings;
232  // settings->tonemapping;
233  // settings->whiteBalance;
234  // settings->enableAutoExposure = false;
235  if(disableFXAA)
236  settings->enableFXAA = false;
237  // settings->enableHDR = false;
238  if(disableLighting)
239  settings->enableLighting = false;
240 
241  if(disableShadows)
242  settings->enableShadows = false;
243  // settings->enableSkybox = false;
244  // settings->enableTonemapping = false;
245 
246 
247  pimpl->WorldCamera->setRenderSettings(settings);
248 
249  // Default sun
250  SetSunlight();
251 }
252 
253 void GameWorld::_DestroyRenderingResources()
254 {
255  if(!pimpl)
256  return;
257 
258  RemoveSunlight();
259 
260  if(pimpl->WorldCameraSO) {
261  pimpl->WorldScene->DestroySceneNode(pimpl->WorldCameraSO);
262  pimpl->WorldCameraSO = nullptr;
263  pimpl->WorldCamera = nullptr;
264  }
265 
266  pimpl->WorldScene = nullptr;
267 }
268 // ------------------------------------ //
269 static bool SunCreated = false;
270 
272 {
273  if(SunCreated) {
274  LOG_WRITE("TODO: multi scene support in BSF needed for separate world lights");
275  return;
276  }
277 
278  SunCreated = true;
279 
280  // Create/update things if they are nullptr //
281  if(!pimpl->SunlightSO) {
282 
283  pimpl->SunlightSO = bs::SceneObject::create("Sunlight");
284  pimpl->Sunlight = pimpl->SunlightSO->addComponent<bs::CLight>();
285  // Oh no! this method does not exist
286  // pimpl->Sunlight->setLayer
287  }
288 
289  // Default properties
290  pimpl->Sunlight->setType(bs::LightType::Directional);
291 
292  SetLightProperties(Float3(1, 1, 1));
293 }
294 
296 {
297  if(pimpl->SunlightSO) {
298  pimpl->SunlightSO->destroy();
299  pimpl->SunlightSO = nullptr;
300  pimpl->Sunlight = nullptr;
301  SunCreated = false;
302  }
303 }
304 
305 DLLEXPORT void GameWorld::SetSkybox(const std::string& skyboxname, float brightness /*= 1.f*/)
306 {
307  if(!pimpl->SkyboxSO) {
308  if(skyboxname.empty())
309  return;
310 
311  pimpl->SkyboxSO = bs::SceneObject::create("Skybox");
312  pimpl->Skybox = pimpl->SkyboxSO->addComponent<bs::CSkybox>();
313  // Oh no! this method does not exist
314  // pimpl->Skybox->setLayer
315  }
316 
317  if(!skyboxname.empty()) {
318 
319  auto texture = Engine::Get()->GetGraphics()->LoadTextureByName(skyboxname);
320 
321  if(!texture) {
322 
323  LOG_ERROR("GameWorld: SetSkybox: could not load skybox texture with the name: " +
324  skyboxname);
325  return;
326  }
327 
328  pimpl->Skybox->setTexture(texture);
329  pimpl->Skybox->setBrightness(brightness);
330 
331  } else {
332 
333  pimpl->Skybox->setTexture(nullptr);
334  pimpl->Skybox->setBrightness(0);
335  }
336 }
337 
338 DLLEXPORT void GameWorld::SetLightProperties(const Float3& colour, float intensity,
339  const Float3& direction, float sourceradius, bool castsshadows)
340 {
341  if(!pimpl->SunlightSO) {
342 
343  LOG_ERROR("GameWorld: SetLightProperties: world doesn't have sun light set");
344  return;
345  }
346 
347  pimpl->Sunlight->setColor(bs::Color(colour.X, colour.Y, colour.Z));
348  pimpl->Sunlight->setIntensity(intensity);
349  pimpl->Sunlight->setSourceRadius(sourceradius);
350  pimpl->Sunlight->setCastsShadow(castsshadows);
351 
352  // pimpl->SunlightSO->setPosition(bs::Vector3(1, 20, 1));
353  // pimpl->SunlightSO->setPosition(bs::Vector3(20, 15, 20));
354  pimpl->SunlightSO->setPosition(-direction);
355 
356  pimpl->SunlightSO->lookAt(bs::Vector3(0, 0, 0));
357  // pimpl->SunlightSO->setWorldRotation(const Quaternion &rotation)
358 
359  // TODO: scene ambient colour
360 
361  // Set scene ambient colour //
362  // TODO: Ogre samples also use this so maybe this works with PBR HLMS system
363  // WorldsScene->setAmbientLight(Ogre::ColourValue(0.3f, 0.5f, 0.7f) * 0.1f * 0.75f,
364  // Ogre::ColourValue(0.6f, 0.45f, 0.3f) * 0.065f * 0.75f,
365  // -Sunlight->getDirection() + Ogre::Vector3::UNIT_Y * 0.2f);
366 }
367 // ------------------------------------ //
368 DLLEXPORT void GameWorld::SetAutoExposure(float mineyeadaptation, float maxeyeadaptation,
369  float eyeadaptationspeeddown, float eyeadaptationspeedup, float histogramlog2max,
370  float histogramlog2min, float histogrampcthigh, float histogrampctlow)
371 {
372  const auto& settings = pimpl->WorldCamera->getRenderSettings();
373 
374  settings->autoExposure.eyeAdaptationSpeedDown = eyeadaptationspeeddown;
375  settings->autoExposure.eyeAdaptationSpeedUp = eyeadaptationspeedup;
376  settings->autoExposure.maxEyeAdaptation = maxeyeadaptation;
377  settings->autoExposure.minEyeAdaptation = mineyeadaptation;
378 
379  settings->autoExposure.histogramLog2Max = histogramlog2max;
380  settings->autoExposure.histogramLog2Min = histogramlog2min;
381  settings->autoExposure.histogramPctHigh = histogrampcthigh;
382  settings->autoExposure.histogramPctLow = histogrampctlow;
383 
384  settings->enableAutoExposure = false;
385 
386  pimpl->WorldCamera->setRenderSettings(settings);
387 }
388 
389 // ------------------------------------ //
390 DLLEXPORT void GameWorld::Render(float elapsed)
391 {
392  if(InBackground) {
393 
394  LOG_ERROR("GameWorld: Render: called while world is in the background (not attached"
395  "to a window)");
396  return;
397  }
398 
399  RunFrameRenderSystems(elapsed);
400 
401  // Read camera entity and update position //
402 
403  // Skip if no camera //
404  if(CameraEntity == 0)
405  return;
406 
407  try {
408  Camera& properties = GetComponent<Camera>(CameraEntity);
409 
410  Position& position = GetComponent<Position>(CameraEntity);
411 
412  auto& states = GetStatesFor<Position>();
413 
414  // set camera position //
415  // TODO: this interpolation here is likely unneeded as the client side world should set
416  // the Position data from the states. This would only work on a hybrid client server
417  // that is running on fixed ticks not related to rendering (but that feels laggy)
418  const auto interpolated =
419  StateInterpolator::Interpolate(states, CameraEntity, &position, elapsed);
420 
421  if(!std::get<0>(interpolated)) {
422 
423  // No interpolated pos //
424  pimpl->WorldCameraSO->SetPosition(position.Members._Position);
425  pimpl->WorldCameraSO->SetOrientation(position.Members._Orientation);
426 
427  } else {
428 
429  const auto& interpolatedPos = std::get<1>(interpolated);
430  pimpl->WorldCameraSO->SetPosition(interpolatedPos._Position);
431  pimpl->WorldCameraSO->SetOrientation(interpolatedPos._Orientation);
432  }
433 
434  if(properties.SoundPerceiver) {
435 
437  position.Members._Position, position.Members._Orientation);
438  }
439 
440  if(properties.Marked || AppliedCameraPropertiesPtr != &properties) {
441 
442  AppliedCameraPropertiesPtr = &properties;
443 
444  FOV = properties.FOV;
445 
446  pimpl->WorldCamera->setCustomProjectionMatrix(
448  LinkedToWindow ? LinkedToWindow->GetAspectRatio() : 1280 / 720.f,
449  0.1f, 5000.f));
450 
451  // pimpl->WorldCamera->setHorzFOV(bs::Degree(properties.FOV));
452 
453  properties.Marked = false;
454  }
455 
456  } catch(const Exception& e) {
457 
458  LOG_ERROR("GameWorld: Render: camera update failed. Was a component removed?, "
459  "exception:");
460  e.PrintToLog();
461  CameraEntity = 0;
462  }
463 
464  // Finalize world positions for scene nodes
465  if(pimpl && pimpl->WorldScene)
466  pimpl->WorldScene->PrepareForRendering();
467 }
468 // ------------------------------------ //
470 {
471  CameraEntity = object;
472 
473  AppliedCameraPropertiesPtr = nullptr;
474 
475  if(CameraEntity == NULL_OBJECT)
476  return;
477 
478  // Check components //
479  try {
480  GetComponent<Camera>(object);
481  } catch(const NotFound&) {
482 
483  throw InvalidArgument("SetCamera object is missing a needed component (Camera)");
484  }
485 
486  try {
487  GetComponent<Position>(object);
488  } catch(const NotFound&) {
489 
490  throw InvalidArgument("SetCamera object is missing a needed component (Position)");
491  }
492 }
493 
495 {
496  // Fail if there is no active camera //
497  if(CameraEntity == NULL_OBJECT)
498  throw InvalidState("This world has no active CameraEntity");
499 
500  if(!pimpl->WorldCamera)
501  throw InvalidState("This world has no initialized camera resources");
502 
503  // Read the latest set data from the camera
504  // TODO: could jump to the actual latest position here if wanted
505  return pimpl->WorldCamera->screenPointToRay(bs::Vector2I(x, y));
506 }
507 
509 {
510  return pimpl->WorldCameraSO.get();
511 }
512 
514 {
515  LEVIATHAN_ASSERT(pimpl, "GameWorld::GetScene called after releasing");
516  return pimpl->WorldScene.get();
517 }
518 
520 {
521  Scene* scene = pimpl->WorldScene.get();
522  if(scene)
523  scene->AddRef();
524  return scene;
525 }
526 // ------------------------------------ //
528 {
529  if(_PhysicalWorld && LinkedToWindow) {
530  pimpl->DebugDraw = std::make_shared<PhysicsDebugDrawer>(*LinkedToWindow, *this);
531 
532  _PhysicalWorld->SetDebugDrawer(pimpl->DebugDraw);
533  }
534 }
535 
537 {
538  if(_PhysicalWorld) {
539 
540  // Clear the contents
541  if(pimpl->DebugDraw)
542  pimpl->DebugDraw->OnBeginDraw();
543 
544  _PhysicalWorld->SetDebugDrawer(nullptr);
545  }
546 }
547 // ------------------------------------ //
549  Position& atposition, Connection& connection)
550 {
551  return true;
552 }
553 
555 {
556  for(auto& player : ReceivingPlayers) {
557 
558  if(player->GetConnection().get() == &connection) {
559 
560  return true;
561  }
562  }
563 
564  return false;
565 }
566 
567 DLLEXPORT void GameWorld::SetPlayerReceiveWorld(std::shared_ptr<ConnectedPlayer> ply)
568 {
569  // Skip if already added //
570  for(auto& player : ReceivingPlayers) {
571 
572  if(player == ply) {
573 
574  return;
575  }
576  }
577 
578  LOG_INFO("GameWorld: player(\"" + ply->GetNickname() + "\") is now receiving world");
579 
580  // Add them to the list of receiving players //
581  ReceivingPlayers.push_back(ply);
582 
583  if(!ply->GetConnection()->IsValidForSend()) {
584 
585  // The closing should be handled by somebody else
586  Logger::Get()->Error("GameWorld: requested to sync with a player who has closed their "
587  "connection");
588 
589  return;
590  }
591 
592  {
593  // Start world receive information
594  ply->GetConnection()->SendPacketToConnection(
595  std::make_shared<ResponseStartWorldReceive>(0, ID, WorldType),
597  }
598 
599  // Update the position data //
600  UpdatePlayersPositionData(*ply);
601 
602  // Start sending initial update //
603  Logger::Get()->Info(
604  "Starting to send " + Convert::ToString(Entities.size()) + " to player");
605 
606  // Now we can queue all objects for sending //
607  // TODO: make sure that all objects are sent
608  // TODO: redo this inside the world tick
609  // ThreadingManager::Get()->QueueTask(
610  // new RepeatCountedTask(std::bind<void>([](
611  // std::shared_ptr<Connection> connection,
612  // std::shared_ptr<ConnectedPlayer> processingobject, GameWorld* world,
613  // std::shared_ptr<bool> WorldInvalid)
614  // -> void
615  // {
616  // // Get the next object //
617  // RepeatCountedTask* task =
618  // dynamic_cast<RepeatCountedTask*>(TaskThread::GetThreadSpecificThreadObject()->
619  // QuickTaskAccess.get());
620 
621  // LEVIATHAN_ASSERT(task, "wrong type passed to our task");
622 
623  // size_t num = task->GetRepeatCount();
624 
625  // if(*WorldInvalid){
626 
627  // taskstopprocessingobjectsforinitialsynclabel:
628 
629  // // Stop processing //
630  // task->StopRepeating();
631  // return;
632  // }
633 
634  // // Stop if out of bounds //
635  // if(num >= world->Entities.size()){
636 
637  // goto taskstopprocessingobjectsforinitialsynclabel;
638  // }
639 
640  // // Get the object //
641  // auto tosend = world->Entities[num];
642 
643  // // Skip if shouldn't send //
644  // try{
645 
646  // auto& position = world->GetComponent<Position>(tosend);
647 
648  // if(!world->ShouldPlayerReceiveObject(position, *connection)){
649 
650  // return;
651  // }
652 
653  // } catch(const NotFound&){
654 
655  // // No position, should probably always send //
656  // }
657 
658 
659  // // Send it //
660  // world->SendObjectToConnection(guard, tosend, connection);
661 
662  // return;
663 
664  // }, ply->GetConnection(), ply, this, WorldDestroyed), Entities.size()));
665 }
666 
668  const std::shared_ptr<NetworkResponse>& response, RECEIVE_GUARANTEE guarantee) const
669 {
670  // Notify everybody that an entity has been destroyed //
671  for(auto iter = ReceivingPlayers.begin(); iter != ReceivingPlayers.end(); ++iter) {
672 
673  auto safe = (*iter)->GetConnection();
674 
675  if(!safe->IsValidForSend()) {
676  // Player has probably closed their connection //
677  continue;
678  }
679 
680  safe->SendPacketToConnection(response, guarantee);
681  }
682 }
683 // ------------------------------------ //
685 
687 {
688  return 0;
689 }
690 
692  ObjectID id, sf::Packet& data, int entriesleft, int decodedtype)
693 {
694  if(entriesleft < 1)
695  return;
696 
697  LOG_ERROR("GameWorld: entity static state decoding was not complete before calling base "
698  "GameWorld implementation. Received entity won't be fully constructed");
699 }
700 
702  ObjectID id, int32_t ticknumber, sf::Packet& data, int32_t referencetick, int decodedtype)
703 {
704  LOG_ERROR(
705  "GameWorld: entity component state decoding was not complete before calling base "
706  "GameWorld implementation. Not all states have been decoded");
707 }
708 
710  ObjectID id, int32_t ticknumber, sf::Packet& data, int32_t referencetick, int decodedtype)
711 {
712  LOG_ERROR("GameWorld: entity component state decoding for local control was not complete "
713  "before calling base GameWorld implementation");
714 }
715 // ------------------------------------ //
716 DLLEXPORT void GameWorld::Tick(float elapsed)
717 {
718  if(InBackground && !TickWhileInBackground && GraphicalMode)
719  return;
720 
721  // Apply queued packets //
723 
724  _HandleDelayedDelete();
725 
726  // All required nodes for entities are created //
729 
730  // Remove closed player connections //
731 
732  for(auto iter = ReceivingPlayers.begin(); iter != ReceivingPlayers.end();) {
733 
734  if(!(*iter)->GetConnection()->IsValidForSend()) {
735 
736  LOG_INFO("GameWorld: a player has diconnected, removing. TODO: release Sendable "
737  "memory");
738  // DEBUG_BREAK;
739  iter = ReceivingPlayers.erase(iter);
740  } else {
741 
742  ++iter;
743  }
744  }
745 
746  // TODO: even while paused sendable objects may need to retransmit stuff
747 
748  if(Paused)
749  return;
750 
751  TotalElapsed += elapsed;
752 
753  // Set this to disallow deleting while running physics as well
754  TickInProgress = true;
755 
756  // Simulate physics //
757  if(!WorldFrozen) {
758 
759  // TODO: a game type that is a client and server at the same time
760  // if(IsOnServer) {
761 
762  // _ApplyEntityUpdatePackets();
763  if(_PhysicalWorld)
764  _PhysicalWorld->SimulateWorld(elapsed);
765 
766  // } else {
767 
768  // Simulate direct control //
769  // }
770  }
771 
772  _RunTickSystems(elapsed);
773 
774  TickInProgress = false;
775 
776  // Sendable objects may need something to be done //
777 
778  if(NetworkSettings.IsAuthoritative) {
779 
780  // Notify new entities //
781  // DEBUG_BREAK;
782 
783  // Skip if not tick that will be stored //
784  // if(TickNumber % WORLD_OBJECT_UPDATE_CLIENTS_INTERVAL == 0){
785 
786  // _SendableSystem.Run(ComponentSendable.GetIndex(), *this);
787  // }
788 
789  } else {
790 
791  // TODO: direct control objects
792  // _ReceivedSystem.Run(ComponentReceived.GetIndex(), *this);
793  }
794 }
795 // ------------------------------------ //
797 {
798  // We are responsible for script systems //
799  for(auto iter = pimpl->RegisteredScriptSystems.begin();
800  iter != pimpl->RegisteredScriptSystems.end(); ++iter) {
801 
802  iter->second->CreateAndDestroyNodes();
803  }
804 }
805 
807 {
808  // We are responsible for script components //
809  for(auto iter = pimpl->RegisteredScriptComponents.begin();
810  iter != pimpl->RegisteredScriptComponents.end(); ++iter) {
811 
812  iter->second->ClearAdded();
813  iter->second->ClearRemoved();
814  }
815 }
816 // ------------------------------------ //
818 {
819  // Skip double Release
820  if(!pimpl)
821  return;
822 
823  // We are responsible for script systems //
824  for(auto iter = pimpl->RegisteredScriptSystems.begin();
825  iter != pimpl->RegisteredScriptSystems.end(); ++iter) {
826 
827  iter->second->Clear();
828  }
829 }
830 
832 {
833  // Skip double Release
834  if(!pimpl)
835  return;
836 
837  // We are responsible for script components //
838  for(auto iter = pimpl->RegisteredScriptComponents.begin();
839  iter != pimpl->RegisteredScriptComponents.end(); ++iter) {
840 
841  iter->second->ReleaseAllComponents();
842  }
843 }
844 // ------------------------------------ //
846 {
847  // Don't have any systems, but these updates may be important for interpolation //
848  // _ApplyEntityUpdatePackets();
849 
850  // TODO: if there are any impactful simulation done here it needs to be also inside a block
851  // where TickInProgress is set to true
852 }
853 
855 {
856  // We are responsible for script systems //
857  for(auto iter = pimpl->RegisteredScriptSystems.begin();
858  iter != pimpl->RegisteredScriptSystems.end(); ++iter) {
859 
860  iter->second->Run(elapsed);
861  }
862 }
863 // ------------------------------------ //
864 // Object managing
866 {
867  if(!GetNetworkSettings().IsAuthoritative) {
868  // Clients create high number entities. This is not optimal but good enough for now
869  auto id = (1 << 31) | static_cast<ObjectID>(IDFactory::GetID());
870 
871  Entities.push_back(id);
872 
873  return id;
874 
875  } else {
876  auto id = static_cast<ObjectID>(IDFactory::GetID());
877 
878  Entities.push_back(id);
879 
880  if(NetworkSettings.IsAuthoritative) {
881  // NewlyCreatedEntities.push_back(id);
882 
883  if(NetworkSettings.AutoCreateNetworkComponents) {
885  }
886  }
887 
888  return id;
889  }
890 }
891 // ------------------------------------ //
893 {
894  // Release objects //
895  Entities.clear();
896  Parents.clear();
897  // This shouldn't be used all that much so release the memory
898  Parents.shrink_to_fit();
899 
900  // Clear all nodes //
901  _ResetSystems();
902 
903  // Clears all components
904  // Runs Release on components that need it
906 
907  // Notify everybody that all entities are discarded //
908  for(auto iter = ReceivingPlayers.begin(); iter != ReceivingPlayers.end(); ++iter) {
909 
910  auto safe = (*iter)->GetConnection();
911 
912  if(!safe->IsValidForSend()) {
913  // Player has probably closed their connection //
914  continue;
915  }
916 
917  Logger::Get()->Write("TODO: send world clear message");
918  DEBUG_BREAK;
919  }
920 }
921 // ------------------------------------ //
922 // DLLEXPORT Float3 GameWorld::GetGravityAtPosition(const Float3& pos)
923 // {
924 // // \todo take position into account //
925 // // create force without mass applied //
926 // return Float3(0.f, PHYSICS_BASE_GRAVITY, 0.f);
927 // }
928 // ------------------------------------ //
929 DLLEXPORT int GameWorld::GetPhysicalMaterial(const std::string& name)
930 {
931  if(!PhysicsMaterials)
932  return -1;
933 
934  return PhysicsMaterials->GetMaterialID(name);
935 }
936 // ------------------------------------ //
938 {
939  // Fail if trying to delete NULL_OBJECT
940  if(id == NULL_OBJECT)
941  throw InvalidArgument("Cannot destroy NULL_OBJECT");
942 
943  // Fail if ticking currently //
944  if(TickInProgress)
945  throw InvalidState(
946  "Cannot DestroyEntity while ticking. Use QueueDestroyEntity instead");
947 
948  for(auto iter = Entities.begin(); iter != Entities.end(); ++iter) {
949 
950  if(*iter == id) {
951 
952  Entities.erase(iter);
953  _DoDestroy(id);
954  return;
955  }
956  }
957 
958  LOG_ERROR("GameWorld: DestroyEntity: unknown entity id: " + std::to_string(id));
959 }
960 
962 {
963  // Fail if trying to delete NULL_OBJECT
964  if(id == NULL_OBJECT)
965  throw InvalidArgument("Cannot destroy NULL_OBJECT");
966 
967  // This is a sanity check, can be disabled (or made cheaper when the world no longer uses
968  // IDFactory) when crashing stops
969  bool exists = false;
970 
971  for(auto existingId : Entities) {
972  if(existingId == id) {
973  exists = true;
974  break;
975  }
976  }
977 
978  if(!exists) {
979  LOG_ERROR("GameWorld: QueueDestroyEntity: unknown entity id: " + std::to_string(id));
980  return;
981  }
982 
983  Lock lock(DeleteMutex);
984 
985  // Skip duplicates
986  for(auto alreadyQueued : DelayedDeleteIDS)
987  if(id == alreadyQueued)
988  return;
989 
990  DelayedDeleteIDS.push_back(id);
991 }
992 
993 void GameWorld::_HandleDelayedDelete()
994 {
995  // We might want to delete everything //
996  if(ClearAllEntities) {
997 
998  ClearEntities();
999 
1000  ClearAllEntities = false;
1001 
1002  Lock lock(DeleteMutex);
1003  DelayedDeleteIDS.clear();
1004 
1005  // All are now cleared //
1006  return;
1007  }
1008 
1009  Lock lock(DeleteMutex);
1010 
1011  // Return right away if no objects to delete //
1012  if(DelayedDeleteIDS.empty())
1013  return;
1014 
1015  // Search all objects and find the ones that need to be deleted //
1016  for(auto iter = Entities.begin(); iter != Entities.end();) {
1017 
1018  // Check does id match any //
1019  auto curid = *iter;
1020  bool delthis = false;
1021 
1022  for(auto iterids = DelayedDeleteIDS.begin(); iterids != DelayedDeleteIDS.end();) {
1023 
1024  if(*iterids == curid) {
1025  // Remove this as it will get deleted //
1026  delthis = true;
1027  DelayedDeleteIDS.erase(iterids);
1028  break;
1029 
1030  } else {
1031  ++iterids;
1032  }
1033  }
1034 
1035  if(delthis) {
1036 
1037  _DoDestroy(curid);
1038  iter = Entities.erase(iter);
1039 
1040  // Check for end //
1041  if(DelayedDeleteIDS.empty())
1042  return;
1043 
1044  } else {
1045  ++iter;
1046  }
1047  }
1048 }
1049 
1050 void GameWorld::_DoDestroy(ObjectID id)
1051 {
1052  // LOG_INFO("GameWorld destroying object " + Convert::ToString(id));
1053 
1054  if(NetworkSettings.IsAuthoritative)
1055  _ReportEntityDestruction(id);
1056 
1057  // TODO: find a better way to do this
1058  DestroyAllIn(id);
1059 
1060  // Parent destroy children //
1061  // We need to support recursively parented entities
1062  for(size_t i = 0; i < Parents.size();) {
1063 
1064  if(std::get<0>(Parents[i]) == id) {
1065 
1066  const auto childId = std::get<1>(Parents[i]);
1067 
1068  // Remove it //
1069  std::swap(Parents[i], Parents[Parents.size() - 1]);
1070  Parents.pop_back();
1071 
1072  // And then destroy //
1073  // LOG_WRITE("Destroying child ID: " + std::to_string(childId));
1074  DestroyEntity(childId);
1075 
1076  // To support recursively parented we go back to the start to scan again
1077  i = 0;
1078 
1079  } else if(std::get<1>(Parents[i]) == id) {
1080  // Child has been destroyed //
1081  // Remove it //
1082  std::swap(Parents[i], Parents[Parents.size() - 1]);
1083  Parents.pop_back();
1084 
1085  } else {
1086  ++i;
1087  }
1088  }
1089 }
1090 // ------------------------------------ //
1092 {
1093  Parents.push_back(std::make_tuple(parent, child));
1094 }
1095 // ------------------------------------ //
1097 {
1098  return std::make_tuple(nullptr, false);
1099 }
1100 
1101 DLLEXPORT std::tuple<void*, ComponentTypeInfo, bool> GameWorld::GetComponentWithType(
1102  ObjectID id, COMPONENT_TYPE type)
1103 {
1104  return std::make_tuple(nullptr, ComponentTypeInfo(-1, -1), false);
1105 }
1106 
1107 DLLEXPORT std::tuple<void*, bool> GameWorld::GetStatesFor(COMPONENT_TYPE type)
1108 {
1109  return std::make_tuple(nullptr, false);
1110 }
1111 
1113  COMPONENT_TYPE type, std::vector<std::tuple<void*, ObjectID>>& result)
1114 {
1115  return false;
1116 }
1117 
1119  const std::string& name, std::vector<std::tuple<asIScriptObject*, ObjectID>>& result)
1120 {
1121  auto iter = pimpl->RegisteredScriptComponents.find(name);
1122 
1123  if(iter == pimpl->RegisteredScriptComponents.end())
1124  return false;
1125 
1126  auto& removed = iter->second->GetRemoved();
1127 
1128  result.insert(std::end(result), std::begin(removed), std::end(removed));
1129  return true;
1130 }
1131 
1133  COMPONENT_TYPE type, std::vector<std::tuple<void*, ObjectID, ComponentTypeInfo>>& result)
1134 {
1135  return false;
1136 }
1137 
1138 DLLEXPORT bool GameWorld::GetAddedForScriptDefined(const std::string& name,
1139  std::vector<std::tuple<asIScriptObject*, ObjectID, ScriptComponentHolder*>>& result)
1140 {
1141  auto iter = pimpl->RegisteredScriptComponents.find(name);
1142 
1143  if(iter == pimpl->RegisteredScriptComponents.end())
1144  return false;
1145 
1146  auto& added = iter->second->GetAdded();
1147 
1148  result.reserve(result.size() + added.size());
1149 
1150  for(const auto& tuple : added) {
1151 
1152  result.push_back(
1153  std::make_tuple(std::get<0>(tuple), std::get<1>(tuple), iter->second.get()));
1154  }
1155 
1156  return true;
1157 }
1158 
1159 // ------------------------------------ //
1161 {
1162  // Script systems are initialized as they are created
1163 }
1164 
1166 {
1167  // This can be called after Releasing once already
1168  if(!pimpl)
1169  return;
1170 
1171  // We are responsible for script systems //
1172  for(auto iter = pimpl->RegisteredScriptSystems.begin();
1173  iter != pimpl->RegisteredScriptSystems.end(); ++iter) {
1174 
1175  iter->second->Release();
1176  }
1177 
1178  pimpl->RegisteredScriptSystems.clear();
1179 }
1180 
1182 {
1183  // We are responsible for script systems //
1184  for(auto iter = pimpl->RegisteredScriptSystems.begin();
1185  iter != pimpl->RegisteredScriptSystems.end(); ++iter) {
1186 
1187  iter->second->Suspend();
1188  }
1189 }
1190 
1192 {
1193  // We are responsible for script systems //
1194  for(auto iter = pimpl->RegisteredScriptSystems.begin();
1195  iter != pimpl->RegisteredScriptSystems.end(); ++iter) {
1196 
1197  iter->second->Resume();
1198  }
1199 }
1200 
1202 {
1203  LOG_ERROR("GameWorld: base version of _CreateSendableComponentForEntity, this shouldn't "
1204  "happen with correct configuration");
1205 }
1206 
1208 {
1209  LOG_ERROR("GameWorld: base version of _CreateReceivedComponentForEntity, this shouldn't "
1210  "happen with correct configuration");
1211 }
1212 
1213 // ------------------------------------ //
1215 {
1216  // This can be called after Releasing once already
1217  if(!pimpl)
1218  return;
1219 
1220  // Handle script types
1221  for(auto iter = pimpl->RegisteredScriptComponents.begin();
1222  iter != pimpl->RegisteredScriptComponents.end(); ++iter) {
1223 
1224  // Just try to remove like the normal c++ components until there is a better way
1225  iter->second->ReleaseComponent(id);
1226  }
1227 }
1228 // ------------------------------------ //
1229 void GameWorld::_ReportEntityDestruction(ObjectID id)
1230 {
1231  SendToAllPlayers(std::make_shared<ResponseEntityDestruction>(0, this->ID, id),
1233 }
1234 // ------------------------------------ //
1236 {
1237  // Skip if set to the same //
1238  if(frozen == WorldFrozen)
1239  return;
1240 
1241  WorldFrozen = frozen;
1242 
1243  // Send it to receiving players (if we are a server) //
1244  if(ReceivingPlayers.empty())
1245  return;
1246 
1247  // Should be safe to create the packet now and send it to all the connections //
1248  // TODO: remake this to work better
1249  SendToAllPlayers(std::make_shared<ResponseWorldFrozen>(0, ID, WorldFrozen, -1),
1251 }
1252 
1253 // DLLEXPORT RayCastHitEntity* GameWorld::CastRayGetFirstHit(const Float3& from, const Float3&
1254 // to)
1255 // {
1256 // // Create a data object for the ray cast //
1257 // RayCastData data(1, from, to);
1258 
1259 // // Call the actual ray firing function //
1260 // NewtonWorldRayCast(_PhysicalWorld->GetNewtonWorld(), &from.X, &to.X,
1261 // RayCallbackDataCallbackClosest, &data, nullptr, 0);
1262 
1263 // // Check the result //
1264 // if(data.HitEntities.size() == 0) {
1265 // // Nothing hit //
1266 // return new RayCastHitEntity();
1267 // }
1268 
1269 // // We need to increase reference count to not to accidentally delete the result while
1270 // // caller is using it
1271 // data.HitEntities[0]->AddRef();
1272 
1273 // // Return the only hit //
1274 // return data.HitEntities[0];
1275 // }
1276 
1277 
1278 // //! \todo improve this performance //
1279 // dFloat RayCallbackDataCallbackClosest(const NewtonBody* const body,
1280 // const NewtonCollision* const shapeHit, const dFloat* const hitContact,
1281 // const dFloat* const hitNormal, dLong collisionID, void* const userData,
1282 // dFloat intersectParam)
1283 // {
1284 // // Let's just store it as a NewtonBody pointer //
1285 // RayCastData* data = reinterpret_cast<RayCastData*>(userData);
1286 
1287 // if(data->HitEntities.size() == 0)
1288 // data->HitEntities.push_back(new RayCastHitEntity(body, intersectParam, data));
1289 // else
1290 // *data->HitEntities[0] = RayCastHitEntity(body, intersectParam, data);
1291 
1292 // // Continue //
1293 // return intersectParam;
1294 // }
1295 
1297 {
1298  ClearAllEntities = true;
1299 }
1300 // ------------------------------------ //
1301 void GameWorld::UpdatePlayersPositionData(ConnectedPlayer& ply)
1302 {
1303  // Get the position for this player in this world //
1304  ObjectID id = ply.GetPositionInWorld(this);
1305 
1306  // Player is using a static position at (0, 0, 0) //
1307  if(id == 0)
1308  return;
1309 
1310  try {
1311 
1312  auto& position = GetComponent<Position>(id);
1313 
1314  (void)position.Members._Position;
1315 
1316  } catch(const NotFound&) {
1317 
1318  // Player has invalid position //
1319  Logger::Get()->Warning("Player position entity has no Position component");
1320  }
1321 }
1322 // ------------------------------------ //
1324  ResponseEntityUpdate&& message, Connection& connection)
1325 {
1326  if(NetworkSettings.IsAuthoritative) {
1327 
1328  // Find matching local control before allowing
1329  auto found = ActiveLocalControl.find(message.EntityID);
1330 
1331  if(found != ActiveLocalControl.end()) {
1332 
1333  if(found->second != &connection) {
1334 
1335  // It's unsafe to dereference found->second here
1336  LOG_WARNING("GameWorld: wrong player sent local control message, entity: " +
1337  std::to_string(message.EntityID));
1338  return;
1339  }
1340 
1341  _ApplyLocalControlUpdateMessage(message.EntityID, message.TickNumber,
1342  message.UpdateData, message.ReferenceTick, -1);
1343  _OnLocalControlUpdatedEntity(message.EntityID, message.TickNumber);
1344  return;
1345  }
1346 
1347  LOG_WARNING(
1348  "GameWorld: didn't find local control entity for ResponseEntityUpdate, entity: " +
1349  std::to_string(message.EntityID));
1350  return;
1351  }
1352 
1353  // Don't apply if we don't have the entity
1354  bool found = false;
1355 
1356  for(auto entity : Entities) {
1357  if(entity == message.EntityID) {
1358 
1359  found = true;
1360  break;
1361  }
1362  }
1363 
1364  if(!found) {
1365 
1366  LOG_WARNING(
1367  "GameWorld: HandleEntityPacket: received update for non-existing entity, id: " +
1368  std::to_string(message.EntityID) +
1369  " TODO: queue for later applying in case packets are out of order");
1370  return;
1371  }
1372 
1373  // If this is controlled by us this is handled differently
1374  for(auto entity : OurActiveLocalControl) {
1375 
1376  if(entity == message.EntityID) {
1377 
1378  // TODO: apply corrections if our simulation was incorrect / not allowed
1379  return;
1380  }
1381  }
1382 
1383  try {
1384  _CreateStatesFromUpdateMessage(message.EntityID, message.TickNumber,
1385  message.UpdateData, message.ReferenceTick, -1);
1386  } catch(const InvalidArgument& e) {
1387  LOG_ERROR("GameWorld: HandleEntityPacket: trying to load update packet data caused an "
1388  "exception: ");
1389  e.PrintToLog();
1390  LOG_INFO("GameWorld: note: entity may have partially updated states, id: " +
1391  std::to_string(message.EntityID));
1392  }
1393 }
1394 
1395 DLLEXPORT ObjectID GameWorld::HandleEntityPacket(ResponseEntityCreation& message)
1396 {
1397  if(NetworkSettings.IsAuthoritative) {
1398 
1399  LOG_WARNING("GameWorld: authoritative world is ignoring ResponseEntityCreation");
1400  return NULL_OBJECT;
1401  }
1402 
1403  if(message.ComponentCount > 1000) {
1404  LOG_ERROR("GameWorld: HandleEntityPacket: entity has more than 1000 components. "
1405  "Packet is likely corrupted / forged, ignoring");
1406  return NULL_OBJECT;
1407  }
1408 
1409  // TODO: somehow detect if the ID collides with local entities (once those are allowed)
1410  Entities.push_back(message.EntityID);
1411 
1412  if(!NetworkSettings.IsAuthoritative) {
1413 
1414  if(NetworkSettings.AutoCreateNetworkComponents) {
1415  _CreateReceivedComponentForEntity(message.EntityID);
1416  }
1417  }
1418 
1419  try {
1421  message.EntityID, message.InitialComponentData, message.ComponentCount, -1);
1422 
1423  return message.EntityID;
1424  } catch(const InvalidArgument& e) {
1425  LOG_ERROR(
1426  "GameWorld: HandleEntityPacket: trying to load packet data caused an exception: ");
1427  e.PrintToLog();
1428  LOG_INFO("GameWorld: destroying invalid received entity: " +
1429  std::to_string(message.EntityID));
1430  DestroyEntity(message.EntityID);
1431 
1432  return NULL_OBJECT;
1433  }
1434 }
1435 
1436 DLLEXPORT void GameWorld::HandleEntityPacket(ResponseEntityDestruction& message)
1437 {
1438  if(NetworkSettings.IsAuthoritative) {
1439 
1440  LOG_WARNING("GameWorld: authoritative world is ignoring ResponseEntityCreation");
1441  return;
1442  }
1443 
1444  for(auto entity : Entities) {
1445  if(entity == message.EntityID) {
1446 
1447  DestroyEntity(message.EntityID);
1448  return;
1449  }
1450  }
1451 
1452  // TODO: queue if we don't have an entity with the ID
1453  LOG_WARNING("GameWorld: HandleEntityPacket: received destruction message for unknown "
1454  "entity, TODO: queue");
1455 }
1456 
1457 DLLEXPORT void GameWorld::HandleEntityPacket(ResponseEntityLocalControlStatus& message)
1458 {
1459  if(!message.Enabled) {
1460 
1461  for(auto iter = OurActiveLocalControl.begin(); iter != OurActiveLocalControl.end();
1462  ++iter) {
1463 
1464  if(*iter == message.EntityID) {
1465  OurActiveLocalControl.erase(iter);
1466  return;
1467  }
1468  }
1469 
1470  LOG_WARNING("GameWorld: received disable local control message for entity that wasn't "
1471  "controlled by us");
1472  } else {
1473 
1474  // Ignore duplicates
1475  for(auto controlled : OurActiveLocalControl)
1476  if(controlled == message.EntityID)
1477  return;
1478 
1479  OurActiveLocalControl.push_back(message.EntityID);
1480 
1481  if(NetworkSettings.AutoCreateNetworkComponents) {
1482  try {
1483  _CreateSendableComponentForEntity(message.EntityID);
1484  LOG_INFO("GameWorld: created Sendable for locally controlled entity: " +
1485  std::to_string(message.EntityID));
1486  } catch(const InvalidState&) {
1487  LOG_WARNING(
1488  "GameWorld: couldn't create Sendable for now locally controlled entity:" +
1489  std::to_string(message.EntityID));
1490  }
1491  }
1492  }
1493 }
1494 // ------------------------------------ //
1496  ObjectID id, bool enabled, const std::shared_ptr<Connection>& allowedconnection)
1497 {
1498  // Apply the change
1499  if(enabled) {
1500 
1501  // TODO: detect changing owner
1502  ActiveLocalControl[id] = allowedconnection.get();
1503  } else {
1504 
1505  auto found = ActiveLocalControl.find(id);
1506 
1507  if(found != ActiveLocalControl.end()) {
1508  ActiveLocalControl.erase(found);
1509  } else {
1510  LOG_ERROR("GameWorld: SetLocalControl: disable called on entity that wasn't being "
1511  "controlled");
1512  }
1513  }
1514 
1515  // Notify
1516  auto response = std::make_shared<ResponseEntityLocalControlStatus>(0, ID, id, enabled);
1517 
1518  allowedconnection->SendPacketToConnection(response, RECEIVE_GUARANTEE::Critical);
1519 }
1520 
1522 {
1523  Position* position = GetComponentPtr<Position>(id);
1524  Physics* physics = GetComponentPtr<Physics>(id);
1525 
1526  if(position && physics) {
1527 
1528  if(position->Marked) {
1529 
1530  physics->JumpTo(*position);
1531  }
1532  }
1533 }
1534 // ------------------------------------ //
1536 {
1537  if(!pimpl->QueuedEntityUpdates.empty()) {
1538  }
1539 
1540  // Applies packets that were received out of order. And throws out any too old packets
1541 
1542  // if(!InitialEntityPackets.empty())
1543  // _ApplyInitialEntityPackets();
1544 
1545  // if(!EntityUpdatePackets.empty())
1546  // _ApplyEntityUpdatePackets();
1547 }
1548 // ------------------------------------ //
1549 // DLLEXPORT void GameWorld::HandleClockSyncPacket(RequestWorldClockSync* data)
1550 // {
1551 // Logger::Get()->Info(
1552 // "GameWorld: adjusting our clock: Absolute: " + Convert::ToString(data->Absolute) +
1553 // ", tick: " + Convert::ToString(data->Ticks) +
1554 // ", engine ms: " + Convert::ToString(data->EngineMSTweak));
1555 
1556 // // Change our TickNumber to match //
1557 // Engine::Get()->_AdjustTickNumber(data->Ticks, data->Absolute);
1558 
1559 // if(data->EngineMSTweak)
1560 // Engine::Get()->_AdjustTickClock(data->EngineMSTweak, data->Absolute);
1561 // }
1562 // // ------------------------------------ //
1563 // DLLEXPORT void GameWorld::HandleWorldFrozenPacket(ResponseWorldFrozen* data)
1564 // {
1565 // Logger::Get()->Info(
1566 // "GameWorld(" + Convert::ToString(ID) +
1567 // "): frozen state updated, now: " + Convert::ToString<int>(data->Frozen) +
1568 // ", tick: " + Convert::ToString(data->TickNumber) +
1569 // " (our tick:" + Convert::ToString(TickNumber) + ")");
1570 
1571 // if(data->TickNumber > TickNumber) {
1572 
1573 // Logger::Get()->Write("TODO: freeze the world in the future");
1574 // }
1575 
1576 // // Set the state //
1577 // SetWorldPhysicsFrozenState(data->Frozen);
1578 
1579 // // Simulate ticks if required //
1580 // if(!data->Frozen) {
1581 
1582 // // Check how many ticks we are behind and simulate that number of physical updates
1583 // // int tickstosimulate = TickNumber - data->TickNumber;
1584 
1585 // if(tickstosimulate > 0) {
1586 
1587 // Logger::Get()->Info("GameWorld: unfreezing and simulating " +
1588 // Convert::ToString(tickstosimulate * TICKSPEED) +
1589 // " ms worth of more physical updates");
1590 
1591 // DEBUG_BREAK;
1592 // // _PhysicalWorld->AdjustClock(tickstosimulate * TICKSPEED);
1593 // }
1594 
1595 
1596 // } else {
1597 
1598 // // Snap objects back //
1599 // Logger::Get()->Info("TODO: world freeze snap things back a bit");
1600 // }
1601 // }
1602 // ------------------------------------ //
1603 DLLEXPORT CScriptArray* GameWorld::GetRemovedIDsForComponents(CScriptArray* componenttypes)
1604 {
1605  if(!componenttypes)
1606  return nullptr;
1607 
1608  if(componenttypes->GetElementTypeId() !=
1610 
1611  LOG_ERROR("GameWorld: GetRemovedIDsForComponents: given an array of wrong type");
1612  componenttypes->Release();
1613  return nullptr;
1614  }
1615 
1616  std::vector<std::tuple<void*, ObjectID>> result;
1617 
1618  for(asUINT i = 0; i < componenttypes->GetSize(); ++i) {
1619 
1620  uint16_t* type = static_cast<uint16_t*>(componenttypes->At(i));
1621 
1622  if(!GetRemovedFor(static_cast<COMPONENT_TYPE>(*type), result)) {
1623 
1624  LOG_WARNING("GameWorld: GetRemovedIDsForComponents: unknown component type: " +
1625  std::to_string(*type));
1626  }
1627  }
1628 
1629  componenttypes->Release();
1630 
1631  asITypeInfo* typeInfo =
1632  ScriptExecutor::Get()->GetASEngine()->GetTypeInfoByDecl("array<ObjectID>");
1633 
1634  CScriptArray* array = CScriptArray::Create(typeInfo, static_cast<asUINT>(result.size()));
1635 
1636  if(!array)
1637  return nullptr;
1638 
1639  for(asUINT i = 0; i < static_cast<asUINT>(result.size()); ++i) {
1640 
1641  array->SetValue(i, &std::get<1>(result[i]));
1642  }
1643 
1644  return array;
1645 }
1646 
1647 DLLEXPORT CScriptArray* GameWorld::GetRemovedIDsForScriptComponents(CScriptArray* typenames)
1648 {
1649  if(!typenames)
1650  return nullptr;
1651 
1652  if(typenames->GetElementTypeId() !=
1654 
1655  LOG_ERROR("GameWorld: GetRemovedIDsForScriptComponents: given an array of wrong type "
1656  "(expected array<string>)");
1657  typenames->Release();
1658  return nullptr;
1659  }
1660 
1661  std::vector<std::tuple<asIScriptObject*, ObjectID>> result;
1662 
1663  for(asUINT i = 0; i < typenames->GetSize(); ++i) {
1664 
1665  std::string* type = static_cast<std::string*>(typenames->At(i));
1666 
1667  if(!GetRemovedForScriptDefined(*type, result)) {
1668 
1669  LOG_WARNING(
1670  "GameWorld: GetRemovedIDsForScriptComponents: unknown component type: " +
1671  *type);
1672  }
1673  }
1674 
1675  typenames->Release();
1676 
1677  asITypeInfo* typeInfo =
1678  ScriptExecutor::Get()->GetASEngine()->GetTypeInfoByDecl("array<ObjectID>");
1679 
1680  CScriptArray* array = CScriptArray::Create(typeInfo, static_cast<asUINT>(result.size()));
1681 
1682  if(!array)
1683  return nullptr;
1684 
1685  for(asUINT i = 0; i < static_cast<asUINT>(result.size()); ++i) {
1686 
1687  array->SetValue(i, &std::get<1>(result[i]));
1688  }
1689 
1690  return array;
1691 }
1692 
1694  const std::string& name, asIScriptFunction* factory)
1695 {
1696  // Skip if already registered //
1697  if(pimpl->RegisteredScriptComponents.find(name) !=
1698  pimpl->RegisteredScriptComponents.end()) {
1699  factory->Release();
1700  return false;
1701  }
1702 
1703  // ScriptComponentHolder takes care of releasing the reference
1704  pimpl->RegisteredScriptComponents[name] =
1705  ScriptComponentHolder::MakeShared<ScriptComponentHolder>(name, factory, this);
1706 
1707  return true;
1708 }
1709 
1711 {
1712  // if called after release
1713  if(!pimpl)
1714  return nullptr;
1715 
1716  auto iter = pimpl->RegisteredScriptComponents.find(name);
1717 
1718  if(iter == pimpl->RegisteredScriptComponents.end())
1719  return nullptr;
1720 
1721  iter->second->AddRef();
1722  return iter->second.get();
1723 }
1724 
1726  const std::string& name, asIScriptObject* system)
1727 {
1728  if(!system) {
1729  LOG_ERROR("GameWorld: RegisterScriptSystem: passed null object as new system");
1730  return false;
1731  }
1732 
1733  // if called after release
1734  if(!pimpl) {
1735  system->Release();
1736  return false;
1737  }
1738 
1739  // Skip if already registered //
1740  if(pimpl->RegisteredScriptSystems.find(name) != pimpl->RegisteredScriptSystems.end()) {
1741  system->Release();
1742  return false;
1743  }
1744 
1745  // Create a wrapper for it //
1746  // The wrapper handles unreferencing the handle
1747  pimpl->RegisteredScriptSystems[name] = std::make_unique<ScriptSystemWrapper>(name, system);
1748 
1749  // Might as well call Init now as other systems are almost certainly initialized as well //
1750  pimpl->RegisteredScriptSystems[name]->Init(this);
1751  return true;
1752 }
1753 
1754 DLLEXPORT bool GameWorld::UnregisterScriptSystem(const std::string& name)
1755 {
1756  // if called after release
1757  if(!pimpl) {
1758  return false;
1759  }
1760 
1761  const auto iter = pimpl->RegisteredScriptSystems.find(name);
1762  if(iter == pimpl->RegisteredScriptSystems.end()) {
1763  return false;
1764  }
1765 
1766  iter->second->Release();
1767  pimpl->RegisteredScriptSystems.erase(iter);
1768 
1769  return true;
1770 }
1771 
1772 DLLEXPORT asIScriptObject* GameWorld::GetScriptSystem(const std::string& name)
1773 {
1774  // if called after release
1775  if(!pimpl)
1776  return nullptr;
1777 
1778  auto iter = pimpl->RegisteredScriptSystems.find(name);
1779 
1780  if(iter == pimpl->RegisteredScriptSystems.end()) {
1781 
1782  LOG_ERROR("GameWorld: GetScriptSystemDirect: world has no system called: " + name);
1783  return nullptr;
1784  }
1785 
1786  return iter->second->GetASImplementationObject();
1787 }
1788 // ------------------------------------ //
1790 {
1791  if(!LinkedToWindow) {
1792  LOG_WARNING(
1793  "GameWorld: unlink from window called while this wasn't linked to a window");
1794  return;
1795  }
1796 
1797  if(window != LinkedToWindow) {
1798 
1799  throw InvalidArgument("GameWorld attempted to be unlinked from window that wasn't the "
1800  "one it was linked to");
1801  }
1802 
1803  pimpl->WorldCamera->getViewport()->setTarget(nullptr);
1804 
1805  if(pimpl->DebugDraw) {
1806  LOG_INFO("GameWorld: stopping debug draw because this was detached from a world");
1807  // Clear the contents
1808  pimpl->DebugDraw->OnBeginDraw();
1809  _PhysicalWorld->SetDebugDrawer(nullptr);
1810  pimpl->DebugDraw = nullptr;
1811  }
1812 
1813  // ogre->getCompositorManager2()->removeWorkspace(WorldWorkspace);
1814  // WorldWorkspace = nullptr;
1815  LinkedToWindow = nullptr;
1816 
1817  if(!TickWhileInBackground) {
1819  }
1820 
1821  InBackground = true;
1822 }
1823 
1825 {
1826  // LEVIATHAN_ASSERT(WorldsScene, "World is not initialized");
1827 
1828  if(!window)
1829  throw InvalidArgument("GameWorld attempted to be linked to a nullptr window");
1830 
1831  if(LinkedToWindow // || WorldWorkspace
1832  ) {
1833  throw InvalidArgument(
1834  "GameWorld attempted to be linked to a window while it is already linked");
1835  }
1836 
1837  LinkedToWindow = window;
1838 
1839  // // Create the workspace for this scene //
1840  // // Which will be rendered before the overlay workspace but after potential
1841  // // clearing workspace
1842  // WorldWorkspace = ogre->getCompositorManager2()->addWorkspace(WorldsScene,
1843  // LinkedToWindow->GetOgreWindow(), WorldSceneCamera, "WorldsWorkspace", true, 0);
1844  pimpl->WorldCamera->getViewport()->setTarget(window->GetBSFWindow());
1845 
1846  // TODO: this needs to be reapplied every time the window is resized
1847  pimpl->WorldCamera->setCustomProjectionMatrix(true,
1848  Matrix4::ProjectionPerspective(FOV, LinkedToWindow->GetAspectRatio(), 0.1f, 5000.f));
1849 
1850  if(!TickWhileInBackground) {
1851  _DoResumeSystems();
1852  }
1853 
1854  InBackground = false;
1855 }
1856 
1857 DLLEXPORT void GameWorld::SetRunInBackground(bool tickinbackground)
1858 {
1859  TickWhileInBackground = tickinbackground;
1860 }
1861 
1862 // // ------------------ RayCastHitEntity ------------------ //
1863 // DLLEXPORT Leviathan::RayCastHitEntity::RayCastHitEntity(
1864 // const NewtonBody* ptr /*= nullptr*/, const float& tvar, RayCastData* ownerptr) :
1865 // HitEntity(ptr),
1866 // HitVariable(tvar)
1867 // {
1868 // if(ownerptr) {
1869 // HitLocation = ownerptr->BaseHitLocationCalcVar * HitVariable;
1870 // } else {
1871 // HitLocation = (Float3)0;
1872 // }
1873 // }
1874 
1875 // DLLEXPORT bool Leviathan::RayCastHitEntity::HasHit()
1876 // {
1877 // return HitEntity != nullptr;
1878 // }
1879 
1880 // DLLEXPORT bool Leviathan::RayCastHitEntity::DoesBodyMatchThisHit(NewtonBody* other)
1881 // {
1882 // return HitEntity == other;
1883 // }
1884 
1885 // DLLEXPORT Float3 Leviathan::RayCastHitEntity::GetPosition()
1886 // {
1887 // return HitLocation;
1888 // }
1889 
1890 // DLLEXPORT RayCastHitEntity& Leviathan::RayCastHitEntity::operator=(
1891 // const RayCastHitEntity& other)
1892 // {
1893 // HitEntity = other.HitEntity;
1894 // HitVariable = other.HitVariable;
1895 // HitLocation = other.HitLocation;
1896 
1897 // return *this;
1898 // }
1899 // // ------------------ RayCastData ------------------ //
1900 // DLLEXPORT Leviathan::RayCastData::RayCastData(
1901 // int maxcount, const Float3& from, const Float3& to) :
1902 // MaxCount(maxcount),
1903 // // Formula based on helpful guy on Newton forums
1904 // BaseHitLocationCalcVar(from + (to - from))
1905 // {
1906 // // Reserve memory for maximum number of objects //
1907 // HitEntities.reserve(maxcount);
1908 // }
1909 
1910 // DLLEXPORT Leviathan::RayCastData::~RayCastData()
1911 // {
1912 // // We want to release all hit data //
1913 // SAFE_RELEASE_VECTOR(HitEntities);
1914 // }
virtual DLLEXPORT std::tuple< void *, ComponentTypeInfo, bool > GetComponentWithType(ObjectID id, COMPONENT_TYPE type)
Gets a component of type or returns nullptr.
Definition: GameWorld.cpp:1101
DLLEXPORT asIScriptObject * GetScriptSystem(const std::string &name)
Returns the underlying angelscript object that implements a script system.
Definition: GameWorld.cpp:1772
static bool SunCreated
Definition: GameWorld.cpp:269
DLLEXPORT void Write(const std::string &data) override
Definition: Logger.cpp:113
virtual DLLEXPORT void _DoSuspendSystems()
Called when this is put in the background and systems (the sound system) should suspend their active ...
Definition: GameWorld.cpp:1181
DLLEXPORT std::shared_ptr< SentRequest > SendPacketToConnection(const std::shared_ptr< NetworkRequest > &request, RECEIVE_GUARANTEE guarantee)
Definition: Connection.cpp:139
DLLEXPORT ObjectID CreateEntity()
Creates a new empty entity and returns its id.
Definition: GameWorld.cpp:865
DLLEXPORT asIScriptEngine * GetASEngine()
#define LOG_INFO(x)
Definition: Define.h:90
constexpr ObjectID NULL_OBJECT
Definition: EntityCommon.h:14
int32_t ObjectID
Definition: EntityCommon.h:11
DLLEXPORT bool RegisterScriptComponentType(const std::string &name, asIScriptFunction *factory)
Registers a component type from scripts.
Definition: GameWorld.cpp:1693
DLLEXPORT void Info(const std::string &data) override
Definition: Logger.cpp:164
#define LOG_ERROR(x)
Definition: Define.h:92
DLLEXPORT void SetEntitysParent(ObjectID child, ObjectID parent)
Makes child entity be deleted when parent is deleted.
Definition: GameWorld.cpp:1091
Ray starting from an origin with a direction.
Definition: Ray.h:14
virtual DLLEXPORT void OnLinkToWindow(Window *window, Graphics *graphics)
Called when this is added to a Window.
Definition: GameWorld.cpp:1824
static int Get(ScriptExecutor *resolver)
DLLEXPORT const auto & GetBSFWindow() const
Definition: Window.h:166
DLLEXPORT void HandleEntityPacket(ResponseEntityUpdate &&message, Connection &connection)
Applies an entity update packet.
Definition: GameWorld.cpp:1323
#define LOG_FATAL(x)
Definition: Define.h:94
DLLEXPORT void Render(float elapsed)
Runs systems required for a rendering run. Also updates camera positions.
Definition: GameWorld.cpp:390
COMPONENT_TYPE
Must contain all valid Component types.
Definition: Component.h:21
virtual DLLEXPORT void _DoSystemsRelease()
Called in Release when systems should run their shutdown logic.
Definition: GameWorld.cpp:1165
virtual DLLEXPORT void DestroyAllIn(ObjectID id)
Removes all components from an entity.
Definition: GameWorld.cpp:1214
static std::tuple< bool, StateT > Interpolate(const StateHolder< StateT > &stateholder, ObjectID entity, ComponentT *entitycomponent, float elapsed)
Interpolates states for component.
RECEIVE_GUARANTEE
Controls whether a packet is critical.
Definition: CommonNetwork.h:49
virtual DLLEXPORT void _CreateSendableComponentForEntity(ObjectID id)
Called when this base class wants to create a Sendable component.
Definition: GameWorld.cpp:1201
virtual DLLEXPORT void _ApplyLocalControlUpdateMessage(ObjectID id, int32_t ticknumber, sf::Packet &data, int32_t referencetick, int decodedtype)
Called to apply local control from a clients message.
Definition: GameWorld.cpp:709
DLLEXPORT void SetLightProperties(const Float3 &colour, float intensity=0.0001f, const Float3 &direction=Float3(0.55f, -0.3f, 0.75f), float sourceradius=0.5f, bool castsshadows=true)
Sets the sunlight properties.
Definition: GameWorld.cpp:338
DLLEXPORT void Tick(float elapsed)
Used to keep track of passed ticks and trigger timed triggers.
Definition: GameWorld.cpp:716
DLLEXPORT CScriptArray * GetRemovedIDsForComponents(CScriptArray *componenttypes)
Returns a list of ObjectIDs that have been removed from any of the specified component types.
Definition: GameWorld.cpp:1603
DLLEXPORT SceneNode * GetCameraSceneObject()
Returns the scene object the camera is attached to.
Definition: GameWorld.cpp:508
DLLEXPORT void EnablePhysicsDebugDraw()
Definition: GameWorld.cpp:527
DLLEXPORT void SetLocalControl(ObjectID id, bool enabled, const std::shared_ptr< Connection > &allowedconnection)
Sets local control on a client over an entity or disables it.
Definition: GameWorld.cpp:1495
static int GetID()
Definition: IDFactory.h:17
std::map< std::string, ScriptComponentHolder::pointer > RegisteredScriptComponents
Definition: GameWorld.cpp:56
virtual DLLEXPORT void _CreateReceivedComponentForEntity(ObjectID id)
Called when this base class wants to create a Received component.
Definition: GameWorld.cpp:1207
virtual DLLEXPORT void RunFrameRenderSystems(float elapsed)
Called by Render which is called from a Window if this is linked to one.
Definition: GameWorld.cpp:845
DLLEXPORT bs::HTexture LoadTextureByName(const std::string &name)
Works the same as LoadShaderByName.
Definition: Graphics.cpp:595
std::shared_ptr< PhysicsDebugDrawer > DebugDraw
Definition: GameWorld.cpp:72
virtual DLLEXPORT bool GetAddedFor(COMPONENT_TYPE type, std::vector< std::tuple< void *, ObjectID, ComponentTypeInfo >> &result)
Gets a list of created components of type.
Definition: GameWorld.cpp:1132
Base class for all exceptions thrown by Leviathan.
Definition: Exceptions.h:10
DLLEXPORT void QueueDestroyEntity(ObjectID id)
Deletes an entity during the next tick.
Definition: GameWorld.cpp:961
virtual DLLEXPORT void HandleAddedAndDeleted()
Handles added entities and components.
Definition: GameWorld.cpp:796
DLLEXPORT bool IsConnectionInWorld(Connection &connection) const
Returns true if a player with the given connection is receiving updates for this world.
Definition: GameWorld.cpp:554
DLLEXPORT void DisablePhysicsDebugDraw()
Definition: GameWorld.cpp:536
const std::shared_ptr< Connection > & GetConnection()
#define LOG_WARNING(x)
Definition: Define.h:91
A node in the Scene used to position renderables and other SceneNodes.
Definition: SceneNode.h:70
DLLEXPORT bool GetRemovedForScriptDefined(const std::string &name, std::vector< std::tuple< asIScriptObject *, ObjectID >> &result)
Variant of GetRemovedFor for script defined types.
Definition: GameWorld.cpp:1118
DLLEXPORT void ApplyQueuedPackets()
Applies packets that were received out of order. And throws out any too old packets.
Definition: GameWorld.cpp:1535
virtual DLLEXPORT void _ResetOrReleaseComponents()
Resets components in holders. Used together with _ResetSystems.
Definition: GameWorld.cpp:831
virtual DLLEXPORT void OnUnLinkedFromWindow(Window *window, Graphics *graphics)
Used to detect that this world is in the background and should not tick.
Definition: GameWorld.cpp:1789
static DLLEXPORT ScriptExecutor * Get()
bool IsAuthoritative
This is true on the server.
const std::string & GetNickname() override
Returns a friendly name, nickname used to represent this entity.
DLLEXPORT void SetSunlight()
Definition: GameWorld.cpp:271
DLLEXPORT const auto & GetNetworkSettings() const
Definition: GameWorld.h:290
DLLEXPORT void SetWorldPhysicsFrozenState(bool frozen)
Definition: GameWorld.cpp:1235
static DLLEXPORT Matrix4 ProjectionPerspective(const Degree &horzFOV, float aspect, float near, float far, bool positiveZ=false)
Definition: Matrix.cpp:1139
TComponent & GetComponent(ObjectID id)
Definition: GameWorld.h:150
void swap(Value &a, Value &b)
Definition: json.h:1359
virtual DLLEXPORT void _CreateStatesFromUpdateMessage(ObjectID id, int32_t ticknumber, sf::Packet &data, int32_t referencetick, int decodedtype)
Called to deserialize entity component states from a packet.
Definition: GameWorld.cpp:701
DLLEXPORT NamedVars * GetValues()
Definition: AppDefine.cpp:40
DLLEXPORT CScriptArray * GetRemovedIDsForScriptComponents(CScriptArray *typenames)
Returns a list of ObjectIDs that have been removed from any of the script registered component types ...
Definition: GameWorld.cpp:1647
DLLEXPORT void Warning(const std::string &data) override
Definition: Logger.cpp:190
Entity has position and direction it is looking at.
Definition: Components.h:36
#define LOG_WRITE(x)
Definition: Define.h:93
DLLEXPORT ~GameWorld()
Definition: GameWorld.cpp:84
SoundDevice * GetSoundDevice()
Definition: Engine.h:227
DLLEXPORT Ray CastRayFromCamera(int x, int y) const
Casts a ray from the active camera.
Definition: GameWorld.cpp:494
std::vector< std::tuple< WantedClockType::time_point, ResponseEntityUpdate > > QueuedEntityUpdates
Queued entity updates. Contains the time it was received in order to throw out old ones.
Definition: GameWorld.cpp:61
DLLEXPORT bool Init(const WorldNetworkSettings &network, Graphics *graphics)
Creates resources for the world to work.
Definition: GameWorld.cpp:95
Graphics * GetGraphics()
Definition: Engine.h:185
FORCE_INLINE void AddRef() const
DLLEXPORT bool ShouldPlayerReceiveEntity(Position &atposition, Connection &connection)
Returns true when the player matching the connection should receive updates about an entity.
Definition: GameWorld.cpp:548
DLLEXPORT float GetAspectRatio() const
Definition: Window.h:77
unsigned short uint16_t
Definition: core.h:39
#define LEVIATHAN_ASSERT(x, msg)
Definition: Define.h:100
DLLEXPORT bool RegisterScriptSystem(const std::string &name, asIScriptObject *system)
Registers a new system defined in a script. Must implement the ScriptSystem interface.
Definition: GameWorld.cpp:1725
static std::string ToString(const T &val)
Definition: Convert.h:72
virtual DLLEXPORT void ClearAddedAndRemoved()
Clears the added components. Call after HandleAddedAndDeleted.
Definition: GameWorld.cpp:806
DLLEXPORT GameWorld(int32_t worldtype, const std::shared_ptr< PhysicsMaterialManager > &physicsMaterials, int worldid=-1)
Definition: GameWorld.cpp:77
Entity has a physical component.
Definition: Components.h:347
StateHolder< typename TComponent::StateT > & GetStatesFor()
Definition: GameWorld.h:198
virtual DLLEXPORT void CaptureEntityState(ObjectID id, EntityState &curstate) const
Captures the current state of an entity.
Definition: GameWorld.cpp:684
DLLEXPORT void RemoveSunlight()
Definition: GameWorld.cpp:295
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
DLLEXPORT void SetSoundListenerPosition(const Float3 &pos, const Float4 &orientation)
Loads the file and plays the sound.
virtual DLLEXPORT void _OnLocalControlUpdatedEntity(ObjectID id, int32_t ticknumber)
This method is for doing checks after applying client sent state to the server.
Definition: GameWorld.cpp:1521
AppDef * GetDefinition()
Definition: Engine.h:211
DLLEXPORT void Release()
Release resources.
Definition: GameWorld.cpp:122
A class that represents a human player.
DLLEXPORT ObjectID GetPositionInWorld(GameWorld *world) const
Returns the object that contains this players position in a certain world or 0.
virtual DLLEXPORT void _CreateComponentsFromCreationMessage(ObjectID id, sf::Packet &data, int entriesleft, int decodedtype)
Called to deserialize initial entity components and their static state.
Definition: GameWorld.cpp:691
DLLEXPORT ScriptComponentHolder * GetScriptComponentHolder(const std::string &name)
Retrieves a script registered component type holder.
Definition: GameWorld.cpp:1710
DLLEXPORT void JumpTo(Position &target)
Syncs this physics body to a changed position.
Definition: Components.cpp:110
Properties that a camera entity has (will also need a Position component)
Definition: Components.h:714
uint16_t FOV
Horizontal (ie. "normal") field of view.
Definition: Components.h:725
Class that handles a single connection to another instance.
Definition: Connection.h:105
virtual DLLEXPORT void _RunTickSystems(float elapsed)
Called by Tick.
Definition: GameWorld.cpp:854
#define DLLEXPORT
Definition: Include.h:84
DLLEXPORT void SetCamera(ObjectID object)
Sets the entity that acts as a camera.
Definition: GameWorld.cpp:469
DLLEXPORT void MarkForClear()
Marks all entities to be deleted.
Definition: GameWorld.cpp:1296
virtual DLLEXPORT void _DoResumeSystems()
Opposite of _DoSuspendSystems.
Definition: GameWorld.cpp:1191
static DLLEXPORT Engine * Get()
Definition: Engine.cpp:86
DLLEXPORT bool GetAddedForScriptDefined(const std::string &name, std::vector< std::tuple< asIScriptObject *, ObjectID, ScriptComponentHolder * >> &result)
Variant of GetAddedFor for script defined types.
Definition: GameWorld.cpp:1138
virtual DLLEXPORT uint32_t CaptureEntityStaticState(ObjectID id, sf::Packet &receiver) const
Captures the initial parameters of an entity with components that don't have current state synchroniz...
Definition: GameWorld.cpp:686
DLLEXPORT void ClearEntities()
Clears all objects from the world.
Definition: GameWorld.cpp:892
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
DLLEXPORT void SetAutoExposure(float mineyeadaptation=0.003f, float maxeyeadaptation=2.0f, float eyeadaptationspeeddown=3.0f, float eyeadaptationspeedup=3.0f, float histogramlog2max=4.0f, float histogramlog2min=-8.0f, float histogrampcthigh=0.985f, float histogrampctlow=0.8f)
Sets the world camera eye adaptation settings.
Definition: GameWorld.cpp:368
Holder of state for a whole entity.
unsigned int uint32_t
Definition: core.h:40
virtual DLLEXPORT void SetRunInBackground(bool tickinbackground)
Configures this world to run tick even when not attached to a window.
Definition: GameWorld.cpp:1857
DLLEXPORT void Error(const std::string &data) override
Definition: Logger.cpp:177
DLLEXPORT void SetSkybox(const std::string &skyboxname, float brightness=1.f)
Definition: GameWorld.cpp:305
virtual DLLEXPORT bool GetRemovedFor(COMPONENT_TYPE type, std::vector< std::tuple< void *, ObjectID >> &result)
Gets a list of destroyed components of type.
Definition: GameWorld.cpp:1112
DLLEXPORT void SetPlayerReceiveWorld(std::shared_ptr< ConnectedPlayer > ply)
Verifies that player is receiving this world.
Definition: GameWorld.cpp:567
virtual DLLEXPORT void _DoSystemsInit()
Called in Init when systems should run their initialization logic.
Definition: GameWorld.cpp:1160
virtual DLLEXPORT void _ResetSystems()
Resets stored nodes in systems. Used together with _ResetComponents.
Definition: GameWorld.cpp:817
bool GraphicalMode
If false a graphical Ogre window hasn't been created and purely graphical stuff should be skipped.
Definition: GameWorld.h:574
DLLEXPORT bool UnregisterScriptSystem(const std::string &name)
Unregisters a script system that was registered with RegisterScriptSystem.
Definition: GameWorld.cpp:1754
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18
DLLEXPORT void DestroyEntity(ObjectID id)
Destroys an entity and all of its components.
Definition: GameWorld.cpp:937
DLLEXPORT Scene * GetScene()
Definition: GameWorld.cpp:513
virtual DLLEXPORT void PrintToLog() const noexcept
Definition: Exceptions.cpp:35
DLLEXPORT void SendToAllPlayers(const std::shared_ptr< NetworkResponse > &response, RECEIVE_GUARANTEE guarantee) const
Sends a packet to all connected players.
Definition: GameWorld.cpp:667
std::map< std::string, std::unique_ptr< ScriptSystemWrapper > > RegisteredScriptSystems
Definition: GameWorld.cpp:57
DLLEXPORT int GetPhysicalMaterial(const std::string &name)
Fetches the physical material ID from the material manager.
Definition: GameWorld.cpp:929
DLLEXPORT Scene * GetSceneWrapper()
Definition: GameWorld.cpp:519