|
@@ -1,831 +1,887 @@
|
|
|
#include "Game.h"
|
|
|
-#include "Zeit.h"
|
|
|
-#include "Player.h"
|
|
|
-#include "OverworldDimension.h"
|
|
|
-#include "NoBlock.h"
|
|
|
+
|
|
|
+#include "AddEntityUpdate.h"
|
|
|
#include "AsynchronCall.h"
|
|
|
#include "Entity.h"
|
|
|
-#include "AddEntityUpdate.h"
|
|
|
#include "EntityRemovedUpdate.h"
|
|
|
#include "NetworkMessage.h"
|
|
|
+#include "NoBlock.h"
|
|
|
+#include "OverworldDimension.h"
|
|
|
+#include "Player.h"
|
|
|
+#include "Zeit.h"
|
|
|
|
|
|
using namespace Framework;
|
|
|
|
|
|
char* randomKey(int& len)
|
|
|
{
|
|
|
- len = 1024 + (int)(((double)rand() / RAND_MAX - 0.5) * 512);
|
|
|
- char* key = new char[len];
|
|
|
- for (int i = 0; i < len; i++)
|
|
|
- key[i] = (char)((((double)rand() / RAND_MAX) * 254) + 1);
|
|
|
- return key;
|
|
|
+ len = 1024 + (int)(((double)rand() / RAND_MAX - 0.5) * 512);
|
|
|
+ char* key = new char[len];
|
|
|
+ for (int i = 0; i < len; i++)
|
|
|
+ key[i] = (char)((((double)rand() / RAND_MAX) * 254) + 1);
|
|
|
+ return key;
|
|
|
}
|
|
|
|
|
|
GameClient::GameClient(Player* zPlayer, FCKlient* client)
|
|
|
- : Thread(),
|
|
|
- zPlayer(zPlayer),
|
|
|
- client(client),
|
|
|
- viewDistance(DEFAULT_VIEW_DISTANCE),
|
|
|
- first(1),
|
|
|
- online(1),
|
|
|
- finished(0),
|
|
|
- backgroundFinished(0),
|
|
|
- foregroundFinished(0)
|
|
|
-{
|
|
|
- new AsynchronCall("Game Client Updates", [this]()
|
|
|
- {
|
|
|
- while (online)
|
|
|
- {
|
|
|
- other.lock();
|
|
|
- if (updateQueue.hat(0))
|
|
|
- {
|
|
|
- WorldUpdate* update = updateQueue.get(0);
|
|
|
- updateQueue.remove(0);
|
|
|
- other.unlock();
|
|
|
- background.lock();
|
|
|
- this->client->zBackgroundWriter()->schreibe((char*)&Message::WORLD_UPDATE, 1);
|
|
|
- update->writeAndCheck(this->client->zBackgroundWriter());
|
|
|
- background.unlock();
|
|
|
- update->release();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- other.unlock();
|
|
|
- updateSync.wait();
|
|
|
- }
|
|
|
- }
|
|
|
- finished = 1;
|
|
|
- });
|
|
|
- start();
|
|
|
+ : Thread(),
|
|
|
+ zPlayer(zPlayer),
|
|
|
+ client(client),
|
|
|
+ viewDistance(DEFAULT_VIEW_DISTANCE),
|
|
|
+ first(1),
|
|
|
+ online(1),
|
|
|
+ finished(0),
|
|
|
+ backgroundFinished(0),
|
|
|
+ foregroundFinished(0)
|
|
|
+{
|
|
|
+ new AsynchronCall("Game Client Updates", [this]() {
|
|
|
+ while (online)
|
|
|
+ {
|
|
|
+ other.lock();
|
|
|
+ if (updateQueue.hat(0))
|
|
|
+ {
|
|
|
+ WorldUpdate* update = updateQueue.get(0);
|
|
|
+ updateQueue.remove(0);
|
|
|
+ other.unlock();
|
|
|
+ background.lock();
|
|
|
+ this->client->zBackgroundWriter()->schreibe(
|
|
|
+ (char*)&Message::WORLD_UPDATE, 1);
|
|
|
+ update->writeAndCheck(this->client->zBackgroundWriter());
|
|
|
+ background.unlock();
|
|
|
+ update->release();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ other.unlock();
|
|
|
+ updateSync.wait();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ finished = 1;
|
|
|
+ });
|
|
|
+ start();
|
|
|
}
|
|
|
|
|
|
GameClient::~GameClient()
|
|
|
{
|
|
|
- online = 0;
|
|
|
- updateSync.notify();
|
|
|
- emptyForegroundQueueSync.notifyAll();
|
|
|
- emptyBackgroundQueueSync.notifyAll();
|
|
|
- foregroundQueueSync.notify();
|
|
|
- backgroundQueueSync.notify();
|
|
|
- while (!finished || !foregroundFinished || !backgroundFinished)
|
|
|
- Sleep(100);
|
|
|
- client->release();
|
|
|
+ online = 0;
|
|
|
+ updateSync.notify();
|
|
|
+ emptyForegroundQueueSync.notifyAll();
|
|
|
+ emptyBackgroundQueueSync.notifyAll();
|
|
|
+ foregroundQueueSync.notify();
|
|
|
+ backgroundQueueSync.notify();
|
|
|
+ while (!finished || !foregroundFinished || !backgroundFinished)
|
|
|
+ Sleep(100);
|
|
|
+ client->release();
|
|
|
}
|
|
|
|
|
|
void GameClient::thread()
|
|
|
{
|
|
|
- new AsynchronCall("Game Client Background", [this]()
|
|
|
- {
|
|
|
- while (online)
|
|
|
- {
|
|
|
- queueCs.lock();
|
|
|
- if (backgroundQueue.hat(0))
|
|
|
- {
|
|
|
- NetworkMessage* message = backgroundQueue.get(0);
|
|
|
- backgroundQueue.remove(0);
|
|
|
- queueCs.unlock();
|
|
|
- background.lock();
|
|
|
- message->writeTo(client->zBackgroundWriter());
|
|
|
- background.unlock();
|
|
|
- message->release();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- queueCs.unlock();
|
|
|
- emptyBackgroundQueueSync.notifyAll();
|
|
|
- backgroundQueueSync.wait();
|
|
|
- }
|
|
|
- }
|
|
|
- backgroundFinished = 1;
|
|
|
- });
|
|
|
- while (online)
|
|
|
- {
|
|
|
- queueCs.lock();
|
|
|
- if (foregroundQueue.hat(0))
|
|
|
- {
|
|
|
- NetworkMessage* message = foregroundQueue.get(0);
|
|
|
- foregroundQueue.remove(0);
|
|
|
- queueCs.unlock();
|
|
|
- foreground.lock();
|
|
|
- message->writeTo(client->zForegroundWriter());
|
|
|
- foreground.unlock();
|
|
|
- message->release();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- queueCs.unlock();
|
|
|
- emptyForegroundQueueSync.notifyAll();
|
|
|
- foregroundQueueSync.wait();
|
|
|
- }
|
|
|
- }
|
|
|
- foregroundFinished = 1;
|
|
|
+ new AsynchronCall("Game Client Background", [this]() {
|
|
|
+ while (online)
|
|
|
+ {
|
|
|
+ queueCs.lock();
|
|
|
+ if (backgroundQueue.hat(0))
|
|
|
+ {
|
|
|
+ NetworkMessage* message = backgroundQueue.get(0);
|
|
|
+ backgroundQueue.remove(0);
|
|
|
+ queueCs.unlock();
|
|
|
+ background.lock();
|
|
|
+ message->writeTo(client->zBackgroundWriter());
|
|
|
+ background.unlock();
|
|
|
+ message->release();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ queueCs.unlock();
|
|
|
+ emptyBackgroundQueueSync.notifyAll();
|
|
|
+ backgroundQueueSync.wait();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ backgroundFinished = 1;
|
|
|
+ });
|
|
|
+ while (online)
|
|
|
+ {
|
|
|
+ queueCs.lock();
|
|
|
+ if (foregroundQueue.hat(0))
|
|
|
+ {
|
|
|
+ NetworkMessage* message = foregroundQueue.get(0);
|
|
|
+ foregroundQueue.remove(0);
|
|
|
+ queueCs.unlock();
|
|
|
+ foreground.lock();
|
|
|
+ message->writeTo(client->zForegroundWriter());
|
|
|
+ foreground.unlock();
|
|
|
+ message->release();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ queueCs.unlock();
|
|
|
+ emptyForegroundQueueSync.notifyAll();
|
|
|
+ foregroundQueueSync.wait();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ foregroundFinished = 1;
|
|
|
}
|
|
|
|
|
|
void GameClient::sendWorldUpdate(WorldUpdate* update)
|
|
|
{
|
|
|
- bool add = 0;
|
|
|
- if (zPlayer->getCurrentDimensionId() == update->getAffectedDimension())
|
|
|
- {
|
|
|
- auto pos = (Vec3<int>)zPlayer->getPosition();
|
|
|
- int dist = update->distanceTo(pos.x, pos.y);
|
|
|
- if (dist < viewDistance * CHUNK_SIZE)
|
|
|
- {
|
|
|
- other.lock();
|
|
|
- int index = 0;
|
|
|
- for (auto update2 : updateQueue)
|
|
|
- {
|
|
|
- int dist2 = update2->distanceTo(pos.x, pos.y);
|
|
|
- if (dist2 > dist)
|
|
|
- break;
|
|
|
- index++;
|
|
|
- }
|
|
|
- updateQueue.add(update, index);
|
|
|
- other.unlock();
|
|
|
- updateSync.notify();
|
|
|
- add = 1;
|
|
|
- }
|
|
|
- }
|
|
|
- if (!add)
|
|
|
- update->release();
|
|
|
+ bool add = 0;
|
|
|
+ if (zPlayer->getCurrentDimensionId() == update->getAffectedDimension())
|
|
|
+ {
|
|
|
+ auto pos = (Vec3<int>)zPlayer->getPosition();
|
|
|
+ int dist = update->distanceTo(pos.x, pos.y);
|
|
|
+ if (dist < viewDistance * CHUNK_SIZE)
|
|
|
+ {
|
|
|
+ other.lock();
|
|
|
+ int index = 0;
|
|
|
+ for (auto update2 : updateQueue)
|
|
|
+ {
|
|
|
+ int dist2 = update2->distanceTo(pos.x, pos.y);
|
|
|
+ if (dist2 > dist) break;
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+ updateQueue.add(update, index);
|
|
|
+ other.unlock();
|
|
|
+ updateSync.notify();
|
|
|
+ add = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!add) update->release();
|
|
|
}
|
|
|
|
|
|
void GameClient::reply()
|
|
|
{
|
|
|
- other.lock();
|
|
|
- for (auto req : requests)
|
|
|
- Game::INSTANCE->api(req, this);
|
|
|
- requests.leeren();
|
|
|
- other.unlock();
|
|
|
- if (first)
|
|
|
- {
|
|
|
- foreground.lock();
|
|
|
- int id = zPlayer->getId();
|
|
|
- client->zForegroundWriter()->schreibe((char*)&Message::POSITION_UPDATE, 1);
|
|
|
- client->zForegroundWriter()->schreibe((char*)&id, 4);
|
|
|
- foreground.unlock();
|
|
|
- first = 0;
|
|
|
- }
|
|
|
+ other.lock();
|
|
|
+ for (auto req : requests)
|
|
|
+ Game::INSTANCE->api(req, this);
|
|
|
+ requests.leeren();
|
|
|
+ other.unlock();
|
|
|
+ if (first)
|
|
|
+ {
|
|
|
+ foreground.lock();
|
|
|
+ int id = zPlayer->getId();
|
|
|
+ client->zForegroundWriter()->schreibe(
|
|
|
+ (char*)&Message::POSITION_UPDATE, 1);
|
|
|
+ client->zForegroundWriter()->schreibe((char*)&id, 4);
|
|
|
+ foreground.unlock();
|
|
|
+ first = 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void GameClient::logout()
|
|
|
{
|
|
|
- online = 0;
|
|
|
+ online = 0;
|
|
|
}
|
|
|
|
|
|
void GameClient::addMessage(StreamReader* reader)
|
|
|
{
|
|
|
- short len = 0;
|
|
|
- reader->lese((char*)&len, 2);
|
|
|
- InMemoryBuffer* buffer = new InMemoryBuffer();
|
|
|
- char* tmp = new char[len];
|
|
|
- reader->lese(tmp, len);
|
|
|
- buffer->schreibe(tmp, len);
|
|
|
- delete[]tmp;
|
|
|
- other.lock();
|
|
|
- requests.add(buffer);
|
|
|
- other.unlock();
|
|
|
+ short len = 0;
|
|
|
+ reader->lese((char*)&len, 2);
|
|
|
+ InMemoryBuffer* buffer = new InMemoryBuffer();
|
|
|
+ char* tmp = new char[len];
|
|
|
+ reader->lese(tmp, len);
|
|
|
+ buffer->schreibe(tmp, len);
|
|
|
+ delete[] tmp;
|
|
|
+ other.lock();
|
|
|
+ requests.add(buffer);
|
|
|
+ other.unlock();
|
|
|
}
|
|
|
|
|
|
bool GameClient::isOnline() const
|
|
|
{
|
|
|
- return online;
|
|
|
+ return online;
|
|
|
}
|
|
|
|
|
|
void GameClient::sendResponse(NetworkMessage* response)
|
|
|
{
|
|
|
- queueCs.lock();
|
|
|
- if (response->isUseBackground())
|
|
|
- {
|
|
|
- if (backgroundQueue.getEintragAnzahl() > 20)
|
|
|
- {
|
|
|
- queueCs.unlock();
|
|
|
- emptyBackgroundQueueSync.wait();
|
|
|
- queueCs.lock();
|
|
|
- }
|
|
|
- backgroundQueue.add(response);
|
|
|
- queueCs.unlock();
|
|
|
- backgroundQueueSync.notify();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (foregroundQueue.getEintragAnzahl() > 100)
|
|
|
- {
|
|
|
- queueCs.unlock();
|
|
|
- std::cout << "WARNING: Game paused because nework connection to " << zPlayer->getName() << " is to slow.\n";
|
|
|
- ZeitMesser m;
|
|
|
- m.messungStart();
|
|
|
- emptyForegroundQueueSync.wait();
|
|
|
- m.messungEnde();
|
|
|
- std::cout << "WARNING: Game resumed after " << m.getSekunden() << " seconds.\n";
|
|
|
- queueCs.lock();
|
|
|
- }
|
|
|
- foregroundQueue.add(response);
|
|
|
- queueCs.unlock();
|
|
|
- foregroundQueueSync.notify();
|
|
|
- }
|
|
|
+ queueCs.lock();
|
|
|
+ if (response->isUseBackground())
|
|
|
+ {
|
|
|
+ if (backgroundQueue.getEintragAnzahl() > 20)
|
|
|
+ {
|
|
|
+ queueCs.unlock();
|
|
|
+ emptyBackgroundQueueSync.wait();
|
|
|
+ queueCs.lock();
|
|
|
+ }
|
|
|
+ backgroundQueue.add(response);
|
|
|
+ queueCs.unlock();
|
|
|
+ backgroundQueueSync.notify();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (foregroundQueue.getEintragAnzahl() > 100)
|
|
|
+ {
|
|
|
+ queueCs.unlock();
|
|
|
+ std::cout << "WARNING: Game paused because nework connection to "
|
|
|
+ << zPlayer->getName() << " is to slow.\n";
|
|
|
+ ZeitMesser m;
|
|
|
+ m.messungStart();
|
|
|
+ emptyForegroundQueueSync.wait();
|
|
|
+ m.messungEnde();
|
|
|
+ std::cout << "WARNING: Game resumed after " << m.getSekunden()
|
|
|
+ << " seconds.\n";
|
|
|
+ queueCs.lock();
|
|
|
+ }
|
|
|
+ foregroundQueue.add(response);
|
|
|
+ queueCs.unlock();
|
|
|
+ foregroundQueueSync.notify();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
Player* GameClient::zEntity() const
|
|
|
{
|
|
|
- return zPlayer;
|
|
|
+ return zPlayer;
|
|
|
}
|
|
|
|
|
|
void GameClient::sendTypes()
|
|
|
{
|
|
|
- foreground.lock();
|
|
|
- int count = StaticRegistry<BlockType>::INSTANCE.getCount();
|
|
|
- client->zForegroundWriter()->schreibe((char*)&count, 4);
|
|
|
- for (int i = 0; i < count; i++)
|
|
|
- {
|
|
|
- BlockType* t = StaticRegistry<BlockType>::INSTANCE.zElement(i);
|
|
|
- int id = t->getId();
|
|
|
- client->zForegroundWriter()->schreibe((char*)&id, 4);
|
|
|
- bool inst = t->doesNeedClientInstance();
|
|
|
- client->zForegroundWriter()->schreibe((char*)&inst, 1);
|
|
|
- int maxHp = t->getInitialMaxHP();
|
|
|
- client->zForegroundWriter()->schreibe((char*)&maxHp, 4);
|
|
|
- t->getModel().writeTo(client->zForegroundWriter());
|
|
|
- }
|
|
|
- count = StaticRegistry<ItemType>::INSTANCE.getCount();
|
|
|
- client->zForegroundWriter()->schreibe((char*)&count, 4);
|
|
|
- for (int i = 0; i < count; i++)
|
|
|
- {
|
|
|
- ItemType* t = StaticRegistry<ItemType>::INSTANCE.zElement(i);
|
|
|
- int id = t->getId();
|
|
|
- client->zForegroundWriter()->schreibe((char*)&id, 4);
|
|
|
- t->getModel().writeTo(client->zForegroundWriter());
|
|
|
- }
|
|
|
- count = StaticRegistry<EntityType>::INSTANCE.getCount();
|
|
|
- client->zForegroundWriter()->schreibe((char*)&count, 4);
|
|
|
- for (int i = 0; i < count; i++)
|
|
|
- {
|
|
|
- EntityType* t = StaticRegistry<EntityType>::INSTANCE.zElement(i);
|
|
|
- int id = t->getId();
|
|
|
- client->zForegroundWriter()->schreibe((char*)&id, 4);
|
|
|
- t->getModel().writeTo(client->zForegroundWriter());
|
|
|
- }
|
|
|
- foreground.unlock();
|
|
|
+ foreground.lock();
|
|
|
+ int count = StaticRegistry<BlockType>::INSTANCE.getCount();
|
|
|
+ client->zForegroundWriter()->schreibe((char*)&count, 4);
|
|
|
+ for (int i = 0; i < count; i++)
|
|
|
+ {
|
|
|
+ BlockType* t = StaticRegistry<BlockType>::INSTANCE.zElement(i);
|
|
|
+ int id = t->getId();
|
|
|
+ client->zForegroundWriter()->schreibe((char*)&id, 4);
|
|
|
+ bool inst = t->doesNeedClientInstance();
|
|
|
+ client->zForegroundWriter()->schreibe((char*)&inst, 1);
|
|
|
+ int maxHp = t->getInitialMaxHP();
|
|
|
+ client->zForegroundWriter()->schreibe((char*)&maxHp, 4);
|
|
|
+ t->getModel().writeTo(client->zForegroundWriter());
|
|
|
+ }
|
|
|
+ count = 0;
|
|
|
+ for (int i = 0; i < StaticRegistry<ItemType>::INSTANCE.getCount(); i++)
|
|
|
+ {
|
|
|
+ if (StaticRegistry<ItemType>::INSTANCE.zElement(i)) count++;
|
|
|
+ }
|
|
|
+ client->zForegroundWriter()->schreibe((char*)&count, 4);
|
|
|
+ for (int i = 0; i < StaticRegistry<ItemType>::INSTANCE.getCount(); i++)
|
|
|
+ {
|
|
|
+ if (StaticRegistry<ItemType>::INSTANCE.zElement(i))
|
|
|
+ {
|
|
|
+ ItemType* t = StaticRegistry<ItemType>::INSTANCE.zElement(i);
|
|
|
+ int id = t->getId();
|
|
|
+ client->zForegroundWriter()->schreibe((char*)&id, 4);
|
|
|
+ t->getModel().writeTo(client->zForegroundWriter());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ count = StaticRegistry<EntityType>::INSTANCE.getCount();
|
|
|
+ client->zForegroundWriter()->schreibe((char*)&count, 4);
|
|
|
+ for (int i = 0; i < count; i++)
|
|
|
+ {
|
|
|
+ EntityType* t = StaticRegistry<EntityType>::INSTANCE.zElement(i);
|
|
|
+ int id = t->getId();
|
|
|
+ client->zForegroundWriter()->schreibe((char*)&id, 4);
|
|
|
+ t->getModel().writeTo(client->zForegroundWriter());
|
|
|
+ }
|
|
|
+ foreground.unlock();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
Game::Game(Framework::Text name, Framework::Text worldsDir)
|
|
|
- : Thread(),
|
|
|
- name(name),
|
|
|
- dimensions(new RCArray<Dimension>()),
|
|
|
- updates(new RCArray<WorldUpdate>()),
|
|
|
- clients(new RCArray<GameClient>()),
|
|
|
- ticker(new TickOrganizer()),
|
|
|
- path((const char*)(worldsDir + "/" + name)),
|
|
|
- stop(0),
|
|
|
- tickId(0),
|
|
|
- nextEntityId(0),
|
|
|
- generator(0),
|
|
|
- loader(0),
|
|
|
- totalTickTime(0),
|
|
|
- tickCounter(0)
|
|
|
-{
|
|
|
- if (!DateiExistiert(worldsDir + "/" + name))
|
|
|
- DateiPfadErstellen(worldsDir + "/" + name + "/");
|
|
|
- Datei d;
|
|
|
- d.setDatei(path + "/eid");
|
|
|
- if (d.existiert())
|
|
|
- {
|
|
|
- d.open(Datei::Style::lesen);
|
|
|
- d.lese((char*)&nextEntityId, 4);
|
|
|
- d.close();
|
|
|
- }
|
|
|
- start();
|
|
|
+ : Thread(),
|
|
|
+ name(name),
|
|
|
+ dimensions(new RCArray<Dimension>()),
|
|
|
+ updates(new RCArray<WorldUpdate>()),
|
|
|
+ clients(new RCArray<GameClient>()),
|
|
|
+ ticker(new TickOrganizer()),
|
|
|
+ path((const char*)(worldsDir + "/" + name)),
|
|
|
+ stop(0),
|
|
|
+ tickId(0),
|
|
|
+ nextEntityId(0),
|
|
|
+ generator(0),
|
|
|
+ loader(0),
|
|
|
+ totalTickTime(0),
|
|
|
+ tickCounter(0)
|
|
|
+{
|
|
|
+ if (!DateiExistiert(worldsDir + "/" + name))
|
|
|
+ DateiPfadErstellen(worldsDir + "/" + name + "/");
|
|
|
+ Datei d;
|
|
|
+ d.setDatei(path + "/eid");
|
|
|
+ if (d.existiert())
|
|
|
+ {
|
|
|
+ d.open(Datei::Style::lesen);
|
|
|
+ d.lese((char*)&nextEntityId, 4);
|
|
|
+ d.close();
|
|
|
+ }
|
|
|
+ start();
|
|
|
}
|
|
|
|
|
|
Game::~Game()
|
|
|
{
|
|
|
- dimensions->release();
|
|
|
- updates->release();
|
|
|
- clients->release();
|
|
|
- generator->release();
|
|
|
- loader->release();
|
|
|
+ dimensions->release();
|
|
|
+ updates->release();
|
|
|
+ clients->release();
|
|
|
+ generator->release();
|
|
|
+ loader->release();
|
|
|
}
|
|
|
|
|
|
void Game::initialize()
|
|
|
{
|
|
|
- int seed = 0;
|
|
|
- int index = 0;
|
|
|
- for (const char* n = name; *n; n++)
|
|
|
- seed += (int)pow((float)*n * 31, (float)++index);
|
|
|
- generator = new WorldGenerator(seed);
|
|
|
- loader = new WorldLoader();
|
|
|
- recipies.loadRecipies("data/recipies");
|
|
|
+ int seed = 0;
|
|
|
+ int index = 0;
|
|
|
+ for (const char* n = name; *n; n++)
|
|
|
+ seed += (int)pow((float)*n * 31, (float)++index);
|
|
|
+ generator = new WorldGenerator(seed);
|
|
|
+ loader = new WorldLoader();
|
|
|
+ recipies.loadRecipies("data/recipies");
|
|
|
}
|
|
|
|
|
|
void Game::thread()
|
|
|
{
|
|
|
- ZeitMesser waitForLock;
|
|
|
- ZeitMesser removeOldClients;
|
|
|
- ZeitMesser tickEntities;
|
|
|
- ZeitMesser worldUpdates;
|
|
|
- ZeitMesser clientReply;
|
|
|
- ZeitMesser removeOldChunks;
|
|
|
- ZeitMesser m;
|
|
|
- while (!stop)
|
|
|
- {
|
|
|
- m.messungStart();
|
|
|
- ticker->nextTick();
|
|
|
- actionsCs.lock();
|
|
|
- while (actions.getEintragAnzahl() > 0)
|
|
|
- {
|
|
|
- actions.get(0)();
|
|
|
- actions.remove(0);
|
|
|
- }
|
|
|
- actionsCs.unlock();
|
|
|
- Array<int> removed;
|
|
|
- double waitTotal = 0;
|
|
|
- waitForLock.messungStart();
|
|
|
- cs.lock();
|
|
|
- waitForLock.messungEnde();
|
|
|
- waitTotal += waitForLock.getSekunden();
|
|
|
- removeOldClients.messungStart();
|
|
|
- int index = 0;
|
|
|
- for (auto player : *clients)
|
|
|
- {
|
|
|
- if (!player->isOnline())
|
|
|
- {
|
|
|
- std::cout << "player " << player->zEntity()->getName() << " disconnected.\n";
|
|
|
- Datei pFile;
|
|
|
- pFile.setDatei(path + "/player/" + player->zEntity()->getName());
|
|
|
- pFile.erstellen();
|
|
|
- if (pFile.open(Datei::Style::schreiben))
|
|
|
- PlayerEntityType::INSTANCE->saveEntity(player->zEntity(), &pFile);
|
|
|
- pFile.close();
|
|
|
- removed.add(index, 0);
|
|
|
- Dimension* dim = zDimension(player->zEntity()->getCurrentDimensionId());
|
|
|
- dim->removeSubscriptions(player->zEntity());
|
|
|
- this->requestWorldUpdate(new EntityRemovedUpdate(player->zEntity()->getId(), player->zEntity()->getCurrentDimensionId(), player->zEntity()->getPosition()));
|
|
|
-
|
|
|
- }
|
|
|
- index++;
|
|
|
- }
|
|
|
- for (auto i : removed)
|
|
|
- clients->remove(i);
|
|
|
- removeOldClients.messungEnde();
|
|
|
- cs.unlock();
|
|
|
- tickEntities.messungStart();
|
|
|
- for (auto dim : *dimensions)
|
|
|
- dim->tickEntities();
|
|
|
- tickEntities.messungEnde();
|
|
|
- waitForLock.messungStart();
|
|
|
- cs.lock();
|
|
|
- waitForLock.messungEnde();
|
|
|
- waitTotal += waitForLock.getSekunden();
|
|
|
- worldUpdates.messungStart();
|
|
|
- while (updates->hat(0))
|
|
|
- {
|
|
|
- WorldUpdate* update = updates->z(0);
|
|
|
- for (auto client : *clients)
|
|
|
- client->sendWorldUpdate(dynamic_cast<WorldUpdate*>(update->getThis()));
|
|
|
- if (!zDimension(update->getAffectedDimension()))
|
|
|
- addDimension(new Dimension(update->getAffectedDimension()));
|
|
|
- update->onUpdate(zDimension(update->getAffectedDimension()));
|
|
|
- updates->remove(0);
|
|
|
- }
|
|
|
- worldUpdates.messungEnde();
|
|
|
- cs.unlock();
|
|
|
- clientReply.messungStart();
|
|
|
- for (auto client : *clients)
|
|
|
- client->reply();
|
|
|
- clientReply.messungEnde();
|
|
|
- waitForLock.messungStart();
|
|
|
- cs.lock();
|
|
|
- waitForLock.messungEnde();
|
|
|
- waitTotal += waitForLock.getSekunden();
|
|
|
- removeOldChunks.messungStart();
|
|
|
- for (auto dim : *dimensions)
|
|
|
- dim->removeOldChunks();
|
|
|
- removeOldChunks.messungEnde();
|
|
|
- cs.unlock();
|
|
|
- m.messungEnde();
|
|
|
- double sec = m.getSekunden();
|
|
|
- tickCounter++;
|
|
|
- totalTickTime += sec;
|
|
|
- if (tickCounter >= 1000)
|
|
|
- {
|
|
|
- std::cout << "Average Tick time: " << (totalTickTime / 1000) << "\n";
|
|
|
- if ((totalTickTime / 1000) * 20 > 1)
|
|
|
- {
|
|
|
- std::cout << "The game runns slower than normal.\n";
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- std::cout << "No performance issues detected.\n";
|
|
|
- }
|
|
|
- totalTickTime = 0;
|
|
|
- tickCounter = 0;
|
|
|
- }
|
|
|
- if (sec < 0.05)
|
|
|
- Sleep((int)((0.05 - sec) * 1000));
|
|
|
- else if (sec > 1)
|
|
|
- {
|
|
|
- std::cout << "WARNING: tick needed " << sec << " seconds. The game will run sower then normal.\n";
|
|
|
- std::cout << "waiting: " << waitTotal << "\nremoveOldClients: " << removeOldClients.getSekunden() << "\ntickEntities:" << tickEntities.getSekunden() << "\nworldUpdates: " << worldUpdates.getSekunden() << "\nclientReply: " << clientReply.getSekunden() << "\nremoveOldChunks:" << removeOldChunks.getSekunden() << "\n";
|
|
|
- }
|
|
|
- }
|
|
|
- save();
|
|
|
+ ZeitMesser waitForLock;
|
|
|
+ ZeitMesser removeOldClients;
|
|
|
+ ZeitMesser tickEntities;
|
|
|
+ ZeitMesser worldUpdates;
|
|
|
+ ZeitMesser clientReply;
|
|
|
+ ZeitMesser removeOldChunks;
|
|
|
+ ZeitMesser m;
|
|
|
+ while (!stop)
|
|
|
+ {
|
|
|
+ m.messungStart();
|
|
|
+ ticker->nextTick();
|
|
|
+ actionsCs.lock();
|
|
|
+ while (actions.getEintragAnzahl() > 0)
|
|
|
+ {
|
|
|
+ actions.get(0)();
|
|
|
+ actions.remove(0);
|
|
|
+ }
|
|
|
+ actionsCs.unlock();
|
|
|
+ Array<int> removed;
|
|
|
+ double waitTotal = 0;
|
|
|
+ waitForLock.messungStart();
|
|
|
+ cs.lock();
|
|
|
+ waitForLock.messungEnde();
|
|
|
+ waitTotal += waitForLock.getSekunden();
|
|
|
+ removeOldClients.messungStart();
|
|
|
+ int index = 0;
|
|
|
+ for (auto player : *clients)
|
|
|
+ {
|
|
|
+ if (!player->isOnline())
|
|
|
+ {
|
|
|
+ std::cout << "player " << player->zEntity()->getName()
|
|
|
+ << " disconnected.\n";
|
|
|
+ Datei pFile;
|
|
|
+ pFile.setDatei(
|
|
|
+ path + "/player/" + player->zEntity()->getName());
|
|
|
+ pFile.erstellen();
|
|
|
+ if (pFile.open(Datei::Style::schreiben))
|
|
|
+ StaticRegistry<EntityType>::INSTANCE
|
|
|
+ .zElement(EntityTypeEnum::PLAYER)
|
|
|
+ ->saveEntity(player->zEntity(), &pFile);
|
|
|
+ pFile.close();
|
|
|
+ removed.add(index, 0);
|
|
|
+ Dimension* dim
|
|
|
+ = zDimension(player->zEntity()->getCurrentDimensionId());
|
|
|
+ dim->removeSubscriptions(player->zEntity());
|
|
|
+ this->requestWorldUpdate(
|
|
|
+ new EntityRemovedUpdate(player->zEntity()->getId(),
|
|
|
+ player->zEntity()->getCurrentDimensionId(),
|
|
|
+ player->zEntity()->getPosition()));
|
|
|
+ }
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+ for (auto i : removed)
|
|
|
+ clients->remove(i);
|
|
|
+ removeOldClients.messungEnde();
|
|
|
+ cs.unlock();
|
|
|
+ tickEntities.messungStart();
|
|
|
+ for (auto dim : *dimensions)
|
|
|
+ dim->tickEntities();
|
|
|
+ tickEntities.messungEnde();
|
|
|
+ waitForLock.messungStart();
|
|
|
+ cs.lock();
|
|
|
+ waitForLock.messungEnde();
|
|
|
+ waitTotal += waitForLock.getSekunden();
|
|
|
+ worldUpdates.messungStart();
|
|
|
+ while (updates->hat(0))
|
|
|
+ {
|
|
|
+ WorldUpdate* update = updates->z(0);
|
|
|
+ for (auto client : *clients)
|
|
|
+ client->sendWorldUpdate(
|
|
|
+ dynamic_cast<WorldUpdate*>(update->getThis()));
|
|
|
+ if (!zDimension(update->getAffectedDimension()))
|
|
|
+ addDimension(new Dimension(update->getAffectedDimension()));
|
|
|
+ update->onUpdate(zDimension(update->getAffectedDimension()));
|
|
|
+ updates->remove(0);
|
|
|
+ }
|
|
|
+ worldUpdates.messungEnde();
|
|
|
+ cs.unlock();
|
|
|
+ clientReply.messungStart();
|
|
|
+ for (auto client : *clients)
|
|
|
+ client->reply();
|
|
|
+ clientReply.messungEnde();
|
|
|
+ waitForLock.messungStart();
|
|
|
+ cs.lock();
|
|
|
+ waitForLock.messungEnde();
|
|
|
+ waitTotal += waitForLock.getSekunden();
|
|
|
+ removeOldChunks.messungStart();
|
|
|
+ for (auto dim : *dimensions)
|
|
|
+ dim->removeOldChunks();
|
|
|
+ removeOldChunks.messungEnde();
|
|
|
+ cs.unlock();
|
|
|
+ m.messungEnde();
|
|
|
+ double sec = m.getSekunden();
|
|
|
+ tickCounter++;
|
|
|
+ totalTickTime += sec;
|
|
|
+ if (tickCounter >= 1000)
|
|
|
+ {
|
|
|
+ std::cout << "Average Tick time: " << (totalTickTime / 1000)
|
|
|
+ << "\n";
|
|
|
+ if ((totalTickTime / 1000) * 20 > 1)
|
|
|
+ {
|
|
|
+ std::cout << "The game runns slower than normal.\n";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ std::cout << "No performance issues detected.\n";
|
|
|
+ }
|
|
|
+ totalTickTime = 0;
|
|
|
+ tickCounter = 0;
|
|
|
+ }
|
|
|
+ if (sec < 0.05)
|
|
|
+ Sleep((int)((0.05 - sec) * 1000));
|
|
|
+ else if (sec > 1)
|
|
|
+ {
|
|
|
+ std::cout << "WARNING: tick needed " << sec
|
|
|
+ << " seconds. The game will run sower then normal.\n";
|
|
|
+ std::cout << "waiting: " << waitTotal << "\nremoveOldClients: "
|
|
|
+ << removeOldClients.getSekunden()
|
|
|
+ << "\ntickEntities:" << tickEntities.getSekunden()
|
|
|
+ << "\nworldUpdates: " << worldUpdates.getSekunden()
|
|
|
+ << "\nclientReply: " << clientReply.getSekunden()
|
|
|
+ << "\nremoveOldChunks:" << removeOldChunks.getSekunden()
|
|
|
+ << "\n";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ save();
|
|
|
}
|
|
|
|
|
|
void Game::api(Framework::InMemoryBuffer* zRequest, GameClient* zOrigin)
|
|
|
{
|
|
|
- char type;
|
|
|
- zRequest->lese(&type, 1);
|
|
|
- NetworkMessage* response = new NetworkMessage();
|
|
|
- switch (type)
|
|
|
- {
|
|
|
- case 1: // world
|
|
|
- {
|
|
|
- Dimension* dim = zDimension(zOrigin->zEntity()->getCurrentDimensionId());
|
|
|
- if (!dim)
|
|
|
- {
|
|
|
- dim = new Dimension(zOrigin->zEntity()->getCurrentDimensionId());
|
|
|
- addDimension(dim);
|
|
|
- }
|
|
|
- dim->api(zRequest, response, zOrigin->zEntity());
|
|
|
- break;
|
|
|
- }
|
|
|
- case 2: // player
|
|
|
- zOrigin->zEntity()->playerApi(zRequest, response);
|
|
|
- break;
|
|
|
- case 3: // entity
|
|
|
- {
|
|
|
- int id;
|
|
|
- zRequest->lese((char*)&id, 4);
|
|
|
- for (Dimension* dim : *dimensions)
|
|
|
- {
|
|
|
- Entity* entity = dim->zEntity(id);
|
|
|
- if (entity)
|
|
|
- {
|
|
|
- entity->api(zRequest, response);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- case 4:
|
|
|
- { // inventory
|
|
|
- bool isEntity;
|
|
|
- zRequest->lese((char*)&isEntity, 1);
|
|
|
- Inventory* target;
|
|
|
- if (isEntity)
|
|
|
- {
|
|
|
- int id;
|
|
|
- zRequest->lese((char*)&id, 4);
|
|
|
- target = zEntity(id);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- int dim;
|
|
|
- Vec3<int> pos;
|
|
|
- zRequest->lese((char*)&dim, 4);
|
|
|
- zRequest->lese((char*)&pos.x, 4);
|
|
|
- zRequest->lese((char*)&pos.y, 4);
|
|
|
- zRequest->lese((char*)&pos.z, 4);
|
|
|
- target = zBlockAt(pos, dim);
|
|
|
- }
|
|
|
- if (target)
|
|
|
- target->inventoryApi(zRequest, response, zOrigin->zEntity());
|
|
|
- break;
|
|
|
- }
|
|
|
- default:
|
|
|
- std::cout << "received unknown api request in game with type " << (int)type << "\n";
|
|
|
- }
|
|
|
- if (!response->isEmpty())
|
|
|
- {
|
|
|
- if (response->isBroadcast())
|
|
|
- broadcastMessage(response);
|
|
|
- else
|
|
|
- zOrigin->sendResponse(response);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- response->release();
|
|
|
- }
|
|
|
+ char type;
|
|
|
+ zRequest->lese(&type, 1);
|
|
|
+ NetworkMessage* response = new NetworkMessage();
|
|
|
+ switch (type)
|
|
|
+ {
|
|
|
+ case 1: // world
|
|
|
+ {
|
|
|
+ Dimension* dim
|
|
|
+ = zDimension(zOrigin->zEntity()->getCurrentDimensionId());
|
|
|
+ if (!dim)
|
|
|
+ {
|
|
|
+ dim = new Dimension(
|
|
|
+ zOrigin->zEntity()->getCurrentDimensionId());
|
|
|
+ addDimension(dim);
|
|
|
+ }
|
|
|
+ dim->api(zRequest, response, zOrigin->zEntity());
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 2: // player
|
|
|
+ zOrigin->zEntity()->playerApi(zRequest, response);
|
|
|
+ break;
|
|
|
+ case 3: // entity
|
|
|
+ {
|
|
|
+ int id;
|
|
|
+ zRequest->lese((char*)&id, 4);
|
|
|
+ for (Dimension* dim : *dimensions)
|
|
|
+ {
|
|
|
+ Entity* entity = dim->zEntity(id);
|
|
|
+ if (entity)
|
|
|
+ {
|
|
|
+ entity->api(zRequest, response);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 4:
|
|
|
+ { // inventory
|
|
|
+ bool isEntity;
|
|
|
+ zRequest->lese((char*)&isEntity, 1);
|
|
|
+ Inventory* target;
|
|
|
+ if (isEntity)
|
|
|
+ {
|
|
|
+ int id;
|
|
|
+ zRequest->lese((char*)&id, 4);
|
|
|
+ target = zEntity(id);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ int dim;
|
|
|
+ Vec3<int> pos;
|
|
|
+ zRequest->lese((char*)&dim, 4);
|
|
|
+ zRequest->lese((char*)&pos.x, 4);
|
|
|
+ zRequest->lese((char*)&pos.y, 4);
|
|
|
+ zRequest->lese((char*)&pos.z, 4);
|
|
|
+ target = zBlockAt(pos, dim);
|
|
|
+ }
|
|
|
+ if (target)
|
|
|
+ target->inventoryApi(zRequest, response, zOrigin->zEntity());
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ std::cout << "received unknown api request in game with type "
|
|
|
+ << (int)type << "\n";
|
|
|
+ }
|
|
|
+ if (!response->isEmpty())
|
|
|
+ {
|
|
|
+ if (response->isBroadcast())
|
|
|
+ broadcastMessage(response);
|
|
|
+ else
|
|
|
+ zOrigin->sendResponse(response);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ response->release();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void Game::updateLightning(int dimensionId, Vec3<int> location)
|
|
|
{
|
|
|
- Dimension* zDim = zDimension(dimensionId);
|
|
|
- if (zDim)
|
|
|
- zDim->updateLightning(location);
|
|
|
+ Dimension* zDim = zDimension(dimensionId);
|
|
|
+ if (zDim) zDim->updateLightning(location);
|
|
|
}
|
|
|
|
|
|
void Game::updateLightningWithoutWait(int dimensionId, Vec3<int> location)
|
|
|
{
|
|
|
- Dimension* zDim = zDimension(dimensionId);
|
|
|
- if (zDim)
|
|
|
- zDim->updateLightningWithoutWait(location);
|
|
|
+ Dimension* zDim = zDimension(dimensionId);
|
|
|
+ if (zDim) zDim->updateLightningWithoutWait(location);
|
|
|
}
|
|
|
|
|
|
void Game::broadcastMessage(NetworkMessage* response)
|
|
|
{
|
|
|
- for (auto client : *clients)
|
|
|
- client->sendResponse(dynamic_cast<NetworkMessage*>(response->getThis()));
|
|
|
+ for (auto client : *clients)
|
|
|
+ client->sendResponse(
|
|
|
+ dynamic_cast<NetworkMessage*>(response->getThis()));
|
|
|
}
|
|
|
|
|
|
void Game::sendMessage(NetworkMessage* response, Entity* zTargetPlayer)
|
|
|
{
|
|
|
- for (auto client : *clients)
|
|
|
- {
|
|
|
- if (client->zEntity()->getId() == zTargetPlayer->getId())
|
|
|
- {
|
|
|
- client->sendResponse(response);
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- response->release();
|
|
|
+ for (auto client : *clients)
|
|
|
+ {
|
|
|
+ if (client->zEntity()->getId() == zTargetPlayer->getId())
|
|
|
+ {
|
|
|
+ client->sendResponse(response);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ response->release();
|
|
|
}
|
|
|
|
|
|
bool Game::requestWorldUpdate(WorldUpdate* update)
|
|
|
{
|
|
|
- cs.lock();
|
|
|
- for (WorldUpdate* u : *updates)
|
|
|
- {
|
|
|
- if (u->getMaxAffectedPoint().x >= update->getMinAffectedPoint().x && u->getMinAffectedPoint().x <= update->getMaxAffectedPoint().x &&
|
|
|
- u->getMaxAffectedPoint().y >= update->getMinAffectedPoint().y && u->getMinAffectedPoint().y <= update->getMaxAffectedPoint().y &&
|
|
|
- u->getMaxAffectedPoint().z >= update->getMinAffectedPoint().z && u->getMinAffectedPoint().z <= update->getMaxAffectedPoint().z && u->getType() == update->getType())
|
|
|
- {
|
|
|
- cs.unlock();
|
|
|
- update->release();
|
|
|
- return 0;
|
|
|
- }
|
|
|
- }
|
|
|
- updates->add(update);
|
|
|
- cs.unlock();
|
|
|
- return 1;
|
|
|
+ cs.lock();
|
|
|
+ for (WorldUpdate* u : *updates)
|
|
|
+ {
|
|
|
+ if (u->getMaxAffectedPoint().x >= update->getMinAffectedPoint().x
|
|
|
+ && u->getMinAffectedPoint().x <= update->getMaxAffectedPoint().x
|
|
|
+ && u->getMaxAffectedPoint().y >= update->getMinAffectedPoint().y
|
|
|
+ && u->getMinAffectedPoint().y <= update->getMaxAffectedPoint().y
|
|
|
+ && u->getMaxAffectedPoint().z >= update->getMinAffectedPoint().z
|
|
|
+ && u->getMinAffectedPoint().z <= update->getMaxAffectedPoint().z
|
|
|
+ && u->getType() == update->getType())
|
|
|
+ {
|
|
|
+ cs.unlock();
|
|
|
+ update->release();
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ updates->add(update);
|
|
|
+ cs.unlock();
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
bool Game::checkPlayer(Framework::Text name, Framework::Text secret)
|
|
|
{
|
|
|
- Datei pFile;
|
|
|
- pFile.setDatei(path + "/player/" + name + ".key");
|
|
|
- if (!pFile.existiert())
|
|
|
- {
|
|
|
- if (!secret.getLength())
|
|
|
- return 1;
|
|
|
- else
|
|
|
- {
|
|
|
- std::cout << "player " << name.getText() << " tryed to connect with an invalid secret.\n";
|
|
|
- return 0;
|
|
|
- }
|
|
|
- }
|
|
|
- pFile.open(Datei::Style::lesen);
|
|
|
- char* buffer = new char[(int)pFile.getSize()];
|
|
|
- pFile.lese(buffer, (int)pFile.getSize());
|
|
|
- bool eq = 1;
|
|
|
- int sLen = secret.getLength();
|
|
|
- for (int i = 0; i < pFile.getSize(); i++) // !!SECURITY!! runtime should not be dependent on the position of the first unequal character in the secret
|
|
|
- eq &= buffer[i] == (sLen > i ? secret[i] : ~buffer[i]);
|
|
|
- delete[] buffer;
|
|
|
- pFile.close();
|
|
|
- if (!eq)
|
|
|
- {
|
|
|
- std::cout << "player " << name.getText() << " tryed to connect with an invalid secret.\n";
|
|
|
- }
|
|
|
- return eq;
|
|
|
+ Datei pFile;
|
|
|
+ pFile.setDatei(path + "/player/" + name + ".key");
|
|
|
+ if (!pFile.existiert())
|
|
|
+ {
|
|
|
+ if (!secret.getLength())
|
|
|
+ return 1;
|
|
|
+ else
|
|
|
+ {
|
|
|
+ std::cout << "player " << name.getText()
|
|
|
+ << " tryed to connect with an invalid secret.\n";
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pFile.open(Datei::Style::lesen);
|
|
|
+ char* buffer = new char[(int)pFile.getSize()];
|
|
|
+ pFile.lese(buffer, (int)pFile.getSize());
|
|
|
+ bool eq = 1;
|
|
|
+ int sLen = secret.getLength();
|
|
|
+ for (int i = 0; i < pFile.getSize();
|
|
|
+ i++) // !!SECURITY!! runtime should not be dependent on the position of
|
|
|
+ // the first unequal character in the secret
|
|
|
+ eq &= buffer[i] == (sLen > i ? secret[i] : ~buffer[i]);
|
|
|
+ delete[] buffer;
|
|
|
+ pFile.close();
|
|
|
+ if (!eq)
|
|
|
+ {
|
|
|
+ std::cout << "player " << name.getText()
|
|
|
+ << " tryed to connect with an invalid secret.\n";
|
|
|
+ }
|
|
|
+ return eq;
|
|
|
}
|
|
|
|
|
|
bool Game::existsPlayer(Framework::Text name)
|
|
|
{
|
|
|
- Datei pFile;
|
|
|
- pFile.setDatei(path + "/player/" + name + ".key");
|
|
|
- return pFile.existiert();
|
|
|
+ Datei pFile;
|
|
|
+ pFile.setDatei(path + "/player/" + name + ".key");
|
|
|
+ return pFile.existiert();
|
|
|
}
|
|
|
|
|
|
Framework::Text Game::createPlayer(Framework::Text name)
|
|
|
{
|
|
|
- Datei pFile;
|
|
|
- pFile.setDatei(path + "/player/" + name + ".key");
|
|
|
- if (!pFile.existiert())
|
|
|
- {
|
|
|
- pFile.erstellen();
|
|
|
- int keyLen;
|
|
|
- char* key = randomKey(keyLen);
|
|
|
- pFile.open(Datei::Style::schreiben);
|
|
|
- pFile.schreibe(key, keyLen);
|
|
|
- pFile.close();
|
|
|
- Text res = "";
|
|
|
- for (int i = 0; i < keyLen; i++)
|
|
|
- res.append(key[i]);
|
|
|
- delete[] key;
|
|
|
- return res;
|
|
|
- }
|
|
|
- return "";
|
|
|
+ Datei pFile;
|
|
|
+ pFile.setDatei(path + "/player/" + name + ".key");
|
|
|
+ if (!pFile.existiert())
|
|
|
+ {
|
|
|
+ pFile.erstellen();
|
|
|
+ int keyLen;
|
|
|
+ char* key = randomKey(keyLen);
|
|
|
+ pFile.open(Datei::Style::schreiben);
|
|
|
+ pFile.schreibe(key, keyLen);
|
|
|
+ pFile.close();
|
|
|
+ Text res = "";
|
|
|
+ for (int i = 0; i < keyLen; i++)
|
|
|
+ res.append(key[i]);
|
|
|
+ delete[] key;
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+ return "";
|
|
|
}
|
|
|
|
|
|
GameClient* Game::addPlayer(FCKlient* client, Framework::Text name)
|
|
|
{
|
|
|
- cs.lock();
|
|
|
- Datei pFile;
|
|
|
- pFile.setDatei(path + "/player/" + name);
|
|
|
- std::cout << "player " << name.getText() << " connected.\n";
|
|
|
- Player* player;
|
|
|
- bool isNew = 0;
|
|
|
- if (!pFile.existiert() || !pFile.open(Datei::Style::lesen))
|
|
|
- {
|
|
|
- player = (Player*)PlayerEntityType::INSTANCE->createEntityAt(Vec3<float>(0.5, 0.5, 0), OverworldDimension::ID);
|
|
|
- player->setName(name);
|
|
|
- isNew = 1;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- player = (Player*)PlayerEntityType::INSTANCE->loadEntity(&pFile);
|
|
|
- pFile.close();
|
|
|
- }
|
|
|
- if (player->getId() >= nextEntityId)
|
|
|
- {
|
|
|
- nextEntityId = player->getId() + 1;
|
|
|
- }
|
|
|
- GameClient* gameClient = new GameClient(player, client);
|
|
|
- gameClient->sendTypes();
|
|
|
- clients->add(gameClient);
|
|
|
- if (!zDimension(player->getCurrentDimensionId()))
|
|
|
- {
|
|
|
- this->addDimension(new Dimension(player->getCurrentDimensionId()));
|
|
|
- }
|
|
|
- // subscribe the new player as an observer of the new chunk
|
|
|
- Dimension* dim = zDimension(player->getCurrentDimensionId());
|
|
|
- InMemoryBuffer* buffer = new InMemoryBuffer();
|
|
|
- buffer->schreibe("\0", 1);
|
|
|
- Punkt center = getChunkCenter((int)player->getPosition().x, (int)player->getPosition().y);
|
|
|
- buffer->schreibe((char*)¢er.x, 4);
|
|
|
- buffer->schreibe((char*)¢er.y, 4);
|
|
|
- buffer->schreibe("\0", 1);
|
|
|
- dim->api(buffer, 0, player);
|
|
|
- buffer->release();
|
|
|
- while (isNew && !dim->zChunk(getChunkCenter((int)player->getPosition().x, (int)player->getPosition().y)))
|
|
|
- {
|
|
|
- cs.unlock();
|
|
|
- Sleep(1000);
|
|
|
- cs.lock();
|
|
|
- }
|
|
|
- if (isNew)
|
|
|
- {
|
|
|
- Either<Block*, int> b = AirBlockBlockType::ID;
|
|
|
- int h = WORLD_HEIGHT;
|
|
|
- while (((b.isA() && (!(Block*)b || ((Block*)b)->isPassable())) || (b.isB() && StaticRegistry<BlockType>::INSTANCE.zElement(b)->zDefault()->isPassable())) && h > 0)
|
|
|
- b = zBlockAt({ (int)player->getPosition().x, (int)player->getPosition().y, --h }, player->getCurrentDimensionId());
|
|
|
- player->setPosition({ player->getPosition().x, player->getPosition().y, (float)h + 1.f });
|
|
|
- }
|
|
|
- requestWorldUpdate(new AddEntityUpdate(player, player->getCurrentDimensionId()));
|
|
|
- cs.unlock();
|
|
|
- return dynamic_cast<GameClient*>(gameClient->getThis());
|
|
|
+ cs.lock();
|
|
|
+ Datei pFile;
|
|
|
+ pFile.setDatei(path + "/player/" + name);
|
|
|
+ std::cout << "player " << name.getText() << " connected.\n";
|
|
|
+ Player* player;
|
|
|
+ bool isNew = 0;
|
|
|
+ if (!pFile.existiert() || !pFile.open(Datei::Style::lesen))
|
|
|
+ {
|
|
|
+ player = (Player*)StaticRegistry<EntityType>::INSTANCE
|
|
|
+ .zElement(EntityTypeEnum::PLAYER)
|
|
|
+ ->createEntityAt(
|
|
|
+ Vec3<float>(0.5, 0.5, 0), DimensionEnum::OVERWORLD);
|
|
|
+ player->setName(name);
|
|
|
+ isNew = 1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ player = (Player*)StaticRegistry<EntityType>::INSTANCE
|
|
|
+ .zElement(EntityTypeEnum::PLAYER)
|
|
|
+ ->loadEntity(&pFile);
|
|
|
+ pFile.close();
|
|
|
+ }
|
|
|
+ if (player->getId() >= nextEntityId)
|
|
|
+ {
|
|
|
+ nextEntityId = player->getId() + 1;
|
|
|
+ }
|
|
|
+ GameClient* gameClient = new GameClient(player, client);
|
|
|
+ gameClient->sendTypes();
|
|
|
+ clients->add(gameClient);
|
|
|
+ if (!zDimension(player->getCurrentDimensionId()))
|
|
|
+ {
|
|
|
+ this->addDimension(new Dimension(player->getCurrentDimensionId()));
|
|
|
+ }
|
|
|
+ // subscribe the new player as an observer of the new chunk
|
|
|
+ Dimension* dim = zDimension(player->getCurrentDimensionId());
|
|
|
+ InMemoryBuffer* buffer = new InMemoryBuffer();
|
|
|
+ buffer->schreibe("\0", 1);
|
|
|
+ Punkt center = getChunkCenter(
|
|
|
+ (int)player->getPosition().x, (int)player->getPosition().y);
|
|
|
+ buffer->schreibe((char*)¢er.x, 4);
|
|
|
+ buffer->schreibe((char*)¢er.y, 4);
|
|
|
+ buffer->schreibe("\0", 1);
|
|
|
+ dim->api(buffer, 0, player);
|
|
|
+ buffer->release();
|
|
|
+ while (isNew
|
|
|
+ && !dim->zChunk(getChunkCenter(
|
|
|
+ (int)player->getPosition().x, (int)player->getPosition().y)))
|
|
|
+ {
|
|
|
+ cs.unlock();
|
|
|
+ Sleep(1000);
|
|
|
+ cs.lock();
|
|
|
+ }
|
|
|
+ if (isNew)
|
|
|
+ {
|
|
|
+ Either<Block*, int> b = BlockTypeEnum::AIR;
|
|
|
+ int h = WORLD_HEIGHT;
|
|
|
+ while (((b.isA() && (!(Block*)b || ((Block*)b)->isPassable()))
|
|
|
+ || (b.isB()
|
|
|
+ && StaticRegistry<BlockType>::INSTANCE.zElement(b)
|
|
|
+ ->zDefault()
|
|
|
+ ->isPassable()))
|
|
|
+ && h > 0)
|
|
|
+ b = zBlockAt({(int)player->getPosition().x,
|
|
|
+ (int)player->getPosition().y,
|
|
|
+ --h},
|
|
|
+ player->getCurrentDimensionId());
|
|
|
+ player->setPosition(
|
|
|
+ {player->getPosition().x, player->getPosition().y, (float)h + 1.f});
|
|
|
+ }
|
|
|
+ requestWorldUpdate(
|
|
|
+ new AddEntityUpdate(player, player->getCurrentDimensionId()));
|
|
|
+ cs.unlock();
|
|
|
+ return dynamic_cast<GameClient*>(gameClient->getThis());
|
|
|
}
|
|
|
|
|
|
bool Game::isChunkLoaded(int x, int y, int dimension) const
|
|
|
{
|
|
|
- Dimension* dim = zDimension(dimension);
|
|
|
- return (dim && dim->hasChunck(x, y));
|
|
|
+ Dimension* dim = zDimension(dimension);
|
|
|
+ return (dim && dim->hasChunck(x, y));
|
|
|
}
|
|
|
|
|
|
bool Game::doesChunkExist(int x, int y, int dimension)
|
|
|
{
|
|
|
- cs.lock();
|
|
|
- bool result = isChunkLoaded(x, y, dimension) || loader->existsChunk(x, y, dimension);
|
|
|
- cs.unlock();
|
|
|
- return result;
|
|
|
+ cs.lock();
|
|
|
+ bool result = isChunkLoaded(x, y, dimension)
|
|
|
+ || loader->existsChunk(x, y, dimension);
|
|
|
+ cs.unlock();
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
-Framework::Either<Block*, int> Game::zBlockAt(Framework::Vec3<int> location, int dimension) const
|
|
|
+Framework::Either<Block*, int> Game::zBlockAt(
|
|
|
+ Framework::Vec3<int> location, int dimension) const
|
|
|
{
|
|
|
- Dimension* dim = zDimension(dimension);
|
|
|
- if (dim)
|
|
|
- return dim->zBlock(location);
|
|
|
- return 0;
|
|
|
+ Dimension* dim = zDimension(dimension);
|
|
|
+ if (dim) return dim->zBlock(location);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
Block* Game::zRealBlockInstance(Framework::Vec3<int> location, int dimension)
|
|
|
{
|
|
|
- Dimension* dim = zDimension(dimension);
|
|
|
- if (dim)
|
|
|
- return dim->zRealBlockInstance(location);
|
|
|
- return 0;
|
|
|
+ Dimension* dim = zDimension(dimension);
|
|
|
+ if (dim) return dim->zRealBlockInstance(location);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
Dimension* Game::zDimension(int id) const
|
|
|
{
|
|
|
- for (auto dim : *dimensions)
|
|
|
- {
|
|
|
- if (dim->getDimensionId() == id)
|
|
|
- return dim;
|
|
|
- }
|
|
|
- return 0;
|
|
|
+ for (auto dim : *dimensions)
|
|
|
+ {
|
|
|
+ if (dim->getDimensionId() == id) return dim;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
Framework::Punkt Game::getChunkCenter(int x, int y)
|
|
|
{
|
|
|
- return Punkt(((x < 0 ? x + 1 : x) / CHUNK_SIZE) * CHUNK_SIZE + (x < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2, ((y < 0 ? y + 1 : y) / CHUNK_SIZE) * CHUNK_SIZE + (y < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2);
|
|
|
+ return Punkt(((x < 0 ? x + 1 : x) / CHUNK_SIZE) * CHUNK_SIZE
|
|
|
+ + (x < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2,
|
|
|
+ ((y < 0 ? y + 1 : y) / CHUNK_SIZE) * CHUNK_SIZE
|
|
|
+ + (y < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2);
|
|
|
}
|
|
|
|
|
|
Area Game::getChunckArea(Punkt center) const
|
|
|
{
|
|
|
- return { center.x - CHUNK_SIZE / 2, center.y - CHUNK_SIZE / 2, center.x + CHUNK_SIZE / 2 - 1, center.y + CHUNK_SIZE / 2 - 1, 0 };
|
|
|
+ return {center.x - CHUNK_SIZE / 2,
|
|
|
+ center.y - CHUNK_SIZE / 2,
|
|
|
+ center.x + CHUNK_SIZE / 2 - 1,
|
|
|
+ center.y + CHUNK_SIZE / 2 - 1,
|
|
|
+ 0};
|
|
|
}
|
|
|
|
|
|
Framework::Text Game::getWorldDirectory() const
|
|
|
{
|
|
|
- return path;
|
|
|
+ return path;
|
|
|
}
|
|
|
|
|
|
void Game::requestArea(Area area)
|
|
|
{
|
|
|
- generator->requestGeneration(area);
|
|
|
- loader->requestLoading(area);
|
|
|
+ generator->requestGeneration(area);
|
|
|
+ loader->requestLoading(area);
|
|
|
}
|
|
|
|
|
|
void Game::save() const
|
|
|
{
|
|
|
- Datei d;
|
|
|
- d.setDatei(path + "/eid");
|
|
|
- d.open(Datei::Style::schreiben);
|
|
|
- d.schreibe((char*)&nextEntityId, 4);
|
|
|
- d.close();
|
|
|
- for (auto dim : *dimensions)
|
|
|
- dim->save(path);
|
|
|
+ Datei d;
|
|
|
+ d.setDatei(path + "/eid");
|
|
|
+ d.open(Datei::Style::schreiben);
|
|
|
+ d.schreibe((char*)&nextEntityId, 4);
|
|
|
+ d.close();
|
|
|
+ for (auto dim : *dimensions)
|
|
|
+ dim->save(path);
|
|
|
}
|
|
|
|
|
|
void Game::requestStop()
|
|
|
{
|
|
|
- stop = 1;
|
|
|
- warteAufThread(1000000);
|
|
|
+ stop = 1;
|
|
|
+ warteAufThread(1000000);
|
|
|
}
|
|
|
|
|
|
void Game::addDimension(Dimension* d)
|
|
|
{
|
|
|
- dimensions->add(d);
|
|
|
+ dimensions->add(d);
|
|
|
}
|
|
|
|
|
|
int Game::getNextEntityId()
|
|
|
{
|
|
|
- cs.lock();
|
|
|
- int result = nextEntityId++;
|
|
|
- cs.unlock();
|
|
|
- return result;
|
|
|
+ cs.lock();
|
|
|
+ int result = nextEntityId++;
|
|
|
+ cs.unlock();
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
WorldGenerator* Game::zGenerator() const
|
|
|
{
|
|
|
- return generator;
|
|
|
+ return generator;
|
|
|
}
|
|
|
|
|
|
Game* Game::INSTANCE = 0;
|
|
|
|
|
|
void Game::initialize(Framework::Text name, Framework::Text worldsDir)
|
|
|
{
|
|
|
- if (!Game::INSTANCE)
|
|
|
- {
|
|
|
- Game::INSTANCE = new Game(name, worldsDir);
|
|
|
- Game::INSTANCE->initialize();
|
|
|
- }
|
|
|
+ if (!Game::INSTANCE)
|
|
|
+ {
|
|
|
+ Game::INSTANCE = new Game(name, worldsDir);
|
|
|
+ Game::INSTANCE->initialize();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
Entity* Game::zEntity(int id, int dimensionId) const
|
|
|
{
|
|
|
- Dimension* d = zDimension(dimensionId);
|
|
|
- if (d)
|
|
|
- return d->zEntity(id);
|
|
|
- return 0;
|
|
|
+ Dimension* d = zDimension(dimensionId);
|
|
|
+ if (d) return d->zEntity(id);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
Entity* Game::zEntity(int id) const
|
|
|
{
|
|
|
- for (Dimension* d : *dimensions)
|
|
|
- {
|
|
|
- Entity* e = d->zEntity(id);
|
|
|
- if (e)
|
|
|
- return e;
|
|
|
- }
|
|
|
- // for new players that are currently loading
|
|
|
- for (GameClient* client : *clients)
|
|
|
- {
|
|
|
- if (client->zEntity()->getId() == id)
|
|
|
- {
|
|
|
- return client->zEntity();
|
|
|
- }
|
|
|
- }
|
|
|
- return 0;
|
|
|
+ for (Dimension* d : *dimensions)
|
|
|
+ {
|
|
|
+ Entity* e = d->zEntity(id);
|
|
|
+ if (e) return e;
|
|
|
+ }
|
|
|
+ // for new players that are currently loading
|
|
|
+ for (GameClient* client : *clients)
|
|
|
+ {
|
|
|
+ if (client->zEntity()->getId() == id)
|
|
|
+ {
|
|
|
+ return client->zEntity();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-Entity* Game::zNearestEntity(int dimensionId, Framework::Vec3<float> pos, std::function<bool(Entity*)> filter)
|
|
|
+Entity* Game::zNearestEntity(int dimensionId,
|
|
|
+ Framework::Vec3<float> pos,
|
|
|
+ std::function<bool(Entity*)> filter)
|
|
|
{
|
|
|
- Dimension* d = zDimension(dimensionId);
|
|
|
- if (!d)
|
|
|
- return 0;
|
|
|
- return d->zNearestEntity(pos, filter);
|
|
|
+ Dimension* d = zDimension(dimensionId);
|
|
|
+ if (!d) return 0;
|
|
|
+ return d->zNearestEntity(pos, filter);
|
|
|
}
|
|
|
|
|
|
const RecipieLoader& Game::getRecipies() const
|
|
|
{
|
|
|
- return recipies;
|
|
|
+ return recipies;
|
|
|
}
|
|
|
|
|
|
void Game::doLater(std::function<void()> action)
|
|
|
{
|
|
|
- actionsCs.lock();
|
|
|
- actions.add(action);
|
|
|
- actionsCs.unlock();
|
|
|
+ actionsCs.lock();
|
|
|
+ actions.add(action);
|
|
|
+ actionsCs.unlock();
|
|
|
}
|