Networking
Π‘Π΅ΡΠ΅Π²ΠΎΠ΅ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ Π² Wudgine ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΠΎΠ·Π΄Π°Π²Π°ΡΡ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠ΅ ΠΈΠ³ΡΡ Ρ ΡΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΠΌ ΠΈΠ³ΡΠΎΠ²ΡΠΌ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠΌ ΠΈ Π½ΠΈΠ·ΠΊΠΎΠΉ Π·Π°Π΄Π΅ΡΠΆΠΊΠΎΠΉ.
ΠΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π² ΡΠ΅ΡΠ΅Π²ΠΎΠ΅ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅
Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ ΠΈΠ³Ρ ΡΡΠ΅Π±ΡΠ΅Ρ Π½Π°Π΄Π΅ΠΆΠ½ΠΎΠΉ ΠΈ ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΠΉ ΡΠ΅ΡΠ΅Π²ΠΎΠΉ ΠΈΠ½ΡΡΠ°ΡΡΡΡΠΊΡΡΡΡ. Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΌΠΎΡΠ½ΡΠΉ Π½Π°Π±ΠΎΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΎΠ² Π΄Π»Ρ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΡΠ°Π·Π»ΠΈΡΠ½ΡΡ ΡΠΈΠΏΠΎΠ² ΡΠ΅ΡΠ΅Π²ΠΎΠ³ΠΎ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ, ΠΎΡ ΠΏΡΠΎΡΡΡΡ ΠΏΠΎΡΠ°Π³ΠΎΠ²ΡΡ ΠΈΠ³Ρ Π΄ΠΎ ΡΠ»ΠΎΠΆΠ½ΡΡ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ ΠΌΠΈΡΠΎΠ² ΡΠ΅Π°Π»ΡΠ½ΠΎΠ³ΠΎ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ.
ΠΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ° ΠΊΠ»ΠΈΠ΅Π½Ρ-ΡΠ΅ΡΠ²Π΅Ρ
Wudgine ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ ΠΊΠ»Π°ΡΡΠΈΡΠ΅ΡΠΊΡΡ Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΡ ΠΊΠ»ΠΈΠ΅Π½Ρ-ΡΠ΅ΡΠ²Π΅Ρ Π΄Π»Ρ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ ΠΈΠ³Ρ, Π³Π΄Π΅ ΡΠ΅ΡΠ²Π΅Ρ ΡΠ²Π»ΡΠ΅ΡΡΡ Π°Π²ΡΠΎΡΠΈΡΠ΅ΡΠ½ΡΠΌ ΠΈΡΡΠΎΡΠ½ΠΈΠΊΠΎΠΌ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΈΠ³ΡΡ.
ΠΡΠ½ΠΎΠ²Π½ΡΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ
- Π‘Π΅ΡΠ²Π΅Ρ β ΡΠ΅Π½ΡΡΠ°Π»ΡΠ½ΡΠΉ ΡΠ·Π΅Π», ΡΠΏΡΠ°Π²Π»ΡΡΡΠΈΠΉ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ΠΌ ΠΈΠ³ΡΡ
- ΠΠ»ΠΈΠ΅Π½Ρ β ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅ΡΡΡ ΠΊ ΡΠ΅ΡΠ²Π΅ΡΡ ΠΈ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°Π΅Ρ ΠΈΠ³ΡΠΎΠ²ΠΎΠΉ ΠΌΠΈΡ
- Π‘Π΅ΡΠ΅Π²ΠΎΠΉ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ β ΡΠΏΡΠ°Π²Π»ΡΠ΅Ρ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡΠΌΠΈ ΠΈ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠ΅ΠΉ Π΄Π°Π½Π½ΡΡ
- Π‘Π΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ β ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠ³ΡΠΎΠ²ΡΡ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ² Π² Π΄Π°Π½Π½ΡΠ΅ Π΄Π»Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠΈ
Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΠ΅ΡΠ²Π΅ΡΠ°
#include "Wudgine/Networking/Server.hpp"
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΠ΅ΡΠ²Π΅ΡΠ°
Wudgine::Networking::Server server;
// ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ²
server.SetMaxClients(16);
server.SetTickRate(60); // 60 ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ Π² ΡΠ΅ΠΊΡΠ½Π΄Ρ
// ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ ΡΠΎΠ±ΡΡΠΈΠΉ
server.OnClientConnected([](Wudgine::Networking::ClientID clientID) {
std::cout << "ΠΠ»ΠΈΠ΅Π½Ρ " << clientID << " ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠΈΠ»ΡΡ" << std::endl;
// ΠΡΠΏΡΠ°Π²ΠΊΠ° Π½Π°ΡΠ°Π»ΡΠ½ΠΎΠ³ΠΎ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΈΠ³ΡΡ
SendInitialGameState(clientID);
});
// ΠΠ°ΠΏΡΡΠΊ ΡΠ΅ΡΠ²Π΅ΡΠ°
if (server.Start(27015)) {
std::cout << "Π‘Π΅ΡΠ²Π΅Ρ Π·Π°ΠΏΡΡΠ΅Π½ Π½Π° ΠΏΠΎΡΡΡ 27015" << std::endl;
}
Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°
#include "Wudgine/Networking/Client.hpp"
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°
Wudgine::Networking::Client client;
// ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ ΡΠΎΠ±ΡΡΠΈΠΉ
client.OnConnected([]() {
std::cout << "ΠΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΊ ΡΠ΅ΡΠ²Π΅ΡΡ ΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΎ" << std::endl;
});
// ΠΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΊ ΡΠ΅ΡΠ²Π΅ΡΡ
if (client.Connect("127.0.0.1", 27015)) {
std::cout << "ΠΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΊ ΡΠ΅ΡΠ²Π΅ΡΡ..." << std::endl;
}
Π‘ΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΈΠ³ΡΡ
ΠΠ΄Π½Π° ΠΈΠ· ΠΊΠ»ΡΡΠ΅Π²ΡΡ Π·Π°Π΄Π°Ρ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ ΠΈΠ³ΡΠ°Ρ β ΡΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΈΠ³ΡΡ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ ΠΈ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°ΠΌΠΈ.
Π‘Π΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² ECS
// Π‘Π΅ΡΠ΅Π²ΠΎΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ Π΄Π»Ρ ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ
struct NetworkTransformComponent : public Wudgine::ECS::Component,
public Wudgine::Core::Serializable {
Wudgine::Math::Vector3 position;
Wudgine::Math::Quaternion rotation;
Wudgine::Math::Vector3 scale;
// ΠΠ΅ΡΠΎΠ΄ ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π΄Π»Ρ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ ΠΏΠΎ ΡΠ΅ΡΠΈ
void Serialize(Wudgine::Core::ByteBuffer& buffer) const override {
buffer.Write(position);
buffer.Write(rotation);
buffer.Write(scale);
}
// ΠΠ΅ΡΠΎΠ΄ Π΄Π΅ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π΄Π»Ρ ΠΏΡΠΈΠ΅ΠΌΠ° ΠΏΠΎ ΡΠ΅ΡΠΈ
void Deserialize(Wudgine::Core::ByteBuffer& buffer) override {
buffer.Read(position);
buffer.Read(rotation);
buffer.Read(scale);
}
};
ΠΡΠ΅Π΄ΡΠΊΠ°Π·Π°Π½ΠΈΠ΅ ΠΈ ΠΈΠ½ΡΠ΅ΡΠΏΠΎΠ»ΡΡΠΈΡ
ΠΠ»Ρ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠ΅Π½ΠΈΡ ΠΏΠ»Π°Π²Π½ΠΎΠ³ΠΎ ΠΈΠ³ΡΠΎΠ²ΠΎΠ³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° ΠΏΡΠΈ Π½Π°Π»ΠΈΡΠΈΠΈ ΡΠ΅ΡΠ΅Π²ΡΡ Π·Π°Π΄Π΅ΡΠΆΠ΅ΠΊ Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌΡ ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·Π°Π½ΠΈΡ ΠΈ ΠΈΠ½ΡΠ΅ΡΠΏΠΎΠ»ΡΡΠΈΠΈ.
ΠΡΠ΅Π΄ΡΠΊΠ°Π·Π°Π½ΠΈΠ΅ Π½Π° ΡΡΠΎΡΠΎΠ½Π΅ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°
// Π‘ΠΈΡΡΠ΅ΠΌΠ° ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·Π°Π½ΠΈΡ Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΡ
class MovementPredictionSystem : public Wudgine::ECS::System {
public:
void Update(float deltaTime) override {
auto view = GetWorld()->GetRegistry().view<NetworkTransformComponent, InputComponent>();
view.each([deltaTime](auto entity, NetworkTransformComponent& transform, InputComponent& input) {
// ΠΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π»ΠΎΠΊΠ°Π»ΡΠ½ΠΎΠ³ΠΎ Π²Π²ΠΎΠ΄Π° Π΄ΠΎ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ ΠΏΠΎΠ΄ΡΠ²Π΅ΡΠΆΠ΄Π΅Π½ΠΈΡ ΠΎΡ ΡΠ΅ΡΠ²Π΅ΡΠ°
if (input.moveForward) {
transform.position += transform.rotation * Wudgine::Math::Vector3::Forward() * MOVE_SPEED * deltaTime;
}
// Π‘ΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·Π°Π½Π½ΠΎΠ³ΠΎ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ
m_PredictedStates[entity].push_back({transform, GetWorld()->GetTime()});
});
}
};
ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π·Π°Π΄Π΅ΡΠΆΠ΅ΠΊ ΠΈ ΠΏΠΎΡΠ΅ΡΡ ΠΏΠ°ΠΊΠ΅ΡΠΎΠ²
Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌΡ Π΄Π»Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΡΠ΅ΡΠ΅Π²ΡΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌ, ΡΠ°ΠΊΠΈΡ ΠΊΠ°ΠΊ Π·Π°Π΄Π΅ΡΠΆΠΊΠΈ ΠΈ ΠΏΠΎΡΠ΅ΡΠΈ ΠΏΠ°ΠΊΠ΅ΡΠΎΠ².
ΠΠ°Π΄Π΅ΠΆΠ½Π°Ρ Π΄ΠΎΡΡΠ°Π²ΠΊΠ°
// ΠΡΠΏΡΠ°Π²ΠΊΠ° Π½Π°Π΄Π΅ΠΆΠ½ΠΎΠ³ΠΎ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ
void SendReliableMessage(Wudgine::Networking::ClientID clientID, const GameEvent& event) {
Wudgine::Core::ByteBuffer buffer;
// Π‘Π΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΡΠΎΠ±ΡΡΠΈΡ
buffer.Write(static_cast<uint8_t>(event.type));
event.Serialize(buffer);
// ΠΡΠΏΡΠ°Π²ΠΊΠ° Ρ Π³Π°ΡΠ°Π½ΡΠΈΠ΅ΠΉ Π΄ΠΎΡΡΠ°Π²ΠΊΠΈ
m_Server.SendReliable(clientID, buffer);
}
ΠΠ°ΡΡΡΠ°Π±ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ΅ΡΠ²Π΅ΡΠ½ΠΎΠΉ ΡΠ°ΡΡΠΈ
ΠΠ»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΌΠ°ΡΡΡΠ°Π±ΠΈΡΡΠ΅ΠΌΡΡ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ ΠΈΠ³Ρ Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ Π΄Π»Ρ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ Π½Π°Π³ΡΡΠ·ΠΊΠΈ.
ΠΠΎΠ½ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΌΠΈΡΠ°
// ΠΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ Π·ΠΎΠ½
class ZoneManager {
public:
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π·ΠΎΠ½
void Initialize(const Wudgine::Math::Vector2& worldSize, const Wudgine::Math::Vector2& zoneSize) {
m_WorldSize = worldSize;
m_ZoneSize = zoneSize;
// ΠΡΡΠΈΡΠ»Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π° Π·ΠΎΠ½
int zonesX = static_cast<int>(std::ceil(worldSize.x / zoneSize.x));
int zonesY = static_cast<int>(std::ceil(worldSize.y / zoneSize.y));
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π·ΠΎΠ½
m_Zones.resize(zonesX * zonesY);
}
};
Π§ΡΠΎ Π΄Π°Π»ΡΡΠ΅?
- ΠΠ·ΡΡΠΈΡΠ΅ ΡΠ°ΡΡΠΈΡΠ΅Π½Π½ΡΡ ΡΠ°Π±ΠΎΡΡ Ρ ΡΠ΅ΡΡΡΡΠ°ΠΌΠΈ Π΄Π»Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΠΈ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΈΠ³ΡΠΎΠ²ΡΠΌΠΈ ΡΠ΅ΡΡΡΡΠ°ΠΌΠΈ
- ΠΠ·Π½Π°ΠΊΠΎΠΌΡΡΠ΅ΡΡ Ρ ΠΎΡΠ»Π°Π΄ΠΊΠΎΠΉ ΠΈ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Π΄Π»Ρ Π°Π½Π°Π»ΠΈΠ·Π° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΡΠ΅ΡΠ΅Π²ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°
- ΠΡΡΠ»Π΅Π΄ΡΠΉΡΠ΅ ΠΏΡΠΈΠΌΠ΅ΡΡ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ ΠΈΠ³Ρ Π² ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠΈ ΠΏΡΠΈΠΌΠ΅ΡΠΎΠ² Wudgine
Π Π°Π·ΡΠ°Π±ΠΎΡΠΊΠ° ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ ΠΈΠ³Ρ ΡΡΠ΅Π±ΡΠ΅Ρ ΠΎΡΠΎΠ±ΠΎΠ³ΠΎ Π²Π½ΠΈΠΌΠ°Π½ΠΈΡ ΠΊ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡΠΈ. ΠΡΠ΅Π³Π΄Π° ΠΏΡΠΎΠ²Π΅ΡΡΠΉΡΠ΅ Π²Ρ ΠΎΠ΄ΡΡΠΈΠ΅ Π΄Π°Π½Π½ΡΠ΅ Π½Π° ΡΠ΅ΡΠ²Π΅ΡΠ΅ ΠΈ Π½Π΅ Π΄ΠΎΠ²Π΅ΡΡΠΉΡΠ΅ Π΄Π°Π½Π½ΡΠΌ, ΠΏΠΎΠ»ΡΡΠ΅Π½Π½ΡΠΌ ΠΎΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠΎΠ².