Snake/src/Core/Crawl/iworld.cpp

461 lines
9.9 KiB
C++
Raw Normal View History

//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "Extensions/claster.h"
2021-06-14 18:15:59 +03:00
#include "iai.h"
2021-06-06 15:53:49 +03:00
#include "iworld.h"
2021-06-07 17:37:03 +03:00
#include "iworlditem.h"
2021-06-14 18:15:59 +03:00
#include <defaultbackgroundai.h>
2021-06-06 22:10:43 +03:00
#include <quasarapp.h>
2021-07-10 00:40:35 +03:00
#include "groundclaster.h"
2021-06-12 18:20:29 +03:00
#include "defaultcontrol.h"
2021-06-14 18:15:59 +03:00
#include "worldstatus.h"
2021-06-15 16:04:18 +03:00
#include "iai.h"
#include "clasteritem.h"
2021-06-21 10:57:31 +03:00
#include "thread"
#include "chrono"
2021-07-05 17:39:26 +03:00
#include "diff.h"
2021-08-05 18:43:01 +03:00
#include "eventserver.h"
2021-07-05 17:39:26 +03:00
namespace CRAWL {
2021-06-06 15:53:49 +03:00
IWorld::IWorld() {
2021-07-15 00:48:28 +03:00
qRegisterMetaType<WorldRule::const_iterator>("WorldRule::const_iterator");
connect(this, &IWorld::sigWorldChanged, this, &IWorld::worldChanged, Qt::QueuedConnection);
2021-08-05 18:43:01 +03:00
2021-08-06 14:17:08 +03:00
_eventServer = new EventServer(this);
connect(_eventServer, &EventServer::sigIntersect, this, &IWorld::onIntersects);
connect(this, &IWorld::sigOBjctsListChanged, _eventServer, &EventServer::handleAvailableObjectChanges);
2021-06-06 15:53:49 +03:00
}
IWorld::~IWorld() {
2021-06-28 18:16:27 +03:00
reset();
2021-08-05 18:43:01 +03:00
delete _eventServer;
2021-06-06 15:53:49 +03:00
}
2021-06-28 18:16:27 +03:00
void IWorld::init() {prepare();}
IControl *IWorld::initUserInterface() const {
2021-06-12 18:20:29 +03:00
return new DefaultControl;
}
2021-06-06 22:10:43 +03:00
void IWorld::render(unsigned int tbfMsec) {
2021-06-30 12:15:57 +03:00
if (!_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
return;
}
2021-06-21 10:57:31 +03:00
_ItemsMutex.lock();
2021-08-06 18:03:23 +03:00
QList<int> toRemove;
2021-06-06 22:10:43 +03:00
for (auto i = _items.begin(); i != _items.end(); ++i) {
2021-08-06 18:03:23 +03:00
if ((*i)->destroyIsScheduled())
toRemove.push_back((*i)->guiId());
(*i)->render(tbfMsec);
2021-06-07 17:37:03 +03:00
}
_ItemsMutex.unlock();
2021-08-06 18:03:23 +03:00
for (int id: toRemove) {
removeItem(id);
}
2021-07-15 00:48:28 +03:00
updateWorld();
2021-06-21 10:57:31 +03:00
2021-08-05 18:43:01 +03:00
int waitTime = 1000 / targetFps() - tbfMsec;
2021-06-21 10:57:31 +03:00
if (waitTime > 0)
std::this_thread::sleep_for(std::chrono::milliseconds(waitTime));
2021-06-06 22:10:43 +03:00
}
2021-06-15 16:04:18 +03:00
void IWorld::initPlayerControl(IControl *control) {
auto controlObject = dynamic_cast<DefaultControl*>(control);
if (controlObject) {
connect(controlObject, &DefaultControl::backToMenu, this, &IWorld::handleStop);
}
}
2021-06-11 18:09:03 +03:00
bool IWorld::start() {
_player->setposition({0,0,0});
2021-06-14 18:15:59 +03:00
setWorldStatus(WorldStatus::Game);
_backgroundAI->stopAI();
_player->setControl(_userInterface);
2021-06-11 18:09:03 +03:00
2021-06-16 18:57:50 +03:00
2021-07-15 00:48:28 +03:00
worldChanged(_worldRules->cbegin());
2021-06-21 10:57:31 +03:00
setTargetFps(60);
2021-06-30 12:15:57 +03:00
setRunning(true);
2021-08-06 14:55:52 +03:00
_eventServer->start();
2021-06-30 12:15:57 +03:00
2021-06-11 18:09:03 +03:00
return true;
}
2021-06-17 13:57:57 +03:00
QObject *IWorld::player() const {
return _player;
}
void IWorld::setPlayer(QObject *newPlayer) {
if (_player == newPlayer)
return;
auto newPlayerObject = dynamic_cast<PlayableObject*>(newPlayer);
2021-06-17 13:57:57 +03:00
if (!newPlayerObject) {
QuasarAppUtils::Params::log("Failed to set player object. The input object is not player.",
QuasarAppUtils::Error);
return;
}
if (_player)
removeItem(_player->guiId());
2021-06-17 13:57:57 +03:00
_player = newPlayerObject;
2021-06-28 18:16:27 +03:00
addItem(_player);
2021-06-17 13:57:57 +03:00
emit playerChanged();
}
2021-06-20 12:48:08 +03:00
IWorldItem *IWorld::generate(const QString &objectType) const {
return _registeredTypes.value(objectType, [](){return nullptr;}).operator()();
}
2021-06-14 18:15:59 +03:00
bool IWorld::stop() {
2021-06-30 12:15:57 +03:00
setRunning(false);
2021-08-06 14:55:52 +03:00
_eventServer->stop();
2021-06-14 18:15:59 +03:00
return true;
}
IAI *IWorld::initBackGroundAI() const {
return new DefaultBackgroundAI();
}
2021-06-16 18:57:50 +03:00
IWorldItem *IWorld::getItem(int id) const {
2021-06-21 10:57:31 +03:00
QMutexLocker lock(&_ItemsMutex);
return _items.value(id, nullptr);
2021-06-09 18:23:07 +03:00
}
2021-06-28 18:16:27 +03:00
bool IWorld::prepare() {
2021-06-06 15:53:49 +03:00
2021-06-13 15:16:46 +03:00
if (isInit())
return true;
2021-06-06 22:10:43 +03:00
_worldRules = initWorldRules();
2021-06-17 13:57:57 +03:00
setHdr(initHdrBackGround());
2021-06-17 13:57:57 +03:00
setPlayer(initPlayer());
2021-06-09 16:38:55 +03:00
_player->initOnWorld(this, _player);
_userInterface = initUserInterface();
2021-06-14 18:15:59 +03:00
_backgroundAI = initBackGroundAI();
2021-06-09 16:38:55 +03:00
2021-06-13 20:16:36 +03:00
if (!isInit()) {
QuasarAppUtils::Params::log("Failed to init world implementation.");
2021-06-28 18:16:27 +03:00
reset();
2021-06-13 20:16:36 +03:00
return false;
}
2021-06-13 15:16:46 +03:00
if (!_worldRules->size()) {
2021-06-28 18:16:27 +03:00
reset();
2021-06-06 22:10:43 +03:00
return false;
2021-06-13 15:16:46 +03:00
}
2021-06-15 16:04:18 +03:00
initPlayerControl(_userInterface);
initPlayerControl(dynamic_cast<IControl*>(_backgroundAI));
2021-06-13 20:16:36 +03:00
2021-06-06 22:10:43 +03:00
return true;
2021-06-06 15:53:49 +03:00
}
2021-06-06 22:10:43 +03:00
void IWorld::clearItems() {
2021-07-06 18:10:07 +03:00
stop();
2021-06-21 10:57:31 +03:00
2021-07-06 18:10:07 +03:00
while (_items.cbegin() != _items.cend()) {
removeItem(*_items.cbegin());
2021-06-06 15:53:49 +03:00
}
2021-06-06 22:10:43 +03:00
_items.clear();
}
void IWorld::addItem(IWorldItem *obj, QList<int> *addedObjectsList) {
if (!obj)
return;
2021-06-28 18:16:27 +03:00
obj->init();
Diff diff;
2021-06-28 18:16:27 +03:00
2021-06-18 17:33:31 +03:00
// Work wih claster
if (auto claster = dynamic_cast<Claster*>(obj)) {
for (auto item : claster->objects()) {
addAtomicItem(item);
if (item) {
diff.addedIds.push_back(item->guiId());
}
}
2021-06-18 17:33:31 +03:00
}
addAtomicItem(obj);
diff.addedIds.push_back(obj->guiId());
if (addedObjectsList)
*addedObjectsList = diff.addedIds;
emit sigOBjctsListChanged(diff);
2021-06-18 17:33:31 +03:00
}
void IWorld::removeItem(int id, QList<int> *removedObjectsList) {
2021-07-06 18:10:07 +03:00
removeItem(getItem(id), removedObjectsList);
}
2021-07-06 18:10:07 +03:00
void IWorld::removeItem(IWorldItem* item, QList<int> *removedObjectsList) {
2021-07-06 18:10:07 +03:00
if (!item)
return;
Diff diff;
2021-06-18 17:33:31 +03:00
// Work wih claster
2021-07-06 18:10:07 +03:00
if (auto claster = dynamic_cast<Claster*>(item)) {
const auto copyOfObjectsList = claster->objects();
2021-06-20 12:48:08 +03:00
for (auto item : copyOfObjectsList) {
2021-07-18 11:50:45 +03:00
auto clasterItem = dynamic_cast<ClasterItem*>(item);
if (!clasterItem || clasterItem->parentClastersCount() > 1)
continue;
int id = item->guiId();
removeAtomicItem(item);
if (removedObjectsList)
diff.removeIds.push_back(id);
}
}
2021-07-06 18:10:07 +03:00
removeAtomicItem(item);
diff.removeIds.push_back(item->guiId());
2021-06-20 12:48:08 +03:00
if (removedObjectsList)
*removedObjectsList = diff.removeIds;
2021-06-18 17:33:31 +03:00
emit sigOBjctsListChanged(diff);
2021-06-18 17:33:31 +03:00
}
2021-06-28 18:16:27 +03:00
void IWorld::reset() {
2021-06-30 12:15:57 +03:00
2021-06-13 15:16:46 +03:00
if (_player) {
_player = nullptr;
}
if (_worldRules) {
delete _worldRules;
_worldRules = nullptr;
}
if (_userInterface) {
delete _userInterface;
_userInterface = nullptr;
}
2021-06-06 15:53:49 +03:00
2021-06-15 16:04:18 +03:00
if (_backgroundAI) {
delete _backgroundAI;
_backgroundAI = nullptr;
}
2021-06-06 22:10:43 +03:00
clearItems();
setHdr("");
2021-06-06 22:10:43 +03:00
2021-06-06 15:53:49 +03:00
}
2021-06-06 22:10:43 +03:00
2021-06-08 21:56:36 +03:00
void IWorld::addAtomicItem(IWorldItem* obj) {
if (!obj)
return;
2021-06-21 10:57:31 +03:00
QMutexLocker lock(&_ItemsMutex);
_items.insert(obj->guiId(), obj);
_itemsGroup.insert(obj->className(), obj->guiId());
2021-06-21 10:57:31 +03:00
obj->initOnWorld(this, _player);
2021-06-06 22:10:43 +03:00
}
bool IWorld::removeAtomicItem(int id) {
2021-06-21 10:57:31 +03:00
QMutexLocker lock(&_ItemsMutex);
2021-06-06 22:10:43 +03:00
auto obj = _items.value(id);
if (!obj) {
2021-06-06 22:10:43 +03:00
return false;
}
_itemsGroup.remove(obj->className(), id);
2021-06-06 22:10:43 +03:00
_items.remove(id);
2021-07-06 18:10:07 +03:00
obj->deleteLater();
2021-06-06 22:10:43 +03:00
return true;
}
bool IWorld::removeAtomicItem(IWorldItem *obj) {
if (!obj) {
return false;
2021-06-13 20:16:36 +03:00
}
2021-06-21 10:57:31 +03:00
QMutexLocker lock(&_ItemsMutex);
_itemsGroup.remove(obj->className(), obj->guiId());
_items.remove(obj->guiId());
2021-07-06 18:10:07 +03:00
obj->deleteLater();
return true;
}
void IWorld::removeAnyItemFromGroup(const QString &group,
QList<int> *removedObjectsList) {
int anyObjectId = _itemsGroup.value(group);
removeItem(anyObjectId, removedObjectsList);
2021-06-06 22:10:43 +03:00
}
2021-06-30 12:15:57 +03:00
bool IWorld::running() const {
return _running;
}
void IWorld::setRunning(bool newRunning) {
_running = newRunning;
}
2021-06-21 10:57:31 +03:00
int IWorld::targetFps() const {
return _targetFps;
}
void IWorld::setTargetFps(int newTargetFps) {
_targetFps = newTargetFps;
}
void IWorld::setHdr(const QString &hdr) {
if (hdr == _hdrMap)
return;
_hdrMap = hdr;
emit hdrChanged();
}
2021-07-15 00:48:28 +03:00
void IWorld::updateWorld() {
if (_currendWorldLevel->isEmpty() || !_worldRules || !_player)
return;
float distance = _player->position().x();
2021-07-19 12:27:58 +03:00
auto nextLevel = std::next(_currendWorldLevel);
2021-07-15 00:48:28 +03:00
if (nextLevel != _worldRules->cend() && distance > nextLevel.key()) {
emit sigWorldChanged(nextLevel);
}
}
2021-08-06 14:17:08 +03:00
void IWorld::onIntersects(QList<const IWorldItem *> list) {
Q_UNUSED(list);
}
2021-07-30 13:19:19 +03:00
const QQuaternion &IWorld::cameraRotation() const {
return _cameraRotation;
2021-06-14 18:15:59 +03:00
}
2021-07-30 13:19:19 +03:00
void IWorld::setCameraRotation(const QQuaternion &newCameraRotation) {
if (_cameraRotation == newCameraRotation)
2021-06-16 15:46:21 +03:00
return;
2021-07-30 13:19:19 +03:00
_cameraRotation = newCameraRotation;
emit cameraRotationChanged();
2021-06-14 18:15:59 +03:00
}
2021-06-15 16:04:18 +03:00
IAI *IWorld::backgroundAI() const {
return _backgroundAI;
}
IControl *IWorld::userInterface() const {
return _userInterface;
}
2021-06-13 15:16:46 +03:00
bool IWorld::isInit() const {
2021-06-14 18:15:59 +03:00
return _userInterface && _player && _worldRules && _backgroundAI;
2021-06-13 15:16:46 +03:00
}
2021-06-09 16:38:55 +03:00
void IWorld::setCameraReleativePosition(const QVector3D &newCameraReleativePosition) {
if (_cameraReleativePosition == newCameraReleativePosition)
return;
_cameraReleativePosition = newCameraReleativePosition;
emit cameraReleativePositionChanged();
}
2021-06-14 18:15:59 +03:00
void IWorld::handleStop() {
2021-06-30 12:15:57 +03:00
runAsBackGround();
2021-06-14 18:15:59 +03:00
}
2021-06-09 16:38:55 +03:00
const QVector3D &IWorld::cameraReleativePosition() const {
return _cameraReleativePosition;
}
2021-07-15 00:48:28 +03:00
void IWorld::worldChanged(WorldRule::const_iterator iterator) {
2021-06-08 18:00:42 +03:00
2021-07-15 00:48:28 +03:00
if (_currendWorldLevel == iterator)
return;
auto objects = iterator.value();
objects[_player->className()] = 1;
2021-06-06 22:10:43 +03:00
for (auto it = objects.begin(); it != objects.end(); ++it) {
2021-06-08 21:56:36 +03:00
int count = it.value() - _itemsGroup.count(it.key());
2021-06-06 22:10:43 +03:00
if (count > 0) {
for ( int i = 0; i < count; ++i ) {
addItem(generate(it.key()));
2021-06-06 22:10:43 +03:00
}
} else {
for (; count < 0; ++count ) {
removeAnyItemFromGroup(it.key());
2021-06-06 22:10:43 +03:00
}
}
}
2021-07-15 00:48:28 +03:00
_currendWorldLevel = iterator;
2021-06-06 22:10:43 +03:00
}
2021-06-14 18:15:59 +03:00
int IWorld::wordlStatus() const {
return _worldStatus;
}
void IWorld::setWorldStatus(int newWorldStatus) {
if (_worldStatus == newWorldStatus) {
2021-06-14 18:15:59 +03:00
return;
}
2021-06-14 18:15:59 +03:00
_worldStatus = newWorldStatus;
emit worldStatusChanged();
}
2021-06-20 12:48:08 +03:00
const QString &IWorld::hdr() const {
return _hdrMap;
}
2021-06-30 12:15:57 +03:00
void IWorld::runAsBackGround() {
start();
setWorldStatus(WorldStatus::Background);
_player->setControl(dynamic_cast<IControl*>(_backgroundAI));
_backgroundAI->startAI();
setTargetFps(30);
}
2021-07-05 17:39:26 +03:00
}