This repository has been archived on 2026-04-01. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
kolyah-game-2025/src/Multiplayer.cpp
2026-04-01 23:25:51 +02:00

247 lines
7.4 KiB
C++

#include "Multiplayer.hpp"
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include "Game.hpp"
// #define SERVER_ADDRESS "127.0.0.1"
#define SERVER_ADDRESS "sffnetwork.su"
void Multiplayer::connect(const char* name) {
printf("name %s\n", name);
m_name = name;
m_state = MultiplayerState::CONNECTING;
client = enet_host_create(nullptr, 1, LAST_CHANNEL, 0, 0);
if (!client) {
printf("client null\n");
exit(1);
}
ENetAddress address;
enet_address_set_host(&address, SERVER_ADDRESS);
address.port = 7777;
peer = enet_host_connect(client, &address, LAST_CHANNEL, 0);
if (peer == nullptr) {
printf("peer null\n");
enet_host_destroy(client);
exit(1);
}
ENetEvent event;
auto res = enet_host_service(client, &event, 5000);
if (res <= 0 || event.type != ENET_EVENT_TYPE_CONNECT) {
enet_peer_reset(peer);
printf("Failed to connect to server!\n");
exit(1);
}
auto packet_size = 1 + 2 + strlen(name);
auto login_packet = new char[packet_size];
login_packet[0] = Header::IDENTIFICATION;
*(uint16_t*)(login_packet + 1) = strlen(name);
memcpy(login_packet + 3, name, strlen(name));
if (sendPacket(login_packet, packet_size)) {
printf("trying to reg!!\n");
m_state = MultiplayerState::LOGGING_IN;
}
}
int Multiplayer::sendPacket(char* data, int size, Channel channel, bool reliable) {
auto enetPacket = enet_packet_create(data, size, reliable ? ENET_PACKET_FLAG_RELIABLE : ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT);
return enet_peer_send(peer, channel, enetPacket) == 0;
}
void Multiplayer::update(float dt) {
ENetEvent event;
while (enet_host_service(client, &event, 0) > 0) {
switch (event.type) {
case ENET_EVENT_TYPE_RECEIVE: {
// printf("packet received\n");
auto bytes = event.packet->data;
// for (int i = 0; i < event.packet->dataLength; i++) {
// printf("%02X ", bytes[i]);
// }
// printf("\n");
switch (bytes[0]) {
case LOAD_PLAYER: { // all players get this when a new player connects
bytes++;
uint16_t nameLen = *(uint16_t*)bytes;
bytes += 2;
auto name = new char[nameLen + 1];
memcpy(name, bytes, nameLen);
bytes += nameLen;
name[nameLen] = 0;
uint32_t playerID = *(uint32_t*)bytes;
bytes += 4;
float serverTime = *(float*)bytes;
printf("- load player name %s id %i server time %f\n", name, playerID, serverTime);
Game::get().chatMessages.push_back({"Player " + std::string(name) + " has joined.", (float)GetTime()});
if (m_name == name) {
printf("- its me!\n");
m_id = playerID;
m_state = MultiplayerState::PLAYING;
Game::get().serverTime = serverTime;
char packet = Header::LOAD_PLAYERS;
sendPacket(&packet, 1);
} else {
// std::string texture = "assets/";
// std::string nicknamee = name;
// std::transform(nicknamee.begin(), nicknamee.end(), nicknamee.begin(), ::tolower);
// texture.append(nicknamee).append(".png");
auto p = Player(skinFromName(name), name);
p.pos.y = -400;
Game::get().otherPlayers[playerID] = p;
}
break;
}
case LOAD_PLAYERS: { // get list of all players on server with their id,pos,name
printf("- load players packet size %i\n", event.packet->dataLength);
bytes++;
auto num = *bytes;
bytes++;
for (int i = 0; i < num; i++) {
auto id = *(uint32_t*)bytes;
bytes += 4;
auto x = *(float*)bytes;
bytes += 4;
auto y = *(float*)bytes;
bytes += 4;
auto nameLen = *(uint16_t*)bytes;
bytes += 2;
auto name = new char[nameLen + 1];
name[nameLen] = 0;
memcpy(name, bytes, nameLen);
bytes += nameLen;
printf("- - player: x %f y %f name %s id %i\n", x, y, name, id);
// std::string texture = "assets/";
// std::string nicknamee = name;
// std::transform(nicknamee.begin(), nicknamee.end(), nicknamee.begin(), ::tolower);
// texture.append(nicknamee).append(".png");
auto p = Player(skinFromName(name), name);
// auto p = Player(texture.c_str(), name);
p.pos = {x, y};
Game::get().otherPlayers[id] = p;
}
break;
}
case PLAYER: { // pos of all players
bytes++;
auto num = *bytes;
bytes++;
for (int i = 0; i < num; i++) {
auto id = *(uint32_t*)bytes;
bytes += 4;
auto x = *(float*)bytes;
bytes += 4;
auto y = *(float*)bytes;
bytes += 4;
if (id == peer->connectID) {
continue;
}
if (Game::get().otherPlayers.contains(id)) {
auto& p = Game::get().otherPlayers[id];
// Game::get().otherPlayers[id].pos = {x, y};
auto delta_x = x - p.pos.x;
p.pos = {x, y};
p.vel.x = delta_x;
// p.walkRight = delta_x > 0;
if (delta_x > 0) {
p.walkRight = true;
} else if (delta_x < 0) {
p.walkRight = false;
}
}
}
break;
}
case MESSAGE: {
bytes++;
auto len = *(uint16_t*)bytes;
bytes += 2;
auto msg = new char[len + 1];
msg[len] = 0;
memcpy(msg, bytes, len);
Game::get().chatMessages.push_back({msg, (float)GetTime()});
delete[] msg;
break;
}
default: {
printf("- unk packet %i\n", bytes[0]);
break;
}
}
break;
}
case ENET_EVENT_TYPE_DISCONNECT: {
printf("Connection closed.\n");
break;
}
default: break;
}
}
m_updateTime += dt;
const auto POS_TIME = 1 / 30.f;
if (m_updateTime > POS_TIME) {
// printf("sending pos\n");
m_updateTime -= POS_TIME;
auto data = new char[1 + 4 + 4];
data[0] = Header::PLAYER;
*(float*)(data + 1) = Game::get().player.pos.x;
*(float*)(data + 1 + 4) = Game::get().player.pos.y;
sendPacket(data, 1 + 4 + 4);
delete[] data;
}
}