Browse Source

player movement is now client sided

Kolja Strohm 2 years ago
parent
commit
5737635a11

+ 2 - 0
FactoryCraft/AddEntityUpdate.cpp

@@ -30,6 +30,8 @@ void AddEntityUpdate::write(Framework::StreamWriter* zWriter)
 	zWriter->schreibe((char*)&pos.x, 4);
 	zWriter->schreibe((char*)&pos.y, 4);
 	zWriter->schreibe((char*)&pos.z, 4);
+	float maxSpeed = entity->getMaxSpeed();
+	zWriter->schreibe((char*)&maxSpeed, 4);
 	bool special = !entity->hasDefaultModel();
 	zWriter->schreibe((char*)&special, 1);
 	if (special)

+ 2 - 4
FactoryCraft/Block.cpp

@@ -2,8 +2,6 @@
 #include "Inventory.h"
 #include "NoBlock.h"
 #include "Game.h"
-#include "PlaceBlockUpdate.h"
-#include "BlockRemovedUpdate.h"
 #include "ItemEntity.h"
 #include "AddEntityUpdate.h"
 
@@ -208,11 +206,11 @@ void Block::setHP(float hp)
 			if (neighbourTypes[i] == NoBlockBlockType::ID)
 			{
 				Framework::Vec3<int> pos = getPos() + getDirection(getDirectionFromIndex(i));
-				Game::INSTANCE->requestWorldUpdate(new PlaceBlockUpdate(Game::INSTANCE->zGenerator()->generateSingleBlock(pos, dimensionId), pos, dimensionId));
+				Game::INSTANCE->zDimension(dimensionId)->placeBlock(pos, Game::INSTANCE->zGenerator()->generateSingleBlock(pos, dimensionId));
 			}
 		}
-		Game::INSTANCE->requestWorldUpdate(new BlockRemovedUpdate(getPos(), dimensionId));
 		onDestroy();
+		Game::INSTANCE->zDimension(dimensionId)->placeBlock(getPos(), AirBlockBlockType::ID);
 	}
 	else
 	{

+ 0 - 29
FactoryCraft/BlockRemovedUpdate.cpp

@@ -1,29 +0,0 @@
-#include "BlockRemovedUpdate.h"
-#include "Dimension.h"
-#include "NoBlock.h"
-
-
-BlockRemovedUpdate::BlockRemovedUpdate(Framework::Vec3<int> pos, int dimension)
-	: WorldUpdate(BlockRemovedUpdateType::ID, dimension, pos, pos)
-{}
-
-BlockRemovedUpdate::~BlockRemovedUpdate()
-{}
-
-void BlockRemovedUpdate::onUpdate(Dimension* zDimension)
-{
-	zDimension->placeBlock(getMaxAffectedPoint(), AirBlockBlockType::ID);
-}
-
-void BlockRemovedUpdate::write(Framework::StreamWriter* zWriter)
-{
-	auto pos = getMinAffectedPoint();
-	zWriter->schreibe((char*)&pos.x, 4);
-	zWriter->schreibe((char*)&pos.y, 4);
-	zWriter->schreibe((char*)&pos.z, 4);
-}
-
-
-BlockRemovedUpdateType::BlockRemovedUpdateType()
-	: WorldUpdateType(ID)
-{}

+ 0 - 24
FactoryCraft/BlockRemovedUpdate.h

@@ -1,24 +0,0 @@
-#pragma once
-
-#include "WorldUpdate.h"
-
-class BlockRemovedUpdate : public WorldUpdate
-{
-protected:
-	void write(Framework::StreamWriter* zWriter) override;
-
-public:
-	BlockRemovedUpdate(Framework::Vec3<int> pos, int dimension);
-	~BlockRemovedUpdate();
-
-	void onUpdate(Dimension* zDimension) override;
-};
-
-class BlockRemovedUpdateType : WorldUpdateType
-{
-	REGISTRABLE(BlockRemovedUpdateType)
-
-protected:
-	BlockRemovedUpdateType();
-};
-REGISTER(BlockRemovedUpdateType, WorldUpdateType)

+ 19 - 8
FactoryCraft/Chunk.cpp

@@ -174,8 +174,16 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
 	int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
 	assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT&& index >= 0);
 	Block* old = blocks[index];
+	bool change = 0;
 	if (block)
+	{
+		change = blockIds[index] != (unsigned short)block->zBlockType()->getId();
 		blockIds[index] = (unsigned short)block->zBlockType()->getId();
+	}
+	else
+	{
+		change = blocks[index] != 0;
+	}
 	blocks[index] = block;
 	Either<Block*, int> neighbor = zBlockNeighbor(location + getDirection(NORTH));
 	if (neighbor.isA())
@@ -209,14 +217,17 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
 		block->setNeighbour(BOTTOM, neighbor);
 	if (old)
 		old->release();
-	char msg[9];
-	msg[0] = 0; // set block
-	*(int*)(msg + 1) = index;
-	*(int*)(msg + 5) = block ? block->zBlockType()->getId() : NoBlockBlockType::ID;
-	NetworkMessage message;
-	message.addressChunck(this);
-	message.setMessage(msg, 9, 0);
-	notifyObservers(message);
+	if (change)
+	{
+		char msg[9];
+		msg[0] = 0; // set block
+		*(int*)(msg + 1) = index;
+		*(int*)(msg + 5) = block ? block->zBlockType()->getId() : NoBlockBlockType::ID;
+		NetworkMessage message;
+		message.addressChunck(this);
+		message.setMessage(msg, 9, 0);
+		notifyObservers(message);
+	}
 }
 
 void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)

+ 8 - 1
FactoryCraft/Dimension.cpp

@@ -115,7 +115,8 @@ Block* Dimension::zRealBlockInstance(Framework::Vec3<int> location)
 		if (y < 0)
 			y += CHUNK_SIZE;
 		c->instantiateBlock(Vec3<int>(x, y, location.z));
-		return c->zBlockAt(Vec3<int>(x, y, location.z));
+		auto result = c->zBlockAt(Vec3<int>(x, y, location.z));
+		return result.isA() ? result.getA() : 0;
 	}
 	return 0;
 }
@@ -363,4 +364,10 @@ void Dimension::removeEntity(int id)
 		}
 		index++;
 	}
+}
+
+void Dimension::removeSubscriptions(Entity* zEntity)
+{
+	for (Chunk* chunk : chunkList)
+		chunk->removeObserver(zEntity);
 }

+ 1 - 0
FactoryCraft/Dimension.h

@@ -47,4 +47,5 @@ public:
 	Entity* zEntity(int id);
 	Entity* zNearestEntity(Framework::Vec3<float> pos, std::function<bool(Entity*)> filter);
 	void removeEntity(int id);
+	void removeSubscriptions(Entity* zEntity);
 };

+ 81 - 35
FactoryCraft/Entity.cpp

@@ -3,7 +3,6 @@
 #include "Game.h"
 #include "BlockType.h"
 #include "ItemSkill.h"
-#include "PlaceBlockUpdate.h"
 #include "EntityRemovedUpdate.h"
 
 
@@ -47,11 +46,9 @@ void ActionTarget::placeBlock(Entity* zActor, Item* zItem)
 	Block* block = zItem->zPlacedBlockType()->createBlockAt(blockPos + getDirection(targetBlockSide), zItem);
 	if (block)
 	{
-		if (Game::INSTANCE->requestWorldUpdate(new PlaceBlockUpdate(block, block->getPos(), zActor->getCurrentDimensionId())))
-		{
-			zItem->onPlaced();
-			// TODO: decrese stamina of actor
-		}
+		Game::INSTANCE->zDimension(zActor->getCurrentDimensionId())->placeBlock(block->getPos(), block);
+		zItem->onPlaced();
+		// TODO: decrese stamina of actor
 	}
 }
 
@@ -165,11 +162,14 @@ void Entity::useItem(const ItemType* zType, Item* zItem)
 	}
 	else if (zItem && zItem->isPlaceable())
 	{ // TODO: place item
+		cs.lock();
 		if (target)
 			target->placeBlock(this, zItem);
+		cs.unlock();
 	}
 	else if (!zItem || zItem->isUsable())
 	{ // use item skill
+		cs.lock();
 		if (target)
 		{
 			ItemSkill* selected = 0;
@@ -188,37 +188,65 @@ void Entity::useItem(const ItemType* zType, Item* zItem)
 			}
 			target->applyItemSkillOnTarget(this, selected, zItem);
 		}
+		cs.unlock();
 	}
 }
 
 void Entity::onTargetChange()
 {}
 
-void Entity::prepareTick(const Dimension* zDimension)
-{
-	Vec3<float> headPosition = location + faceOffset;
+void Entity::addMovementFrame(MovementFrame& frame)
+{
+	cs.lock();
+	movements.add(frame);
+	cs.unlock();
+	NetworkMessage message;
+	message.addressEntity(this);
+	char msg[37];
+	msg[0] = 0;
+	*(float*)(msg + 1) = frame.direction.x;
+	*(float*)(msg + 5) = frame.direction.y;
+	*(float*)(msg + 9) = frame.direction.z;
+	*(float*)(msg + 13) = frame.targetPosition.x;
+	*(float*)(msg + 17) = frame.targetPosition.y;
+	*(float*)(msg + 21) = frame.targetPosition.z;
+	*(int*)(msg + 25) = frame.movementFlags;
+	*(double*)(msg + 29) = frame.duration;
+	message.setMessage(msg, 37, 0);
+	Game::INSTANCE->broadcastMessage(&message);
+	// TODO: implement movement on server
+	setPosition(frame.targetPosition);
+	faceDir = frame.direction;
+	// TODO implement subscription system to notify only interested clients
+}
+
+void Entity::calculateTarget(Framework::Vec3<float> basePos, Framework::Vec3<float> direction)
+{
+	Vec3<float> headPosition = basePos + faceOffset;
 	int px = (int)floor(headPosition.x);
 	int py = (int)floor(headPosition.y);
 	int pz = (int)floor(headPosition.z);
-	faceDir.normalize();
+	direction.normalize();
 	Direction dir = BOTTOM;
 	while (true)
 	{
-		if (getDefaultBlock(Game::INSTANCE->zBlockAt(Vec3<int>{ px, py, pz }, zDimension->getDimensionId()))->isInteractable())
+		if (getDefaultBlock(Game::INSTANCE->zBlockAt(Vec3<int>{ px, py, pz }, currentDimensionId))->isInteractable())
 		{
 			if (!target || !target->isBlock({ px, py, pz }, dir))
 			{
+				cs.lock();
 				delete target;
 				target = new ActionTarget({ px, py, pz }, dir);
+				cs.unlock();
 				onTargetChange();
 			}
 			break;
 		}
 		// collision to neighbor of current block
-		if (faceDir.x > 0)
+		if (direction.x > 0)
 		{
-			float xt = ((float)px + 1.f - headPosition.x) / faceDir.x;
-			Vec3<float> tmp = headPosition + faceDir * xt;
+			float xt = ((float)px + 1.f - headPosition.x) / direction.x;
+			Vec3<float> tmp = headPosition + direction * xt;
 			if (xt <= targetDistanceLimit && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f)
 			{
 				dir = WEST;
@@ -226,10 +254,10 @@ void Entity::prepareTick(const Dimension* zDimension)
 				continue;
 			}
 		}
-		if (faceDir.x < 0)
+		if (direction.x < 0)
 		{
-			float xt = ((float)px - headPosition.x) / faceDir.x;
-			Vec3<float> tmp = headPosition + faceDir * xt;
+			float xt = ((float)px - headPosition.x) / direction.x;
+			Vec3<float> tmp = headPosition + direction * xt;
 			if (xt <= targetDistanceLimit && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f)
 			{
 				dir = EAST;
@@ -237,10 +265,10 @@ void Entity::prepareTick(const Dimension* zDimension)
 				continue;
 			}
 		}
-		if (faceDir.y > 0)
+		if (direction.y > 0)
 		{
-			float yt = ((float)py + 1.f - headPosition.y) / faceDir.y;
-			Vec3<float> tmp = headPosition + faceDir * yt;
+			float yt = ((float)py + 1.f - headPosition.y) / direction.y;
+			Vec3<float> tmp = headPosition + direction * yt;
 			if (yt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f)
 			{
 				dir = NORTH;
@@ -248,10 +276,10 @@ void Entity::prepareTick(const Dimension* zDimension)
 				continue;
 			}
 		}
-		if (faceDir.y < 0)
+		if (direction.y < 0)
 		{
-			float yt = ((float)py - headPosition.y) / faceDir.y;
-			Vec3<float> tmp = headPosition + faceDir * yt;
+			float yt = ((float)py - headPosition.y) / direction.y;
+			Vec3<float> tmp = headPosition + direction * yt;
 			if (yt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f)
 			{
 				dir = SOUTH;
@@ -259,10 +287,10 @@ void Entity::prepareTick(const Dimension* zDimension)
 				continue;
 			}
 		}
-		if (faceDir.z > 0)
+		if (direction.z > 0)
 		{
-			float zt = ((float)pz + 1.f - headPosition.z) / faceDir.z;
-			Vec3<float> tmp = headPosition + faceDir * zt;
+			float zt = ((float)pz + 1.f - headPosition.z) / direction.z;
+			Vec3<float> tmp = headPosition + direction * zt;
 			if (zt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1.f)
 			{
 				dir = BOTTOM;
@@ -270,10 +298,10 @@ void Entity::prepareTick(const Dimension* zDimension)
 				continue;
 			}
 		}
-		if (faceDir.z < 0)
+		if (direction.z < 0)
 		{
-			float zt = ((float)pz - headPosition.z) / faceDir.z;
-			Vec3<float> tmp = headPosition + faceDir * zt;
+			float zt = ((float)pz - headPosition.z) / direction.z;
+			Vec3<float> tmp = headPosition + direction * zt;
 			if (zt <= targetDistanceLimit && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1)
 			{
 				dir = TOP;
@@ -283,26 +311,33 @@ void Entity::prepareTick(const Dimension* zDimension)
 		}
 		if (target)
 		{
+			cs.lock();
 			delete target;
 			target = 0;
+			cs.unlock();
 			onTargetChange();
 		}
 		break;
 	}
 }
 
+void Entity::prepareTick(const Dimension* zDimension)
+{}
+
 void Entity::tick(const Dimension* zDimension)
 {
+	/*
 	Vec3<float> oldPos = location;
 	// current block cooredinates
 	int px = (int)floor(location.x);
 	int py = (int)floor(location.y);
 	int pz = (int)floor(location.z);
 	// falling down
-	speed.z -= (zDimension->getGravity() * gravityMultiplier) / 30.f;
+	speed.z -= (zDimension->getGravity() * gravityMultiplier) * time;
 	// movement in current tick
-	Vec3<float> frameSpeed = speed / 30.f;
+	Vec3<float> frameSpeed = speed * time;
 	// loop through all collided blocks
+	bool hasCollided = 0;
 	bool needCollisionCheck = 1;
 	while (needCollisionCheck)
 	{
@@ -318,6 +353,7 @@ void Entity::tick(const Dimension* zDimension)
 				{
 					frameSpeed.x = frameSpeed.x * (xt - 0.1f);
 					speed.x = 0;
+					hasCollided = 1;
 				}
 				else
 					px++;
@@ -335,6 +371,7 @@ void Entity::tick(const Dimension* zDimension)
 				{
 					frameSpeed.x = frameSpeed.x * (xt - 0.1f);
 					speed.x = 0;
+					hasCollided = 1;
 				}
 				else
 					px--;
@@ -352,6 +389,7 @@ void Entity::tick(const Dimension* zDimension)
 				{
 					frameSpeed.y = frameSpeed.y * (yt - 0.1f);
 					speed.y = 0;
+					hasCollided = 1;
 				}
 				else
 					py++;
@@ -369,6 +407,7 @@ void Entity::tick(const Dimension* zDimension)
 				{
 					frameSpeed.y = frameSpeed.y * (yt - 0.1f);
 					speed.y = 0;
+					hasCollided = 1;
 				}
 				else
 					py--;
@@ -386,6 +425,7 @@ void Entity::tick(const Dimension* zDimension)
 				{
 					frameSpeed.z = frameSpeed.z * (zt - 0.1f);
 					speed.z = 0;
+					hasCollided = 1;
 				}
 				else
 					pz++;
@@ -404,6 +444,7 @@ void Entity::tick(const Dimension* zDimension)
 					frameSpeed.z = frameSpeed.z * (zt - 0.1f);
 					onFall(speed.z);
 					speed.z = 0;
+					hasCollided = 1;
 				}
 				else
 					pz--;
@@ -413,18 +454,18 @@ void Entity::tick(const Dimension* zDimension)
 		}
 	}
 	location += frameSpeed;
-	if (oldPos != location)
+	if (hasCollided)
 	{
 		NetworkMessage changeMsg;
 		changeMsg.addressEntity(this);
 		char msg[13];
-		msg[0] = 0; // position changed
+		msg[0] = 1; // position correction
 		*(float*)(msg + 1) = this->location.x;
 		*(float*)(msg + 5) = this->location.y;
 		*(float*)(msg + 9) = this->location.z;
 		changeMsg.setMessage(msg, 13, 0);
-		Game::INSTANCE->broadcastMessage(&changeMsg);
-	}
+		Game::INSTANCE->sendMessage(&changeMsg, this);
+	}*/
 }
 
 void Entity::api(Framework::StreamReader* zRequest, NetworkMessage* zResponse)
@@ -537,3 +578,8 @@ ModelInfo Entity::getSpecialModel() const
 {
 	return ModelInfo("", "", 0);
 }
+
+float Entity::getMaxSpeed() const
+{
+	return maxMovementSpeed;
+}

+ 17 - 1
FactoryCraft/Entity.h

@@ -4,6 +4,7 @@
 #include <Vec3.h>
 #include <Vec2.h>
 #include <Writer.h>
+#include <Zeit.h>
 
 #include "Effect.h"
 #include "Inventory.h"
@@ -35,6 +36,14 @@ public:
 	static ActionTarget* load(Framework::StreamReader* zReader);
 };
 
+struct MovementFrame
+{
+	Framework::Vec3<float> direction;
+	Framework::Vec3<float> targetPosition;
+	int movementFlags;
+	double duration;
+};
+
 class Entity : public Inventory
 {
 protected:
@@ -47,6 +56,7 @@ protected:
 	float thirst;
 	float maxThirst;
 	float targetDistanceLimit;
+	float maxMovementSpeed;
 	Framework::Vec3<float> speed;
 	Framework::Vec3<float> faceDir;
 	Framework::Vec3<float> faceOffset;
@@ -57,14 +67,19 @@ protected:
 	bool removed;
 	float gravityMultiplier;
 	int id;
+	Framework::ZeitMesser time;
+	Framework::Array<MovementFrame> movements;
+	Framework::Critical cs;
 
 	virtual void onDeath();
 	virtual void useItem(const ItemType* zType, Item* zItem);
 	Entity(const EntityType* zType, Framework::Vec3<float> location, int dimensionId, int entityId);
 	virtual void onTargetChange();
+	void addMovementFrame(MovementFrame& frame);
+	void calculateTarget(Framework::Vec3<float> basePos, Framework::Vec3<float> direction);
 
 public:
-	void prepareTick(const Dimension* zDimension);
+	virtual void prepareTick(const Dimension* zDimension);
 	virtual void tick(const Dimension* zDimension);
 
 	virtual void api(Framework::StreamReader* zRequest, NetworkMessage* zResponse);
@@ -91,6 +106,7 @@ public:
 	int getId() const;
 	virtual bool hasDefaultModel() const;
 	virtual ModelInfo getSpecialModel() const;
+	float getMaxSpeed() const;
 
 	friend Effect;
 	friend EntityType;

+ 0 - 4
FactoryCraft/FactoryCraft.vcxproj

@@ -97,7 +97,6 @@
     <ClInclude Include="BasicBlocks.h" />
     <ClInclude Include="BiomGenerator.h" />
     <ClInclude Include="Block.h" />
-    <ClInclude Include="BlockRemovedUpdate.h" />
     <ClInclude Include="BlockType.h" />
     <ClInclude Include="Chunk.h" />
     <ClInclude Include="Constants.h" />
@@ -128,7 +127,6 @@
     <ClInclude Include="NoBlock.h" />
     <ClInclude Include="OverworldDimension.h" />
     <ClInclude Include="NoiseInterpolator.h" />
-    <ClInclude Include="PlaceBlockUpdate.h" />
     <ClInclude Include="Player.h" />
     <ClInclude Include="PlayerHand.h" />
     <ClInclude Include="RandNoise.h" />
@@ -153,7 +151,6 @@
     <ClCompile Include="BasicBlock.cpp" />
     <ClCompile Include="BiomGenerator.cpp" />
     <ClCompile Include="Block.cpp" />
-    <ClCompile Include="BlockRemovedUpdate.cpp" />
     <ClCompile Include="BlockType.cpp" />
     <ClCompile Include="Chunk.cpp" />
     <ClCompile Include="CraftingStorage.cpp" />
@@ -181,7 +178,6 @@
     <ClCompile Include="Noise.cpp" />
     <ClCompile Include="OverworldDimension.cpp" />
     <ClCompile Include="NoiseInterpolator.cpp" />
-    <ClCompile Include="PlaceBlockUpdate.cpp" />
     <ClCompile Include="Player.cpp" />
     <ClCompile Include="PlayerHand.cpp" />
     <ClCompile Include="RandNoise.cpp" />

+ 0 - 12
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -180,12 +180,6 @@
     <ClInclude Include="PlayerHand.h">
       <Filter>inventory\items</Filter>
     </ClInclude>
-    <ClInclude Include="PlaceBlockUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
-    <ClInclude Include="BlockRemovedUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
     <ClInclude Include="ItemEntity.h">
       <Filter>entities</Filter>
     </ClInclude>
@@ -332,15 +326,9 @@
     <ClCompile Include="FastNoiseWrapper.cpp">
       <Filter>world\generator\noise</Filter>
     </ClCompile>
-    <ClCompile Include="PlaceBlockUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
     <ClCompile Include="PlayerHand.cpp">
       <Filter>inventory\items</Filter>
     </ClCompile>
-    <ClCompile Include="BlockRemovedUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
     <ClCompile Include="ItemEntity.cpp">
       <Filter>entities</Filter>
     </ClCompile>

+ 26 - 7
FactoryCraft/Game.cpp

@@ -90,10 +90,6 @@ void GameClient::reply()
 		Game::INSTANCE->api(req, this);
 	requests.leeren();
 	other.unlock();
-	int x = (int)floor(zPlayer->getPosition().x);
-	int y = (int)floor(zPlayer->getPosition().y);
-	int d = zPlayer->getCurrentDimensionId();
-	// send world to client
 	if (first)
 	{
 		foreground.lock();
@@ -102,7 +98,6 @@ void GameClient::reply()
 		client->zForegroundWriter()->schreibe((char*)&id, 4);
 		foreground.unlock();
 		first = 0;
-		Game::INSTANCE->requestArea({ x - CHUNK_SIZE * viewDistance, y - CHUNK_SIZE * viewDistance, x + CHUNK_SIZE * viewDistance, y + CHUNK_SIZE * viewDistance, d });
 	}
 }
 
@@ -260,7 +255,10 @@ void Game::thread()
 					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++;
 		}
@@ -447,8 +445,21 @@ GameClient* Game::addPlayer(FCKlient* client, Framework::Text name)
 	GameClient* gameClient = new GameClient(player, client);
 	gameClient->sendTypes();
 	clients->add(gameClient);
-	requestArea(getChunckArea(getChunkCenter((int)player->getPosition().x, (int)player->getPosition().y)));
-	while (!zDimension(player->getCurrentDimensionId()) || (isNew && !zDimension(player->getCurrentDimensionId())->zChunk(getChunkCenter((int)player->getPosition().x, (int)player->getPosition().y))))
+	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*)&center.x, 4);
+	buffer->schreibe((char*)&center.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);
@@ -590,6 +601,14 @@ Entity* Game::zEntity(int id) const
 		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;
 }
 

+ 23 - 19
FactoryCraft/ItemEntity.cpp

@@ -17,18 +17,38 @@ ItemEntity::ItemEntity(Framework::Vec3<float> location, int dimensionId, int ent
 	thirst = 10;
 	maxThirst = 10;
 	targetDistanceLimit = 4;
+	maxMovementSpeed = 1;
 }
 
-void ItemEntity::tick(const Dimension* zDimension)
+void ItemEntity::prepareTick(const Dimension* zDimension)
 {
 	if (slot->zStack() == 0 && !removed)
 		throw "Illegal State exception";
-	// add speed to next entity with free inventory
+	if (movements.getEintragAnzahl() <= 1)
+	{
+		Entity* zOther = Game::INSTANCE->zNearestEntity(currentDimensionId, location, [this](Entity* zOther)
+			{
+				return zOther != this && zOther->numberOfAddableItems(slot->zStack(), NO_DIRECTION);
+			});
+		if (zOther)
+		{
+			MovementFrame frame;
+			frame.direction = zOther->getPosition() - getPosition();
+			frame.duration = 0.25;
+			frame.movementFlags = 0x1; // TODO: torn on flight mode
+			frame.targetPosition = getPosition() + frame.direction * (0.5f * maxMovementSpeed);
+			addMovementFrame(frame);
+		}
+	}
+	Entity::prepareTick(zDimension);
+}
+
+void ItemEntity::tick(const Dimension* zDimension)
+{
 	Entity* zOther = Game::INSTANCE->zNearestEntity(currentDimensionId, location, [this](Entity* zOther)
 		{
 			return zOther != this && zOther->numberOfAddableItems(slot->zStack(), NO_DIRECTION);
 		});
-	bool found = 1;
 	if (zOther)
 	{
 		float d = location.abstand(zOther->getPosition());
@@ -39,23 +59,7 @@ void ItemEntity::tick(const Dimension* zDimension)
 			if (slot->getNumberOfItems() == 0)
 				onDeath();
 		}
-		else if (d < 3.f)
-		{
-			// accelerate towards of the other entity
-			speed += (zOther->getPosition() - location).normalize() * (20 / (d + 0.5f)) / 30.f;
-		}
-		else
-			found = 0;
-	}
-	else
-		found = 0;
-	if (!found)
-	{
-		speed -= speed / 30.f;
-		if (speed.getLength() < 0.2f)
-			speed = { 0.f, 0.f, 0.f };
 	}
-	Entity::tick(zDimension);
 }
 
 void ItemEntity::onFall(float collisionSpeed)

+ 1 - 0
FactoryCraft/ItemEntity.h

@@ -13,6 +13,7 @@ private:
 	ItemEntity(Framework::Vec3<float> location, int dimensionId, int entityId);
 
 public:
+	void prepareTick(const Dimension* zDimension) override;
 	void tick(const Dimension* zDimension) override;
 
 	void onFall(float collisionSpeed) override;

+ 0 - 42
FactoryCraft/PlaceBlockUpdate.cpp

@@ -1,42 +0,0 @@
-#include "PlaceBlockUpdate.h"
-#include "Block.h"
-#include "Dimension.h"
-
-
-PlaceBlockUpdate::PlaceBlockUpdate(Framework::Either<Block*, int> block, Framework::Vec3<int> location, int dimensionId)
-	: WorldUpdate(PlaceBlockUpdateType::ID, dimensionId, location, location),
-	block(block)
-{}
-
-PlaceBlockUpdate::~PlaceBlockUpdate()
-{
-	if (block.isA())
-		block.getA()->release();
-}
-
-void PlaceBlockUpdate::onUpdate(Dimension* zDimension)
-{
-	if (block.isA())
-		block.getA()->getThis();
-	zDimension->placeBlock(getMaxAffectedPoint(), block);
-}
-
-void PlaceBlockUpdate::write(Framework::StreamWriter* zWriter)
-{
-	auto pos = getMinAffectedPoint();
-	zWriter->schreibe((char*)&pos.x, 4);
-	zWriter->schreibe((char*)&pos.y, 4);
-	zWriter->schreibe((char*)&pos.z, 4);
-	unsigned short blockType = block.isA() ? (unsigned short)block.getA()->zBlockType()->getId() : (unsigned short)block.getB();
-	zWriter->schreibe((char*)&blockType, 2);
-}
-
-Block* PlaceBlockUpdate::zBlock() const
-{
-	return block;
-}
-
-
-PlaceBlockUpdateType::PlaceBlockUpdateType()
-	: WorldUpdateType(ID)
-{}

+ 0 - 32
FactoryCraft/PlaceBlockUpdate.h

@@ -1,32 +0,0 @@
-#pragma once
-
-#include <Either.h>
-#include <Vec3.h>
-#include "WorldUpdate.h"
-
-class Block;
-
-class PlaceBlockUpdate : public WorldUpdate
-{
-private:
-	Framework::Either<Block*, int> block;
-
-protected:
-	void write(Framework::StreamWriter* zWriter) override;
-
-public:
-	PlaceBlockUpdate(Framework::Either<Block*, int> block, Framework::Vec3<int> location, int dimensionId);
-	~PlaceBlockUpdate();
-
-	void onUpdate(Dimension* zDimension) override;
-	Block* zBlock() const;
-};
-
-class PlaceBlockUpdateType : WorldUpdateType
-{
-	REGISTRABLE(PlaceBlockUpdateType)
-
-protected:
-	PlaceBlockUpdateType();
-};
-REGISTER(PlaceBlockUpdateType, WorldUpdateType)

+ 15 - 102
FactoryCraft/Player.cpp

@@ -32,6 +32,7 @@ Player::Player(Framework::Vec3<float> location, int dimensionId, int entityId)
 	jumping = 0;
 	faceOffset = { 0.f, 0.f, 1.5f };
 	targetDistanceLimit = 4;
+	maxMovementSpeed = 4;
 }
 
 void Player::onTargetChange()
@@ -148,32 +149,6 @@ const char* Player::getName() const
 
 void Player::tick(const Dimension* zDimension)
 {
-	speed = { 0, 0, speed.z };
-	if ((keyState | Key::MOVE_FRONT) == keyState)
-		speed += {faceDir.x, faceDir.y, 0};
-	if ((keyState | Key::MOVE_BACK) == keyState)
-		speed += {-faceDir.x, -faceDir.y, 0};
-	if ((keyState | Key::MOVE_RIGHT) == keyState)
-	{
-		Vec2<float> norm = { faceDir.x, faceDir.y };
-		norm.CW90().normalize();
-		speed += {norm.x, norm.y, 0};
-	}
-	if ((keyState | Key::MOVE_LEFT) == keyState)
-	{
-		Vec2<float> norm = { faceDir.x, faceDir.y };
-		norm.CCW90().normalize();
-		speed += {norm.x, norm.y, 0};
-	}
-	Vec2<float> norm = { speed.x, speed.y };
-	if (norm.getLengthSq() != 0)
-	{
-		norm.normalize();
-		speed.x = norm.x * 4.f; // 4 blocks per second movement speed
-		speed.y = norm.y * 4.f;
-	}
-	if ((keyState | Key::MOVE_DOWN) == keyState && gravityMultiplier == 0.f)
-		speed.z = -4.f;
 	if ((keyState | Key::LEFT_HAND_ACTION) == keyState)
 		useItemSlot(itemBar.get(leftHandPosition));
 	if ((keyState | Key::RIGHT_HAND_ACTION) == keyState)
@@ -192,34 +167,6 @@ void Player::playerApi(Framework::StreamReader* zRequest, NetworkMessage* zRespo
 		zRequest->lese(&byte, 1);
 		switch (byte)
 		{
-		case 0:
-			keyState = keyState & ~Key::MOVE_FRONT;
-			break;
-		case 1:
-			keyState = keyState & ~Key::MOVE_LEFT;
-			break;
-		case 2:
-			keyState = keyState & ~Key::MOVE_BACK;
-			break;
-		case 3:
-			keyState = keyState & ~Key::MOVE_RIGHT;
-			break;
-		case 4:
-			if (gravityMultiplier == 0.f)
-				speed.z = 0;
-			keyState = keyState & ~Key::MOVE_DOWN;
-			break;
-		case 5:
-			keyState = keyState & ~Key::ROTATE_LEFT;
-			break;
-		case 6:
-			keyState = keyState & ~Key::ROTATE_RIGHT;
-			break;
-		case 7:
-			if (gravityMultiplier == 0.f)
-				speed.z = 0;
-			keyState = keyState & ~Key::MOVE_UP;
-			break;
 		case 8:
 			keyState = keyState & ~Key::LEFT_HAND_ACTION;
 			break;
@@ -233,50 +180,6 @@ void Player::playerApi(Framework::StreamReader* zRequest, NetworkMessage* zRespo
 		zRequest->lese(&byte, 1);
 		switch (byte)
 		{
-		case 0:
-			keyState = keyState | Key::MOVE_FRONT;
-			break;
-		case 1:
-			keyState = keyState | Key::MOVE_LEFT;
-			break;
-		case 2:
-			keyState = keyState | Key::MOVE_BACK;
-			break;
-		case 3:
-			keyState = keyState | Key::MOVE_RIGHT;
-			break;
-		case 4:
-			keyState = keyState | Key::MOVE_DOWN;
-			break;
-		case 5:
-			keyState = keyState | Key::ROTATE_LEFT;
-			break;
-		case 6:
-			keyState = keyState | Key::ROTATE_RIGHT;
-			break;
-		case 7:
-			if ((keyState | Key::MOVE_UP) != keyState)
-			{
-				if (gravityMultiplier > 0)
-				{
-					if (jumping)
-					{
-						// TODO: check if flight is enabled
-						gravityMultiplier = 0;
-						jumping = 0;
-						speed.z = 1.5f;
-					}
-					else
-					{
-						jumping = 1;
-						speed.z = 5.f;
-					}
-				}
-				else
-					speed.z = 1.5f;
-			}
-			keyState = keyState | Key::MOVE_UP;
-			break;
 		case 8:
 			keyState = keyState | Key::LEFT_HAND_ACTION;
 			break;
@@ -286,11 +189,21 @@ void Player::playerApi(Framework::StreamReader* zRequest, NetworkMessage* zRespo
 		}
 		break;
 	case 2:
-		// switch target direction
-		zRequest->lese((char*)&faceDir.x, 4);
-		zRequest->lese((char*)&faceDir.y, 4);
-		zRequest->lese((char*)&faceDir.z, 4);
+		// set movement
+	{
+		MovementFrame frame;
+		zRequest->lese((char*)&frame.direction.x, 4);
+		zRequest->lese((char*)&frame.direction.y, 4);
+		zRequest->lese((char*)&frame.direction.z, 4);
+		zRequest->lese((char*)&frame.targetPosition.x, 4);
+		zRequest->lese((char*)&frame.targetPosition.y, 4);
+		zRequest->lese((char*)&frame.targetPosition.z, 4);
+		zRequest->lese((char*)&frame.movementFlags, 4);
+		zRequest->lese((char*)&frame.duration, 8);
+		addMovementFrame(frame);
+		calculateTarget(frame.targetPosition, frame.direction);
 		break;
+	}
 	case 3:
 	{ // switch item bar position
 		zRequest->lese((char*)&leftHandPosition, 4);

+ 0 - 8
FactoryCraft/Player.h

@@ -13,14 +13,6 @@ public:
 	class Key
 	{
 	public:
-		const static __int64 MOVE_FRONT = 0x1;
-		const static __int64 MOVE_BACK = 0x2;
-		const static __int64 MOVE_LEFT = 0x4;
-		const static __int64 MOVE_RIGHT = 0x8;
-		const static __int64 MOVE_UP = 0x10;
-		const static __int64 MOVE_DOWN = 0x20;
-		const static __int64 ROTATE_LEFT = 0x40;
-		const static __int64 ROTATE_RIGHT = 0x80;
 		const static __int64 LEFT_HAND_ACTION = 0x100;
 		const static __int64 RIGHT_HAND_ACTION = 0x200;
 	};

+ 0 - 2
FactoryCraft/StaticInitializerOrder.cpp

@@ -28,7 +28,5 @@ bool initialized_##c##_##typ = StaticRegistry<typ>::INSTANCE.info(c::ID);
 #include "PlayerHand.h"
 #include "StoneTool.h"
 // world updates
-#include "PlaceBlockUpdate.h"
-#include "BlockRemovedUpdate.h"
 #include "AddEntityUpdate.h"
 #include "EntityRemovedUpdate.h"