Merge branch 'master' into TCPConnections
# Conflicts: # include/Engine/Network/Client.h # include/Engine/Network/Server.h # include/Game/Game.h # src/Engine/Network/Client.cpp # src/Engine/Network/Server.cpp # src/Game/Game.cpp
This commit is contained in:
@@ -1,34 +1,44 @@
|
||||
#include "Network/Client.h"
|
||||
using namespace boost::asio::ip;
|
||||
|
||||
Client::Client(ConfigFile* config)
|
||||
Client::Client(World* world, EventBroker* eventBroker)
|
||||
: Network(world, eventBroker)
|
||||
{
|
||||
Network::initialize();
|
||||
|
||||
// Asumes root node is EntityID_Invalid
|
||||
insertIntoServerClientMaps(EntityID_Invalid, EntityID_Invalid);
|
||||
// Init timer
|
||||
m_TimeSinceSentInputs = std::clock();
|
||||
// Default is local host
|
||||
address = config->Get<std::string>("Networking.Address", "127.0.0.1");
|
||||
port = config->Get<int>("Networking.Port", 27666);
|
||||
// Set up network stream
|
||||
|
||||
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
m_PlayerName = config->Get<std::string>("Networking.Name", "Raptorcopter");
|
||||
m_SendInputIntervalMs = config->Get<int>("Networking.SendInputIntervalMs", 33);
|
||||
LOG_INFO("Client initialized");
|
||||
}
|
||||
|
||||
Client::Client(World* world, EventBroker* eventBroker, std::unique_ptr<SnapshotFilter> snapshotFilter)
|
||||
: Client(world, eventBroker)
|
||||
{
|
||||
m_SnapshotFilter = std::move(snapshotFilter);
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
{ }
|
||||
|
||||
void Client::Start(World* world, EventBroker* eventBroker)
|
||||
// Need to call connect at start
|
||||
void Client::Connect(std::string address, int port)
|
||||
{
|
||||
m_EventBroker = eventBroker;
|
||||
m_World = world;
|
||||
|
||||
// Subscribe to events
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Client::OnPlayerDamage);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Client::OnPlayerSpawned);
|
||||
LOG_INFO("I am client. BIP BOP");
|
||||
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
m_Address = address;
|
||||
if (address.empty()) {
|
||||
m_Address = config->Get<std::string>("Networking.Address", "127.0.0.1");
|
||||
}
|
||||
m_Port = port;
|
||||
if (port == 0) {
|
||||
m_Port = config->Get<int>("Networking.Port", 27666);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Update()
|
||||
@@ -63,6 +73,7 @@ void Client::Update()
|
||||
sendInputCommands();
|
||||
m_TimeSinceSentInputs = std::clock();
|
||||
}
|
||||
// HACK: Send absolute player positions for now to avoid desync until we have reliable messages
|
||||
sendLocalPlayerTransform();
|
||||
|
||||
hasServerTimedOut();
|
||||
@@ -198,40 +209,64 @@ void Client::parseComponentDeletion(Packet & packet)
|
||||
}
|
||||
}
|
||||
|
||||
// Fields with strings will not work right now
|
||||
void Client::InterpolateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType)
|
||||
{
|
||||
int sizeOfFields = 0;
|
||||
for (auto field : componentInfo.FieldsInOrder) {
|
||||
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field);
|
||||
sizeOfFields += fieldInfo.Stride;
|
||||
}
|
||||
// Is the size correct?
|
||||
boost::shared_array<char> eventData(new char[componentInfo.Stride]);
|
||||
memcpy(eventData.get(), packet.ReadData(componentInfo.Stride), componentInfo.Stride);
|
||||
//Send event to interpolat system
|
||||
Events::Interpolate e;
|
||||
e.Entity = entityID;
|
||||
e.DataArray = eventData;
|
||||
m_EventBroker->Publish(e);
|
||||
|
||||
}
|
||||
|
||||
void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType)
|
||||
void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID)
|
||||
{
|
||||
for (auto field : componentInfo.FieldsInOrder) {
|
||||
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field);
|
||||
if (fieldInfo.Type == "string") {
|
||||
std::string& value = packet.ReadString();
|
||||
m_World->GetComponent(entityID, componentType)[fieldInfo.Name] = value;
|
||||
m_World->GetComponent(entityID, componentInfo.Name)[fieldInfo.Name] = value;
|
||||
} else {
|
||||
memcpy(m_World->GetComponent(entityID, componentType).Data + fieldInfo.Offset, packet.ReadData(fieldInfo.Stride), fieldInfo.Stride);
|
||||
memcpy(m_World->GetComponent(entityID, componentInfo.Name).Data + fieldInfo.Offset, packet.ReadData(fieldInfo.Stride), fieldInfo.Stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SharedComponentWrapper Client::createSharedComponent(Packet& packet, EntityID entityID, const ComponentInfo& componentInfo)
|
||||
{
|
||||
// Create shared allocation
|
||||
char* data = new char[sizeof(EntityID) + componentInfo.Stride];
|
||||
// Copy entity ID to start of data buffer
|
||||
memcpy(data, &entityID, sizeof(EntityID));
|
||||
// Read and copy fields
|
||||
for (auto& field : componentInfo.FieldsInOrder) {
|
||||
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field);
|
||||
if (fieldInfo.Type == "string") {
|
||||
new (data + sizeof(EntityID) + fieldInfo.Offset) std::string(packet.ReadString());
|
||||
} else {
|
||||
memcpy(data + sizeof(EntityID) + fieldInfo.Offset, packet.ReadData(fieldInfo.Stride), fieldInfo.Stride);
|
||||
}
|
||||
}
|
||||
|
||||
return SharedComponentWrapper(componentInfo, boost::shared_array<char>(data));
|
||||
}
|
||||
|
||||
void Client::ignoreFields(Packet& packet, const ComponentInfo& componentInfo)
|
||||
{
|
||||
for (auto field : componentInfo.FieldsInOrder) {
|
||||
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field);
|
||||
if (fieldInfo.Type == "string") {
|
||||
packet.ReadString();
|
||||
} else {
|
||||
packet.ReadData(fieldInfo.Stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::parseSnapshot(Packet& packet)
|
||||
{
|
||||
// Read input commands
|
||||
std::size_t numInputCommands = packet.ReadPrimitive<std::size_t>();
|
||||
for (std::size_t i = 0; i < numInputCommands; ++i) {
|
||||
Events::InputCommand e;
|
||||
e.PlayerID = packet.ReadPrimitive<EntityID>();
|
||||
e.Player = EntityWrapper(m_World, m_ServerIDToClientID.at(packet.ReadPrimitive<EntityID>()));
|
||||
e.Command = packet.ReadString();
|
||||
e.Value = packet.ReadPrimitive<float>();
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
|
||||
// Read world state
|
||||
while (packet.DataReadSize() < packet.Size()) {
|
||||
EntityID serverEntityID = packet.ReadPrimitive<EntityID>();
|
||||
EntityID serverParentID = packet.ReadPrimitive<EntityID>();
|
||||
@@ -239,26 +274,32 @@ void Client::parseSnapshot(Packet& packet)
|
||||
int ammountOfComponents = packet.ReadPrimitive<int>();
|
||||
for (int i = 0; i < ammountOfComponents; i++) {
|
||||
std::string componentType = packet.ReadString();
|
||||
ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo();
|
||||
const ComponentInfo& componentInfo = m_World->GetComponents(componentType)->ComponentInfo();
|
||||
if (serverClientMapsHasEntity(serverEntityID)) {
|
||||
EntityID localEntityID = m_ServerIDToClientID.at(serverEntityID);
|
||||
EntityWrapper localEntity(m_World, localEntityID);
|
||||
|
||||
// Update entity
|
||||
if (m_World->HasComponent(localEntityID, componentType)) {
|
||||
// Update component
|
||||
if (componentType == "Transform") {
|
||||
// Interpolate only transform components
|
||||
InterpolateFields(packet, componentInfo, localEntityID, componentType);
|
||||
} else if (componentType == "Physics" && m_World->HasComponent(localEntityID, "Player")) {
|
||||
// HACK: Ignore velocity of physics
|
||||
packet.ReadData(componentInfo.Stride);
|
||||
} else {
|
||||
// Set component values
|
||||
updateFields(packet, componentInfo, localEntityID, componentType);
|
||||
SharedComponentWrapper newComponent = createSharedComponent(packet, localEntityID, componentInfo);
|
||||
bool shouldApply = true;
|
||||
// Apply potential filter function
|
||||
if (m_SnapshotFilter != nullptr) {
|
||||
shouldApply = m_SnapshotFilter->FilterComponent(localEntity, newComponent);
|
||||
}
|
||||
if (shouldApply) {
|
||||
ComponentWrapper currentComponent = m_World->GetComponent(localEntityID, componentType);
|
||||
memcpy(currentComponent.Data, newComponent.Data, componentInfo.Stride);
|
||||
}
|
||||
//if (localEntity != m_LocalPlayer && !localEntity.IsChildOf(m_LocalPlayer)) {
|
||||
// updateFields(packet, componentInfo, localEntityID);
|
||||
//} else {
|
||||
// ignoreFields(packet, componentInfo);
|
||||
//}
|
||||
} else {
|
||||
// Has entity but no component
|
||||
m_World->AttachComponent(localEntityID, componentType);
|
||||
updateFields(packet, componentInfo, localEntityID, componentType);
|
||||
updateFields(packet, componentInfo, localEntityID);
|
||||
}
|
||||
} else {
|
||||
// Create Entity and component
|
||||
@@ -271,7 +312,7 @@ void Client::parseSnapshot(Packet& packet)
|
||||
m_World->SetName(newLocalEntityID, serverEntityName);
|
||||
insertIntoServerClientMaps(serverEntityID, newLocalEntityID);
|
||||
m_World->AttachComponent(newLocalEntityID, componentType);
|
||||
updateFields(packet, componentInfo, newLocalEntityID, componentType);
|
||||
updateFields(packet, componentInfo, newLocalEntityID);
|
||||
}
|
||||
}
|
||||
// Parent logic
|
||||
@@ -295,10 +336,14 @@ void Client::disconnect()
|
||||
|
||||
bool Client::OnInputCommand(const Events::InputCommand & e)
|
||||
{
|
||||
if (e.PlayerID != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.Command == "ConnectToServer") { // Connect for now
|
||||
if (e.Value > 0) {
|
||||
m_Reliable.Connect(m_PlayerName, address, port);
|
||||
m_Unreliable.Connect(m_PlayerName, address, port);
|
||||
m_Reliable.Connect(m_PlayerName, m_Address, m_Port);
|
||||
m_Unreliable.Connect(m_PlayerName, m_Address, m_Port);
|
||||
}
|
||||
//LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user