From 9e3341a32ae61994aa5ce4646199dbddfc22ad16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 25 Jan 2017 15:55:07 +0100 Subject: [PATCH 01/73] Commit current work This is a temporary branch because I'm missing a USB drive, huehue --- include/Nazara/Network/ENetHost.hpp | 121 ++++ include/Nazara/Network/ENetHost.inl | 65 ++ include/Nazara/Network/ENetPacket.hpp | 78 +++ include/Nazara/Network/ENetPeer.hpp | 205 ++++++ include/Nazara/Network/ENetPeer.inl | 29 + include/Nazara/Network/ENetProtocol.hpp | 272 ++++++++ src/Nazara/Network/ENetHost.cpp | 743 ++++++++++++++++++++ src/Nazara/Network/ENetPacket.cpp | 23 + src/Nazara/Network/ENetPeer.cpp | 885 ++++++++++++++++++++++++ src/Nazara/Network/ENetSocket.cpp | 642 +++++++++++++++++ 10 files changed, 3063 insertions(+) create mode 100644 include/Nazara/Network/ENetHost.hpp create mode 100644 include/Nazara/Network/ENetHost.inl create mode 100644 include/Nazara/Network/ENetPacket.hpp create mode 100644 include/Nazara/Network/ENetPeer.hpp create mode 100644 include/Nazara/Network/ENetPeer.inl create mode 100644 include/Nazara/Network/ENetProtocol.hpp create mode 100644 src/Nazara/Network/ENetHost.cpp create mode 100644 src/Nazara/Network/ENetPacket.cpp create mode 100644 src/Nazara/Network/ENetPeer.cpp create mode 100644 src/Nazara/Network/ENetSocket.cpp diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp new file mode 100644 index 000000000..87d4dd37b --- /dev/null +++ b/include/Nazara/Network/ENetHost.hpp @@ -0,0 +1,121 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETHOST_HPP +#define NAZARA_ENETHOST_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ENetPeer; + + class NAZARA_NETWORK_API ENetHost + { + friend ENetPeer; + friend class Network; + + public: + inline ENetHost(); + ENetHost(const ENetHost&) = delete; + ENetHost(ENetHost&&) = default; + inline ~ENetHost(); + + void Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet); + + bool Connect(const IpAddress& remoteAddress, std::size_t channelCount = 0, UInt32 data = 0); + bool Connect(const String& hostName, NetProtocol protocol = NetProtocol_Any, const String& service = "http", ResolveError* error = nullptr, std::size_t channelCount = 0, UInt32 data = 0); + + inline bool Create(NetProtocol protocol, UInt16 port, std::size_t peerCount, std::size_t channelCount = 0); + bool Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount = 0); + bool Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount, UInt32 incomingBandwidth, UInt32 outgoingBandwidth); + void Destroy(); + + void Flush(); + + int Service(ENetEvent* event, UInt32 timeout); + + ENetHost& operator=(const ENetHost&) = delete; + ENetHost& operator=(ENetHost&&) = default; + + private: + bool InitSocket(const IpAddress& address); + + inline void AddToDispatchQueue(ENetPeer* peer); + inline void RemoveFromDispatchQueue(ENetPeer* peer); + + bool DispatchIncomingCommands(ENetEvent* event); + + ENetPeer* HandleConnect(ENetProtocolHeader* header, ENetProtocol* command); + bool HandleIncomingCommands(ENetEvent* event); + bool HandleSendReliable(ENetPeer& peer, const ENetProtocol& command, UInt8** currentData); + + int ReceiveIncomingCommands(ENetEvent* event); + + void NotifyConnect(ENetPeer* peer, ENetEvent* event); + void NotifyDisconnect(ENetPeer*, ENetEvent* event); + + void ThrottleBandwidth(); + + static bool Initialize(); + static void Uninitialize(); + + std::array m_commands; + std::array m_packetData[2]; + std::bernoulli_distribution m_packetLossProbability; + std::size_t m_bandwidthLimitedPeers; + std::size_t m_bufferCount; + std::size_t m_channelLimit; + std::size_t m_commandCount; + std::size_t m_duplicatePeers; + std::size_t m_maximumPacketSize; + std::size_t m_maximumWaitingData; + std::size_t m_receivedDataLength; + std::vector m_peers; + Bitset m_dispatchQueue; + MemoryPool m_packetPool; + IpAddress m_address; + IpAddress m_receivedAddress; + SocketPoller m_poller; + UdpSocket m_socket; + UInt32 m_bandwidthThrottleEpoch; + UInt32 m_connectedPeers; + UInt32 m_mtu; + UInt32 m_randomSeed; + UInt32 m_incomingBandwidth; + UInt32 m_outgoingBandwidth; + UInt32 m_serviceTime; + UInt32 m_totalSentData; + UInt32 m_totalSentPackets; + UInt32 m_totalReceivedData; + UInt32 m_totalReceivedPackets; + UInt8* m_receivedData; + bool m_isSimulationEnabled; + bool m_shouldAcceptConnections; + bool m_recalculateBandwidthLimits; + + static std::mt19937 s_randomGenerator; + static std::mt19937_64 s_randomGenerator64; + }; +} + +#include + +#endif // NAZARA_RUDPSERVER_HPP diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl new file mode 100644 index 000000000..c4a077e8b --- /dev/null +++ b/include/Nazara/Network/ENetHost.inl @@ -0,0 +1,65 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline ENetHost::ENetHost() : + m_packetPool(sizeof(ENetPacket)) + { + } + + inline ENetHost::~ENetHost() + { + Destroy(); + } + + inline bool ENetHost::Create(NetProtocol protocol, UInt16 port, std::size_t peerCount, std::size_t channelCount) + { + NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO + NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); + + IpAddress any; + switch (protocol) + { + case NetProtocol_Any: + case NetProtocol_Unknown: + NazaraInternalError("Invalid protocol Any at this point"); + return false; + + case NetProtocol_IPv4: + any = IpAddress::AnyIpV4; + break; + + case NetProtocol_IPv6: + any = IpAddress::AnyIpV6; + break; + } + + any.SetPort(port); + return Create(any, peerCount, channelCount); + } + + inline void ENetHost::Destroy() + { + m_poller.Clear(); + m_peers.clear(); + m_socket.Close(); + } + + inline void ENetHost::AddToDispatchQueue(ENetPeer* peer) + { + m_dispatchQueue.UnboundedSet(peer->m_incomingPeerID); + } + + inline void ENetHost::RemoveFromDispatchQueue(ENetPeer* peer) + { + m_dispatchQueue.UnboundedReset(peer->m_incomingPeerID); + } +} + +#include diff --git a/include/Nazara/Network/ENetPacket.hpp b/include/Nazara/Network/ENetPacket.hpp new file mode 100644 index 000000000..ad1610eb4 --- /dev/null +++ b/include/Nazara/Network/ENetPacket.hpp @@ -0,0 +1,78 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETPACKET_HPP +#define NAZARA_ENETPACKET_HPP + +#include +#include + +namespace Nz +{ + enum ENetPacketFlag + { + ENetPacketFlag_NoAllocate, + ENetPacketFlag_Reliable, + ENetPacketFlag_Unsequenced, + ENetPacketFlag_UnreliableFragment, + ENetPacketFlag_Sent + }; + + template<> + struct EnumAsFlags + { + static constexpr bool value = true; + static constexpr int max = ENetPacketFlag_Sent; + }; + + using ENetPacketFlags = Flags; + + class MemoryPool; + + struct ENetPacket + { + MemoryPool* owner; + ENetPacketFlags flags; + NetPacket data; + std::size_t referenceCount = 0; + }; + + struct ENetPacketRef + { + ENetPacketRef() = default; + + ENetPacketRef(ENetPacket* packet) + { + Reset(packet); + } + + ~ENetPacketRef() + { + Reset(); + } + + void Reset(ENetPacket* packet = nullptr); + + operator ENetPacket*() const + { + return m_packet; + } + + ENetPacket* operator->() const + { + return m_packet; + } + + ENetPacketRef& operator=(ENetPacket* packet) + { + Reset(packet); + } + + ENetPacket* m_packet = nullptr; + }; +} + +#endif // NAZARA_ENETPACKET_HPP diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp new file mode 100644 index 000000000..4ae8ca16b --- /dev/null +++ b/include/Nazara/Network/ENetPeer.hpp @@ -0,0 +1,205 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETPEER_HPP +#define NAZARA_ENETPEER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ENetHost; + + class NAZARA_NETWORK_API ENetPeer + { + friend ENetHost; + friend struct PacketRef; + + public: + ENetPeer(const ENetPeer&) = delete; + ENetPeer(ENetPeer&&) = default; + ~ENetPeer() = default; + + void Disconnect(UInt32 data); + void DisconnectLater(UInt32 data); + void DisconnectNow(UInt32 data); + + void Ping(); + + bool Receive(ENetPacketRef* packet, UInt8* channelId); + void Reset(); + + bool Send(UInt8 channelId, ENetPacketRef packetRef); + bool Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet); + + void ThrottleConfigure(UInt32 interval, UInt32 acceleration, UInt32 deceleration); + + ENetPeer& operator=(const ENetPeer&) = delete; + ENetPeer& operator=(ENetPeer&&) = default; + + private: + ENetPeer(ENetHost* host, UInt16 peerId); + + void InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand); + void InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize); + + struct Acknowledgement; + struct Channel; + struct IncomingCommmand; + struct OutgoingCommand; + + // Protocol functions + inline void ChangeState(ENetPeerState state); + inline void DispatchState(ENetPeerState state); + + void DispatchIncomingReliableCommands(Channel& channel); + void DispatchIncomingUnreliableCommands(Channel& channel); + + void OnConnect(); + void OnDisconnect(); + + ENetProtocolCommand RemoveSentReliableCommands(UInt16 reliableSequenceNumber, UInt8 channelId); + void RemoveSentUnreliableCommands(); + + void ResetQueues(); + + bool QueueAcknowledgement(ENetProtocol& command, UInt16 sentTime); + IncomingCommmand* QueueIncomingCommand(ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount); + void QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length); + + void SetupOutgoingCommand(OutgoingCommand& outgoingCommand); + + int Throttle(UInt32 rtt); + + struct Acknowledgement + { + ENetProtocol command; + UInt32 sentTime; + }; + + struct Channel + { + Channel() + { + incomingReliableSequenceNumber = 0; + incomingUnreliableSequenceNumber = 0; + outgoingReliableSequenceNumber = 0; + outgoingUnreliableSequenceNumber = 0; + usedReliableWindows = 0; + reliableWindows.fill(0); + } + + std::array reliableWindows; + std::list incomingReliableCommands; + std::list incomingUnreliableCommands; + UInt16 incomingReliableSequenceNumber; + UInt16 incomingUnreliableSequenceNumber; + UInt16 outgoingReliableSequenceNumber; + UInt16 outgoingUnreliableSequenceNumber; + UInt16 usedReliableWindows; + }; + + struct IncomingCommmand + { + ENetProtocol command; + UInt16 reliableSequenceNumber; + UInt16 unreliableSequenceNumber; + UInt32 fragmentsRemaining; + std::vector fragments; + ENetPacketRef packet; + }; + + struct OutgoingCommand + { + ENetProtocol command; + ENetPacketRef packet; + UInt16 fragmentLength; + UInt16 reliableSequenceNumber; + UInt16 sendAttempts; + UInt16 unreliableSequenceNumber; + UInt32 fragmentOffset; + UInt32 roundTripTimeout; + UInt32 roundTripTimeoutLimit; + UInt32 sentTime; + }; + + ENetHost* m_host; + IpAddress m_address; /**< Internet address of the peer */ + std::vector m_channels; + std::list m_acknowledgements; + std::list m_dispatchedCommands; + std::list m_outgoingReliableCommands; + std::list m_outgoingUnreliableCommands; + std::list m_sentReliableCommands; + std::list m_sentUnreliableCommands; + MemoryPool m_packetPool; + //ENetListNode m_dispatchList; + ENetPeerState m_state; + UInt8 m_incomingSessionID; + UInt8 m_outgoingSessionID; + UInt16 m_incomingPeerID; + UInt16 m_incomingUnsequencedGroup; + UInt16 m_outgoingPeerID; + UInt16 m_outgoingReliableSequenceNumber; + UInt16 m_outgoingUnsequencedGroup; + UInt32 m_connectID; + UInt32 m_earliestTimeout; + UInt32 m_eventData; + UInt32 m_highestRoundTripTimeVariance; + UInt32 m_incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + UInt32 m_incomingBandwidthThrottleEpoch; + UInt32 m_incomingDataTotal; + UInt32 m_lastReceiveTime; + UInt32 m_lastRoundTripTime; + UInt32 m_lastRoundTripTimeVariance; + UInt32 m_lastSendTime; + UInt32 m_lowestRoundTripTime; + UInt32 m_mtu; + UInt32 m_nextTimeout; + UInt32 m_outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + UInt32 m_outgoingBandwidthThrottleEpoch; + UInt32 m_outgoingDataTotal; + UInt32 m_packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + UInt32 m_packetLossEpoch; + UInt32 m_packetLossVariance; + UInt32 m_packetThrottle; + UInt32 m_packetThrottleAcceleration; + UInt32 m_packetThrottleCounter; + UInt32 m_packetThrottleDeceleration; + UInt32 m_packetThrottleEpoch; + UInt32 m_packetThrottleInterval; + UInt32 m_packetThrottleLimit; + UInt32 m_packetsLost; + UInt32 m_packetsSent; + UInt32 m_pingInterval; + UInt32 m_reliableDataInTransit; + UInt32 m_roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgment */ + UInt32 m_roundTripTimeVariance; + UInt32 m_timeoutLimit; + UInt32 m_timeoutMaximum; + UInt32 m_timeoutMinimum; + UInt32 m_unsequencedWindow[ENetPeer_ReliableWindowSize / 32]; + UInt32 m_windowSize; + std::size_t m_totalWaitingData; + }; +} + +#include + +#endif // NAZARA_ENETPEER_HPP diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl new file mode 100644 index 000000000..a0cebbc4e --- /dev/null +++ b/include/Nazara/Network/ENetPeer.inl @@ -0,0 +1,29 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline void ENetPeer::ChangeState(ENetPeerState state) + { + if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater) + OnConnect(); + else + OnDisconnect(); + + m_state = state; + } + + inline void ENetPeer::DispatchState(ENetPeerState state) + { + ChangeState(state); + + m_host->AddToDispatchQueue(this); + } +} + +#include diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp new file mode 100644 index 000000000..d4d74fd01 --- /dev/null +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -0,0 +1,272 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETPROTOCOL_HPP +#define NAZARA_ENETPROTOCOL_HPP + +#include +#include +#include + +namespace Nz +{ + // Constants for the ENet implementation and protocol + enum ENetConstants + { + ENetHost_BandwidthThrottleInterval = 1000, + ENetHost_DefaultMaximumPacketSize = 32 * 1024 * 1024, + ENetHost_DefaultMaximumWaitingData = 32 * 1024 * 1024, + ENetHost_DefaultMTU = 1400, + ENetHost_ReceiveBufferSize = 256 * 1024, + ENetHost_SendBufferSize = 256 * 1024, + + ENetPeer_DefaultPacketThrottle = 32, + ENetPeer_DefaultRoundTripTime = 500, + ENetPeer_FreeReliableWindows = 8, + ENetPeer_FreeUnsequencedWindows = 32, + ENetPeer_PacketLossInterval = 10000, + ENetPeer_PacketLossScale = (1 << 16), + ENetPeer_PacketThrottleAcceleration = 2, + ENetPeer_PacketThrottleCounter = 7, + ENetPeer_PacketThrottleDeceleration = 2, + ENetPeer_PacketThrottleInterval = 5000, + ENetPeer_PacketThrottleScale = 32, + ENetPeer_PingInterval = 500, + ENetPeer_ReliableWindows = 16, + ENetPeer_ReliableWindowSize = 0x1000, + ENetPeer_TimeoutLimit = 32, + ENetPeer_TimeoutMaximum = 30000, + ENetPeer_TimeoutMinimum = 5000, + ENetPeer_UnsequencedWindows = 64, + ENetPeer_UnsequencedWindowSize = 1024, + ENetPeer_WindowSizeScale = 64 * 1024, + + ENetProtocol_MaximumChannelCount = 255, + ENetProtocol_MaximumFragmentCount = 1024 * 1024, + ENetProtocol_MaximumMTU = 4096, + ENetProtocol_MaximumPacketCommands = 32, + ENetProtocol_MaximumPeerId = 0xFFF, + ENetProtocol_MaximumWindowSize = 65536, + ENetProtocol_MinimumChannelCount = 1, + ENetProtocol_MinimumMTU = 576, + ENetProtocol_MinimumWindowSize = 4096 + }; + + enum class ENetPeerState + { + AcknowledgingConnect = 2, + AcknowledgingDisconnect = 8, + Connecting = 1, + ConnectionPending = 3, + ConnectionSucceeded = 4, + Connected = 5, + Disconnected = 0, + Disconnecting = 7, + DisconnectLater = 6, + Zombie = 9 + }; + + enum ENetProtocolCommand + { + // Keeping the values is important for compatibility with the native ENet protocol + ENetProtocolCommand_Acknowledge = 1, + ENetProtocolCommand_BandwidthLimit = 10, + ENetProtocolCommand_Connect = 2, + ENetProtocolCommand_Disconnect = 4, + ENetProtocolCommand_None = 0, + ENetProtocolCommand_Ping = 5, + ENetProtocolCommand_SendFragment = 8, + ENetProtocolCommand_SendReliable = 6, + ENetProtocolCommand_SendUnreliable = 7, + ENetProtocolCommand_SendUnreliableFragment = 12, + ENetProtocolCommand_SendUnsequenced = 9, + ENetProtocolCommand_ThrottleConfigure = 11, + ENetProtocolCommand_VerifyConnect = 3, + ENetProtocolCommand_Count = 13, + + ENetProtocolCommand_Mask = 0x0F + }; + + enum ENetProtocolFlag + { + ENetProtocolFlag_Acknowledge = (1 << 7), + ENetProtocolFlag_Unsequenced = (1 << 6), + + ENetProtocolHeaderFlag_Compressed = (1 << 14), + ENetProtocolHeaderFlag_SentTime = (1 << 15), + ENetProtocolHeaderFlag_Mask = ENetProtocolHeaderFlag_Compressed | ENetProtocolHeaderFlag_SentTime, + + ENetProtocolHeaderSessionMask = (3 << 12), + ENetProtocolHeaderSessionShift = 12 + }; + + enum class ENetEventType + { + /** no event occurred within the specified time limit */ + None, + + /** a connection request initiated by enet_host_connect has completed. + * The peer field contains the peer which successfully connected. + */ + Connect, + + /** a peer has disconnected. This event is generated on a successful + * completion of a disconnect initiated by enet_peer_disconnect, if + * a peer has timed out, or if a connection request initialized by + * enet_host_connect has timed out. The peer field contains the peer + * which disconnected. The data field contains user supplied data + * describing the disconnection, or 0, if none is available. + */ + Disconnect, + + /** a packet has been received from a peer. The peer field specifies the + * peer which sent the packet. The channelID field specifies the channel + * number upon which the packet was received. The packet field contains + * the packet that was received; this packet must be destroyed with + * enet_packet_destroy after use. + */ + Receive + }; + + struct ENetEvent + { + ENetEventType type; + ENetPeer* peer; + UInt8 channelId; + UInt32 data; + ENetPacketRef packet; + }; + + struct ENetProtocolHeader + { + UInt16 peerID; + UInt16 sentTime; + }; + + struct ENetProtocolCommandHeader + { + UInt8 command; + UInt8 channelID; + UInt16 reliableSequenceNumber; + }; + + struct ENetProtocolAcknowledge + { + ENetProtocolCommandHeader header; + UInt16 receivedReliableSequenceNumber; + UInt16 receivedSentTime; + }; + + struct ENetProtocolConnect + { + ENetProtocolCommandHeader header; + UInt16 outgoingPeerID; + UInt8 incomingSessionID; + UInt8 outgoingSessionID; + UInt32 mtu; + UInt32 windowSize; + UInt32 channelCount; + UInt32 incomingBandwidth; + UInt32 outgoingBandwidth; + UInt32 packetThrottleInterval; + UInt32 packetThrottleAcceleration; + UInt32 packetThrottleDeceleration; + UInt32 connectID; + UInt32 data; + }; + + struct ENetProtocolBandwidthLimit + { + ENetProtocolCommandHeader header; + UInt32 incomingBandwidth; + UInt32 outgoingBandwidth; + }; + + struct ENetProtocolDisconnect + { + ENetProtocolCommandHeader header; + UInt32 data; + }; + + struct ENetProtocolPing + { + ENetProtocolCommandHeader header; + }; + + struct ENetProtocolSendFragment + { + ENetProtocolCommandHeader header; + UInt16 startSequenceNumber; + UInt16 dataLength; + UInt32 fragmentCount; + UInt32 fragmentNumber; + UInt32 totalLength; + UInt32 fragmentOffset; + }; + + struct ENetProtocolSendReliable + { + ENetProtocolCommandHeader header; + UInt16 dataLength; + }; + + struct ENetProtocolSendUnreliable + { + ENetProtocolCommandHeader header; + UInt16 unreliableSequenceNumber; + UInt16 dataLength; + }; + + struct ENetProtocolSendUnsequenced + { + ENetProtocolCommandHeader header; + UInt16 unsequencedGroup; + UInt16 dataLength; + }; + + struct ENetProtocolThrottleConfigure + { + ENetProtocolCommandHeader header; + UInt32 packetThrottleInterval; + UInt32 packetThrottleAcceleration; + UInt32 packetThrottleDeceleration; + }; + + struct ENetProtocolVerifyConnect + { + ENetProtocolCommandHeader header; + UInt16 outgoingPeerID; + UInt8 incomingSessionID; + UInt8 outgoingSessionID; + UInt32 mtu; + UInt32 windowSize; + UInt32 channelCount; + UInt32 incomingBandwidth; + UInt32 outgoingBandwidth; + UInt32 packetThrottleInterval; + UInt32 packetThrottleAcceleration; + UInt32 packetThrottleDeceleration; + UInt32 connectID; + }; + + union ENetProtocol + { + ENetProtocolCommandHeader header; + ENetProtocolAcknowledge acknowledge; + ENetProtocolBandwidthLimit bandwidthLimit; + ENetProtocolConnect connect; + ENetProtocolDisconnect disconnect; + ENetProtocolPing ping; + ENetProtocolSendReliable sendReliable; + ENetProtocolSendUnreliable sendUnreliable; + ENetProtocolSendUnsequenced sendUnsequenced; + ENetProtocolSendFragment sendFragment; + ENetProtocolThrottleConfigure throttleConfigure; + ENetProtocolVerifyConnect verifyConnect; + }; +} + +#endif // NAZARA_ENETPROTOCOL_HPP diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp new file mode 100644 index 000000000..05179e615 --- /dev/null +++ b/src/Nazara/Network/ENetHost.cpp @@ -0,0 +1,743 @@ +#include +#include +#include +#include +#include +#include +#include + +#define ENET_TIME_OVERFLOW 86400000 + +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) + +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + +namespace Nz +{ + /// Temporary + template + T HostToNet(T value) + { + #ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); + #else + return value; + #endif + } + + /// Temporary + template + T NetToHost(T value) + { + #ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); + #else + return value; + #endif + } + + + void ENetHost::Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) + { + ENetPacket* enetPacket = m_packetPool.New(); + enetPacket->flags = flags; + enetPacket->data = std::move(packet); + enetPacket->owner = &m_packetPool; + + for (ENetPeer& peer : m_peers) + { + if (peer.m_state != ENetPeerState::Connected) + continue; + + peer.Send(channelId, enetPacket); + } + } + + bool ENetHost::Connect(const IpAddress& remoteAddress, std::size_t channelCount, UInt32 data) + { + NazaraAssert(remoteAddress.IsValid(), "Invalid remote address"); + NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port"); + + std::size_t peerId; + for (peerId = 0; peerId < m_peers.size(); ++peerId) + { + if (m_peers[peerId].m_state == ENetPeerState::Disconnected) + break; + } + + if (peerId >= m_peers.size()) + { + NazaraError("Insufficient peers"); + return false; + } + + m_channelLimit = Clamp(channelCount, ENetConstants::ENetProtocol_MinimumChannelCount, ENetConstants::ENetProtocol_MaximumChannelCount); + + UInt32 windowSize; + if (m_outgoingBandwidth == 0) + windowSize = ENetProtocol_MaximumWindowSize; + else + windowSize = (m_outgoingBandwidth / ENetConstants::ENetPeer_WindowSizeScale) * ENetProtocol_MinimumWindowSize; + + ENetPeer& peer = m_peers[peerId]; + peer.InitOutgoing(channelCount, remoteAddress, ++m_randomSeed, windowSize); + + ENetProtocol command; + command.header.command = ENetProtocolCommand_Connect | ENetProtocolFlag_Acknowledge; + command.header.channelID = 0xFF; + + command.connect.channelCount = HostToNet(static_cast(channelCount)); + command.connect.connectID = peer.m_connectID; + command.connect.data = HostToNet(data); + command.connect.incomingBandwidth = HostToNet(m_incomingBandwidth); + command.connect.incomingSessionID = peer.m_incomingSessionID; + command.connect.mtu = HostToNet(peer.m_mtu); + command.connect.outgoingBandwidth = HostToNet(m_outgoingBandwidth); + command.connect.outgoingPeerID = HostToNet(peer.m_incomingPeerID); + command.connect.outgoingSessionID = peer.m_outgoingSessionID; + command.connect.packetThrottleAcceleration = HostToNet(peer.m_packetThrottleAcceleration); + command.connect.packetThrottleDeceleration = HostToNet(peer.m_packetThrottleDeceleration); + command.connect.packetThrottleInterval = HostToNet(peer.m_packetThrottleInterval); + command.connect.windowSize = HostToNet(peer.m_windowSize); + + peer.QueueOutgoingCommand(command, nullptr, 0, 0); + + return true; + } + + bool ENetHost::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error, std::size_t channelCount, UInt32 data) + { + std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); + if (results.empty()) + return false; + + IpAddress hostnameAddress; + for (const HostnameInfo& result : results) + { + if (!result.address) + continue; + + if (result.socketType != SocketType_UDP) + continue; + + hostnameAddress = result.address; + break; //< Take first valid address + } + + return Connect(hostnameAddress, channelCount, data); + } + + bool ENetHost::Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount) + { + return Create(address, peerCount, channelCount, 0, 0); + } + + bool ENetHost::Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount, UInt32 incomingBandwidth, UInt32 outgoingBandwidth) + { + NazaraAssert(address.IsValid(), "Invalid listening address"); + + if (peerCount > ENetConstants::ENetProtocol_MaximumPeerId) + { + NazaraError("Peer count exceeds maximum peer count supported by protocol (" + String::Number(ENetConstants::ENetProtocol_MaximumPeerId) + ")"); + return false; + } + + if (!InitSocket(address)) + return false; + + m_peers.resize(peerCount); + + m_address = address; + m_randomSeed = *reinterpret_cast(this); + m_randomSeed += s_randomGenerator(); + m_randomSeed = (m_randomSeed << 16) | (m_randomSeed >> 16); + m_channelLimit = Clamp(channelCount, ENetConstants::ENetProtocol_MinimumChannelCount, ENetConstants::ENetProtocol_MaximumChannelCount); + m_incomingBandwidth = incomingBandwidth; + m_outgoingBandwidth = outgoingBandwidth; + m_bandwidthThrottleEpoch = 0; + m_recalculateBandwidthLimits = false; + m_mtu = ENetConstants::ENetHost_DefaultMTU; + m_commandCount = 0; + m_bufferCount = 0; + m_receivedAddress = IpAddress::AnyIpV4; + m_receivedData = nullptr; + m_receivedDataLength = 0; + + m_totalSentData = 0; + m_totalSentPackets = 0; + m_totalReceivedData = 0; + m_totalReceivedPackets = 0; + + m_bandwidthLimitedPeers = 0; + m_connectedPeers = 0; + m_duplicatePeers = ENetConstants::ENetProtocol_MaximumPeerId; + m_maximumPacketSize = ENetConstants::ENetHost_DefaultMaximumPacketSize; + m_maximumWaitingData = ENetConstants::ENetHost_DefaultMaximumWaitingData; + + return true; + } + + void ENetHost::Flush() + { + m_serviceTime = GetElapsedMilliseconds(); + + SendOutgoingCommands(nullptr, 0); + } + + int ENetHost::Service(ENetEvent* event, UInt32 timeout) + { + UInt32 waitCondition; + + if (event) + { + event->type = ENetEventType::None; + event->peer = nullptr; + event->packet = nullptr; + + if (DispatchIncomingCommands(event)) + return 1; + } + + m_serviceTime = GetElapsedMilliseconds(); + timeout += m_serviceTime; + + do + { + if (ENET_TIME_DIFFERENCE(m_serviceTime, m_bandwidthThrottleEpoch) >= ENetConstants::ENetHost_BandwidthThrottleInterval) + ThrottleBandwidth(); + + switch (SendOutgoingCommands(event, true)) + { + case 1: + return 1; + + case -1: + #ifdef ENET_DEBUG + perror("Error sending outgoing packets"); + #endif + return -1; + + default: + break; + } + + switch (ReceiveIncomingCommands(event)) + { + case 1: + return 1; + + case -1: +#ifdef ENET_DEBUG + perror("Error receiving incoming packets"); +#endif + + return -1; + + default: + break; + } + + switch (SendOutgoingCommands(event, 1)) + { + case 1: + return 1; + + case -1: +#ifdef ENET_DEBUG + perror("Error sending outgoing packets"); +#endif + + return -1; + + default: + break; + } + + if (event) + { + switch (DispatchIncomingCommands(event)) + { + case 1: + return 1; + + case -1: + #ifdef ENET_DEBUG + perror("Error dispatching incoming packets"); + #endif + + return -1; + + default: + break; + } + } + + if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) + return 0; + + for (;;) + { + m_serviceTime = GetElapsedMilliseconds(); + + if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) + return 0; + + SocketError error; + if (m_poller.Wait(ENET_TIME_DIFFERENCE(timeout, m_serviceTime), &error)) + break; + + if (error != SocketError_NoError) + return -1; + } + + m_serviceTime = GetElapsedMilliseconds(); + } + while (m_poller.IsReady(m_socket)); + + return 0; + } + + bool ENetHost::InitSocket(const IpAddress& address) + { + if (!m_socket.Create(address.GetProtocol())) + return false; + + m_socket.EnableBlocking(false); + m_socket.EnableBroadcasting(true); + m_socket.SetReceiveBufferSize(ENetConstants::ENetHost_ReceiveBufferSize); + m_socket.SetSendBufferSize(ENetConstants::ENetHost_SendBufferSize); + + if (!address.IsLoopback()) + { + if (m_socket.Bind(address) != SocketState_Bound) + { + NazaraError("Failed to bind address " + address.ToString()); + return false; + } + } + + m_poller.RegisterSocket(m_socket); + + return true; + } + + bool ENetHost::DispatchIncomingCommands(ENetEvent* event) + { + for (std::size_t bit = m_dispatchQueue.FindFirst(); bit != m_dispatchQueue.npos; bit = m_dispatchQueue.FindNext(bit)) + { + m_dispatchQueue.Reset(bit); + + ENetPeer& peer = m_peers[bit]; + switch (peer.m_state) + { + case ENetPeerState::ConnectionPending: + case ENetPeerState::ConnectionSucceeded: + peer.ChangeState(ENetPeerState::Connected); + + event->type = ENetEventType::Connect; + event->peer = &peer; + event->data = peer.m_eventData; + return true; + + case ENetPeerState::Zombie: + m_recalculateBandwidthLimits = true; + + event->type = ENetEventType::Disconnect; + event->peer = &peer; + event->data = peer.m_eventData; + + peer.Reset(); + return true; + + case ENetPeerState::Connected: + if (peer.m_dispatchedCommands.empty()) + continue; + + if (!peer.Receive(&event->packet, &event->channelId)) + continue; + + event->type = ENetEventType::Receive; + event->peer = &peer; + + if (!peer.m_dispatchedCommands.empty()) + AddToDispatchQueue(&peer); + + return true; + } + } + + return false; + } + + ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* header, ENetProtocol* command) + { + UInt32 channelCount = NetToHost(command->connect.channelCount); + + if (channelCount < ENetProtocol_MinimumChannelCount || channelCount > ENetProtocol_MaximumChannelCount) + return nullptr; + + std::size_t duplicatePeers = 0; + ENetPeer* peer = nullptr; + for (ENetPeer& currentPeer : m_peers) + { + if (currentPeer.m_state == ENetPeerState::Disconnected) + { + if (!peer) + peer = ¤tPeer; + } + else if (currentPeer.m_state != ENetPeerState::Connecting) + { + // Compare users without comparing their port + IpAddress first(currentPeer.m_address); + first.SetPort(0); + + IpAddress second(m_receivedAddress); + second.SetPort(0); + + if (first == second) + { + if (currentPeer.m_address.GetPort() == m_receivedAddress.GetPort() && currentPeer.m_connectID == command->connect.connectID) + return nullptr; + + ++duplicatePeers; + } + } + } + + if (!peer || duplicatePeers >= m_duplicatePeers) + return nullptr; + + channelCount = std::min(channelCount, m_channelLimit); + + peer->InitIncoming(channelCount, m_receivedAddress, command->connect); + + UInt32 windowSize; + if (m_incomingBandwidth == 0) + windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else + windowSize = (m_incomingBandwidth / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + windowSize = std::max(windowSize, NetToHost(command->connect.windowSize)); + windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + + ENetProtocol verifyCommand; + verifyCommand.header.command = ENetProtocolCommand_VerifyConnect | ENetProtocolFlag_Acknowledge; + verifyCommand.header.channelID = 0xFF; + verifyCommand.verifyConnect.outgoingPeerID = HostToNet(peer->m_incomingPeerID); + verifyCommand.verifyConnect.incomingSessionID = peer->m_outgoingSessionID; + verifyCommand.verifyConnect.outgoingSessionID = peer->m_incomingSessionID; + verifyCommand.verifyConnect.mtu = HostToNet(peer->m_mtu); + verifyCommand.verifyConnect.windowSize = HostToNet(windowSize); + verifyCommand.verifyConnect.channelCount = HostToNet(channelCount); + verifyCommand.verifyConnect.incomingBandwidth = HostToNet(m_incomingBandwidth); + verifyCommand.verifyConnect.outgoingBandwidth = HostToNet(m_outgoingBandwidth); + verifyCommand.verifyConnect.packetThrottleInterval = HostToNet(peer->m_packetThrottleInterval); + verifyCommand.verifyConnect.packetThrottleAcceleration = HostToNet(peer->m_packetThrottleAcceleration); + verifyCommand.verifyConnect.packetThrottleDeceleration = HostToNet(peer->m_packetThrottleDeceleration); + verifyCommand.verifyConnect.connectID = peer->m_connectID; + + peer->QueueOutgoingCommand(verifyCommand, nullptr, 0, 0); + + return peer; + } + + bool ENetHost::HandleIncomingCommands(ENetEvent* event) + { + if (m_receivedDataLength < NazaraOffsetOf(ENetProtocolHeader, sentTime)) + return false; + + ENetProtocolHeader* header = reinterpret_cast(m_receivedData); + + peerID = NetToHost(header->peerID); + sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT; + flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK; + peerID &= ~(ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK); + + headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof(ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *)0)->sentTime); + if (host->checksum != NULL) + headerSize += sizeof(enet_uint32); + + if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) + peer = NULL; + else + if (peerID >= host->peerCount) + return 0; + else + { + peer = &host->peers[peerID]; + + if (peer->state == ENET_PEER_STATE_DISCONNECTED || + peer->state == ENET_PEER_STATE_ZOMBIE || + ((host->receivedAddress.host != peer->address.host || + host->receivedAddress.port != peer->address.port) && + peer->address.host != ENET_HOST_BROADCAST) || + (peer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && + sessionID != peer->incomingSessionID)) + return 0; + } + + return false; + } + + bool ENetHost::HandleSendReliable(ENetPeer& peer, const ENetProtocol& command, UInt8** currentData) + { + if (command.header.channelID >= peer.m_channels.size() || (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater)) + return false; + + UInt16 dataLength = NetToHost(command.sendReliable.dataLength); + *currentData += dataLength; + if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) + return false; + + if (!peer.QueueIncomingCommand(command, co)) + + return true; + } + + int ENetHost::ReceiveIncomingCommands(ENetEvent* event) + { + for (unsigned int i = 0; i < 256; ++i) + { + NetPacket packet; + + std::size_t receivedLength; + if (!m_socket.Receive(m_packetData[0].data(), m_packetData[0].size(), &m_receivedAddress, &receivedLength)) + return -1; //< Error + + if (receivedLength == 0) + return 0; + + m_receivedData = m_packetData[0].data(); + m_receivedDataLength = receivedLength; + + m_totalReceivedData += receivedLength; + m_totalReceivedPackets++; + + // Intercept + + switch (HandleIncomingCommands(event)) + { + case 1: + return 1; + + case -1: + return -1; + + default: + break; + } + } + + return -1; + } + + void ENetHost::NotifyConnect(ENetPeer* peer, ENetEvent* event) + { + m_recalculateBandwidthLimits = true; + + if (event) + { + peer->ChangeState(ENetPeerState::Connected); + + event->type = ENetEventType::Connect; + event->peer = peer; + event->data = peer->m_eventData; + } + else + peer->DispatchState(peer->m_state == ENetPeerState::Connecting ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); + } + + void ENetHost::NotifyDisconnect(ENetPeer* peer, ENetEvent* event) + { + if (peer->m_state >= ENetPeerState::ConnectionPending) + m_recalculateBandwidthLimits = true; + + if (peer->m_state != ENetPeerState::Connecting && (peer->m_state < ENetPeerState::ConnectionSucceeded)) + peer->Reset(); + else if (event) + { + event->type = ENetEventType::Disconnect; + event->peer = peer; + event->data = peer->m_eventData; + + peer->Reset(); + } + else + { + peer->m_eventData = 0; + + peer->DispatchState(ENetPeerState::Zombie); + } + } + + void ENetHost::ThrottleBandwidth() + { + UInt32 currentTime = GetElapsedMilliseconds(); + UInt32 elapsedTime = currentTime - m_bandwidthThrottleEpoch; + + if (elapsedTime < ENetConstants::ENetHost_BandwidthThrottleInterval) + return; + + m_bandwidthThrottleEpoch = currentTime; + + if (m_connectedPeers == 0) + return; + + UInt32 dataTotal = ~0; + UInt32 bandwidth = ~0; + + if (m_outgoingBandwidth != 0) + { + bandwidth = (m_outgoingBandwidth * elapsedTime) / 1000; + + dataTotal = 0; + for (ENetPeer& peer : m_peers) + { + if (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) + continue; + + dataTotal += peer.m_outgoingDataTotal; + } + } + + UInt32 peersRemaining = m_connectedPeers; + UInt32 bandwidthLimit = ~0; + UInt32 throttle = ~0; + bool needsAdjustment = m_bandwidthLimitedPeers > 0; + + while (peersRemaining > 0 && needsAdjustment) + { + needsAdjustment = false; + + if (dataTotal <= bandwidth) + throttle = ENetConstants::ENetPeer_PacketThrottleScale; + else + throttle = (bandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / dataTotal; + + for (ENetPeer& peer : m_peers) + { + if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || + peer.m_incomingBandwidth == 0 || peer.m_outgoingBandwidthThrottleEpoch == currentTime) + continue; + + UInt32 peerBandwidth = (peer.m_incomingBandwidth * elapsedTime) / 1000; + if ((throttle * peer.m_outgoingDataTotal) / ENetConstants::ENetPeer_PacketThrottleScale <= peerBandwidth) + continue; + + peer.m_packetThrottleLimit = (peerBandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / peer.m_outgoingDataTotal; + + if (peer.m_packetThrottleLimit == 0) + peer.m_packetThrottleLimit = 1; + + if (peer.m_packetThrottle > peer.m_packetThrottleLimit) + peer.m_packetThrottle = peer.m_packetThrottleLimit; + + peer.m_outgoingBandwidthThrottleEpoch = currentTime; + + peer.m_incomingDataTotal = 0; + peer.m_outgoingDataTotal = 0; + + needsAdjustment = true; + --peersRemaining; + bandwidth -= peerBandwidth; + dataTotal -= peerBandwidth; + } + } + + if (peersRemaining > 0) + { + if (dataTotal <= bandwidth) + throttle = ENetConstants::ENetPeer_PacketThrottleScale; + else + throttle = (bandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / dataTotal; + + for (ENetPeer& peer : m_peers) + { + if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || + peer.m_outgoingBandwidthThrottleEpoch == currentTime) + continue; + + peer.m_packetThrottleLimit = throttle; + + if (peer.m_packetThrottle > peer.m_packetThrottleLimit) + peer.m_packetThrottle = peer.m_packetThrottleLimit; + + peer.m_incomingDataTotal = 0; + peer.m_outgoingDataTotal = 0; + } + } + + if (m_recalculateBandwidthLimits) + { + m_recalculateBandwidthLimits = false; + + peersRemaining = m_connectedPeers; + bandwidth = m_incomingBandwidth; + needsAdjustment = true; + + if (bandwidth == 0) + bandwidthLimit = 0; + else + { + while (peersRemaining > 0 && needsAdjustment) + { + needsAdjustment = false; + bandwidthLimit = bandwidth / peersRemaining; + + for (ENetPeer& peer : m_peers) + { + if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || + peer.m_incomingBandwidthThrottleEpoch == currentTime) + continue; + + if (peer.m_outgoingBandwidth > 0 && peer.m_outgoingBandwidth >= bandwidthLimit) + continue; + + peer.m_incomingBandwidthThrottleEpoch = currentTime; + + needsAdjustment = true; + --peersRemaining; + bandwidth -= peer.m_outgoingBandwidth; + } + } + } + + for (ENetPeer& peer : m_peers) + { + if (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) + continue; + + ENetProtocol command; + command.header.command = ENetProtocolCommand_BandwidthLimit | ENetProtocolFlag_Acknowledge; + command.header.channelID = 0xFF; + command.bandwidthLimit.outgoingBandwidth = HostToNet(m_outgoingBandwidth); + + if (peer.m_incomingBandwidthThrottleEpoch == currentTime) + command.bandwidthLimit.incomingBandwidth = HostToNet(peer.m_outgoingBandwidth); + else + command.bandwidthLimit.incomingBandwidth = HostToNet(bandwidthLimit); + + peer.QueueOutgoingCommand(command, nullptr, 0, 0); + } + } + } + + bool ENetHost::Initialize() + { + std::random_device device; + s_randomGenerator.seed(device()); + s_randomGenerator64.seed(device()); + + return true; + } + + void ENetHost::Uninitialize() + { + } + + std::mt19937 ENetHost::s_randomGenerator; + std::mt19937_64 ENetHost::s_randomGenerator64; +} \ No newline at end of file diff --git a/src/Nazara/Network/ENetPacket.cpp b/src/Nazara/Network/ENetPacket.cpp new file mode 100644 index 000000000..ec2bc4ab7 --- /dev/null +++ b/src/Nazara/Network/ENetPacket.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +namespace Nz +{ + /// Temporary + void ENetPacketRef::Reset(ENetPacket* packet = nullptr) + { + if (m_packet) + { + if (--m_packet->referenceCount == 0) + { + m_packet->owner->Delete(m_packet); + return; + } + } + + m_packet = packet; + if (m_packet) + m_packet->referenceCount++; + } +} \ No newline at end of file diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp new file mode 100644 index 000000000..9e5471c21 --- /dev/null +++ b/src/Nazara/Network/ENetPeer.cpp @@ -0,0 +1,885 @@ +#include +#include +#include +#include +#include + +namespace Nz +{ + /// Temporary + template + T HostToNet(T value) + { + #ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); + #else + return value; + #endif + } + + /// Temporary + template + T NetToHost(T value) + { + #ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); + #else + return value; + #endif + } + + namespace + { + static std::size_t commandSizes[ENetProtocolCommand_Count] = + { + 0, + sizeof(ENetProtocolAcknowledge), + sizeof(ENetProtocolConnect), + sizeof(ENetProtocolVerifyConnect), + sizeof(ENetProtocolDisconnect), + sizeof(ENetProtocolPing), + sizeof(ENetProtocolSendReliable), + sizeof(ENetProtocolSendUnreliable), + sizeof(ENetProtocolSendFragment), + sizeof(ENetProtocolSendUnsequenced), + sizeof(ENetProtocolBandwidthLimit), + sizeof(ENetProtocolThrottleConfigure), + sizeof(ENetProtocolSendFragment) + }; + + std::size_t enet_protocol_command_size(UInt8 commandNumber) + { + return commandSizes[commandNumber & ENetProtocolCommand_Mask]; + } + } + + ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : + m_packetPool(sizeof(ENetPacket)), + m_host(host), + m_incomingPeerID(peerId), + m_incomingSessionID(0xFF), + m_outgoingSessionID(0xFF) + { + Reset(); + } + + void ENetPeer::Disconnect(UInt32 data) + { + if (m_state == ENetPeerState::Disconnecting || + m_state == ENetPeerState::Disconnected || + m_state == ENetPeerState::AcknowledgingDisconnect || + m_state == ENetPeerState::Zombie) + return; + + ResetQueues(); + + ENetProtocol command; + command.header.command = ENetProtocolCommand_Disconnect; + command.header.channelID = 0xFF; + command.disconnect.data = HostToNet(data); + + if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + command.header.command |= ENetProtocolFlag_Acknowledge; + else + command.header.command |= ENetProtocolFlag_Unsequenced; + + QueueOutgoingCommand(command, nullptr, 0, 0); + + if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + { + OnDisconnect(); + + m_state = ENetPeerState::Disconnecting; + } + else + { + m_host->Flush(); + + Reset(); + } + } + + void ENetPeer::DisconnectLater(UInt32 data) + { + if ((m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) && + !m_outgoingReliableCommands.empty() && + !m_outgoingUnreliableCommands.empty() && + !m_sentReliableCommands.empty()) + { + m_state = ENetPeerState::DisconnectLater; + m_eventData = data; + } + else + Disconnect(data); + } + + void ENetPeer::DisconnectNow(UInt32 data) + { + if (m_state == ENetPeerState::Disconnected) + return; + + if (m_state != ENetPeerState::Zombie && m_state != ENetPeerState::Disconnecting) + { + ResetQueues(); + + ENetProtocol command; + command.header.command = ENetProtocolCommand_Disconnect | ENetProtocolFlag_Unsequenced; + command.header.channelID = 0xFF; + command.disconnect.data = HostToNet(data); + + QueueOutgoingCommand(command, nullptr, 0, 0); + + m_host->Flush(); + } + + Reset(); + } + + void ENetPeer::Ping() + { + if (m_state != ENetPeerState::Connected) + return; + + ENetProtocol command; + command.header.command = ENetProtocolCommand_Ping | ENetProtocolFlag_Acknowledge; + command.header.channelID = 0xFF; + + QueueOutgoingCommand(command, nullptr, 0, 0); + } + + bool ENetPeer::Receive(ENetPacketRef* packet, UInt8* channelId) + { + if (m_dispatchedCommands.empty()) + return false; + + IncomingCommmand& incomingCommand = m_dispatchedCommands.front(); + + m_totalWaitingData -= incomingCommand.packet->data.GetSize(); + + if (packet) + *packet = std::move(incomingCommand.packet); + + if (channelId) + *channelId = incomingCommand.command.header.channelID; + + m_dispatchedCommands.pop_front(); + + return true; + } + + void ENetPeer::Reset() + { + OnDisconnect(); + + m_outgoingPeerID = ENetConstants::ENetProtocol_MaximumPeerId; + m_connectID = 0; + + m_state = ENetPeerState::Disconnected; + + m_incomingBandwidth = 0; + m_outgoingBandwidth = 0; + m_incomingBandwidthThrottleEpoch = 0; + m_outgoingBandwidthThrottleEpoch = 0; + m_incomingDataTotal = 0; + m_outgoingDataTotal = 0; + m_lastSendTime = 0; + m_lastReceiveTime = 0; + m_nextTimeout = 0; + m_earliestTimeout = 0; + m_packetLossEpoch = 0; + m_packetsSent = 0; + m_packetsLost = 0; + m_packetLoss = 0; + m_packetLossVariance = 0; + m_packetThrottle = ENetConstants::ENetProtocol_MaximumWindowSize; + m_packetThrottleLimit = ENetConstants::ENetPeer_PacketThrottleScale; + m_packetThrottleCounter = 0; + m_packetThrottleEpoch = 0; + m_packetThrottleAcceleration = ENetConstants::ENetPeer_PacketThrottleAcceleration; + m_packetThrottleDeceleration = ENetConstants::ENetPeer_PacketThrottleDeceleration; + m_packetThrottleInterval = ENetConstants::ENetPeer_PacketThrottleInterval; + m_pingInterval = ENetConstants::ENetPeer_PingInterval; + m_timeoutLimit = ENetConstants::ENetPeer_TimeoutLimit; + m_timeoutMinimum = ENetConstants::ENetPeer_TimeoutMinimum; + m_timeoutMaximum = ENetConstants::ENetPeer_TimeoutMaximum; + m_lastRoundTripTime = ENetConstants::ENetPeer_DefaultRoundTripTime; + m_lowestRoundTripTime = ENetConstants::ENetPeer_DefaultRoundTripTime; + m_lastRoundTripTimeVariance = 0; + m_highestRoundTripTimeVariance = 0; + m_roundTripTime = ENetConstants::ENetPeer_DefaultRoundTripTime; + m_roundTripTimeVariance = 0; + m_mtu = m_host->m_mtu; + m_reliableDataInTransit = 0; + m_outgoingReliableSequenceNumber = 0; + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + m_incomingUnsequencedGroup = 0; + m_outgoingUnsequencedGroup = 0; + m_eventData = 0; + m_totalWaitingData = 0; + + std::memset(m_unsequencedWindow, 0, sizeof(m_unsequencedWindow)); + + ResetQueues(); + } + + bool ENetPeer::Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) + { + ENetPacket* enetPacket = m_packetPool.New(); + enetPacket->flags = flags; + enetPacket->data = std::move(packet); + enetPacket->owner = &m_packetPool; + + return Send(channelId, enetPacket); + } + + bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef) + { + if (m_state != ENetPeerState::Connected || channelId >= m_channels.size() || packetRef->data.GetSize() > m_host->m_maximumPacketSize) + return false; + + Channel& channel = m_channels[channelId]; + + std::size_t fragmentLength = m_mtu - sizeof(ENetProtocolHeader) - sizeof(ENetProtocolSendFragment); + //if (m_host->m_checksum != nullptr) + // fragmentLength -= sizeof(UInt32); + + UInt32 packetSize = static_cast(packetRef->data.GetSize()); + if (packetSize > fragmentLength) + { + UInt32 fragmentCount = (packetSize + fragmentLength - 1) / fragmentLength; + UInt32 fragmentNumber; + UInt32 fragmentOffset; + + UInt8 commandNumber; + UInt16 startSequenceNumber; + + if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount) + return false; + + if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_UnreliableFragment)) == ENetPacketFlag_UnreliableFragment && + channel.outgoingUnreliableSequenceNumber < 0xFFFF) + { + commandNumber = ENetProtocolCommand_SendUnreliable; + startSequenceNumber = HostToNet(channel.outgoingUnreliableSequenceNumber + 1); + } + else + { + commandNumber = ENetProtocolCommand_SendFragment | ENetProtocolFlag_Acknowledge; + startSequenceNumber = HostToNet(channel.outgoingReliableSequenceNumber + 1); + } + + for (fragmentNumber = 0, + fragmentOffset = 0; + fragmentOffset < packetSize; + ++fragmentNumber, + fragmentOffset += fragmentLength) + { + if (packetSize - fragmentOffset < fragmentLength) + fragmentLength = packetSize - fragmentOffset; + + OutgoingCommand outgoingCommand; + outgoingCommand.fragmentOffset = fragmentOffset; + outgoingCommand.fragmentLength = fragmentLength; + outgoingCommand.packet = packetRef; + outgoingCommand.command.header.command = commandNumber; + outgoingCommand.command.header.channelID = channelId; + outgoingCommand.command.sendFragment.startSequenceNumber = startSequenceNumber; + outgoingCommand.command.sendFragment.dataLength = HostToNet(fragmentLength); + outgoingCommand.command.sendFragment.fragmentCount = HostToNet(fragmentCount); + outgoingCommand.command.sendFragment.fragmentNumber = HostToNet(fragmentNumber); + outgoingCommand.command.sendFragment.totalLength = HostToNet(packetSize); + outgoingCommand.command.sendFragment.fragmentOffset = HostToNet(fragmentOffset); + + SetupOutgoingCommand(outgoingCommand); + } + + return true; + } + + ENetProtocol command; + command.header.channelID = channelId; + + if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_Unsequenced)) == ENetPacketFlag_Unsequenced) + command.header.command = ENetProtocolCommand_SendUnsequenced | ENetProtocolFlag_Unsequenced; + else if (packetRef->flags & ENetPacketFlag_Reliable || channel.outgoingUnreliableSequenceNumber >= 0xFFFF) + command.header.command = ENetProtocolCommand_SendReliable | ENetProtocolFlag_Acknowledge; + else + command.header.command = ENetProtocolCommand_SendUnreliable; + + QueueOutgoingCommand(command, packetRef, 0, packetSize); + + return true; + } + + void ENetPeer::ThrottleConfigure(UInt32 interval, UInt32 acceleration, UInt32 deceleration) + { + m_packetThrottleInterval = interval; + m_packetThrottleAcceleration = acceleration; + m_packetThrottleDeceleration = deceleration; + + ENetProtocol command; + command.header.command = ENetProtocolCommand_ThrottleConfigure | ENetProtocolFlag_Acknowledge; + command.header.channelID = 0xFF; + + command.throttleConfigure.packetThrottleInterval = HostToNet(interval); + command.throttleConfigure.packetThrottleAcceleration = HostToNet(acceleration); + command.throttleConfigure.packetThrottleDeceleration = HostToNet(deceleration); + + QueueOutgoingCommand(command, nullptr, 0, 0); + } + + void ENetPeer::InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand) + { + m_channels.resize(channelCount); + m_address = address; + + m_connectID = incomingCommand.connectID; + m_eventData = NetToHost(incomingCommand.data); + m_incomingBandwidth = NetToHost(incomingCommand.incomingBandwidth); + m_outgoingBandwidth = NetToHost(incomingCommand.outgoingBandwidth); + m_packetThrottleInterval = NetToHost(incomingCommand.packetThrottleInterval); + m_packetThrottleAcceleration = NetToHost(incomingCommand.packetThrottleAcceleration); + m_packetThrottleDeceleration = NetToHost(incomingCommand.packetThrottleDeceleration); + m_outgoingPeerID = NetToHost(incomingCommand.outgoingPeerID); + m_state = ENetPeerState::AcknowledgingConnect; + + UInt8 incomingSessionId, outgoingSessionId; + + incomingSessionId = incomingCommand.incomingSessionID == 0xFF ? m_outgoingSessionID : incomingCommand.incomingSessionID; + incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + if (incomingSessionId == m_outgoingSessionID) + incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + m_outgoingSessionID = incomingSessionId; + + outgoingSessionId = incomingCommand.outgoingSessionID == 0xFF ? m_incomingSessionID : incomingCommand.outgoingSessionID; + outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + if (outgoingSessionId == m_incomingSessionID) + outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + m_incomingSessionID = outgoingSessionId; + + m_mtu = Clamp(NetToHost(incomingCommand.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + + if (m_host->m_outgoingBandwidth == 0 && m_incomingBandwidth == 0) + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else if (m_host->m_outgoingBandwidth == 0 || m_incomingBandwidth == 0) + m_windowSize = (std::max(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + else + m_windowSize = (std::min(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + m_windowSize = Clamp(m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + void ENetPeer::InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize) + { + m_channels.resize(channelCount); + + m_address = address; + m_connectID = connectId; + m_state = ENetPeerState::Connecting; + m_windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + void ENetPeer::DispatchIncomingReliableCommands(Channel& channel) + { + auto currentCommand = channel.incomingReliableCommands.begin(); + for (; currentCommand != channel.incomingReliableCommands.end(); ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if (incomingCommand.fragmentsRemaining > 0 || incomingCommand.reliableSequenceNumber != (channel.incomingReliableSequenceNumber + 1)) + break; + + channel.incomingReliableSequenceNumber = incomingCommand.reliableSequenceNumber; + + if (!incomingCommand.fragments.empty()) + channel.incomingReliableSequenceNumber += incomingCommand.fragments.size() - 1; + } + + if (currentCommand == channel.incomingReliableCommands.begin()) + return; + + channel.incomingUnreliableSequenceNumber = 0; + + m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, channel.incomingReliableCommands.begin(), currentCommand); + + m_host->AddToDispatchQueue(this); + + if (!channel.incomingUnreliableCommands.empty()) + DispatchIncomingUnreliableCommands(channel); + } + + void ENetPeer::DispatchIncomingUnreliableCommands(Channel& channel) + { + std::list::iterator currentCommand; + std::list::iterator droppedCommand; + std::list::iterator startCommand; + + for (droppedCommand = startCommand = currentCommand = channel.incomingUnreliableCommands.begin(); + currentCommand != channel.incomingUnreliableCommands.end(); + ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_SendUnsequenced) + continue; + + if (incomingCommand.reliableSequenceNumber == channel.incomingReliableSequenceNumber) + { + if (incomingCommand.fragmentsRemaining <= 0) + { + channel.incomingUnreliableSequenceNumber = incomingCommand.unreliableSequenceNumber; + continue; + } + + if (startCommand != currentCommand) + { + m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand); + + m_host->AddToDispatchQueue(this); + + droppedCommand = currentCommand; + } + else if (droppedCommand != currentCommand) + { + droppedCommand = currentCommand; + --droppedCommand; + } + } + else + { + UInt16 reliableWindow = incomingCommand.reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow >= currentWindow && reliableWindow < currentWindow + ENetConstants::ENetPeer_ReliableWindowSize - 1) + break; + + droppedCommand = currentCommand; + ++droppedCommand; + + if (startCommand != currentCommand) + { + m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand); + + m_host->AddToDispatchQueue(this); + } + } + + startCommand = currentCommand; + ++startCommand; + } + + if (startCommand != currentCommand) + { + m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand); + + m_host->AddToDispatchQueue(this); + + droppedCommand = currentCommand; + } + + channel.incomingUnreliableCommands.erase(channel.incomingUnreliableCommands.begin(), droppedCommand); + } + + void ENetPeer::OnConnect() + { + if (m_state != ENetPeerState::Connected && m_state != ENetPeerState::DisconnectLater) + { + if (m_incomingBandwidth != 0) + ++m_host->m_bandwidthLimitedPeers; + + ++m_host->m_connectedPeers; + } + } + + void ENetPeer::OnDisconnect() + { + if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + { + if (m_incomingBandwidth != 0) + --m_host->m_bandwidthLimitedPeers; + + --m_host->m_connectedPeers; + } + } + + ENetProtocolCommand ENetPeer::RemoveSentReliableCommands(UInt16 reliableSequenceNumber, UInt8 channelId) + { + std::list* commandList = nullptr; + + bool found = true; + auto currentCommand = m_sentReliableCommands.begin(); + commandList = &m_sentReliableCommands; + for (; currentCommand != m_sentReliableCommands.end(); ++currentCommand) + { + found = true; + + if (currentCommand->reliableSequenceNumber == reliableSequenceNumber && + currentCommand->command.header.channelID == channelId) + break; + } + + bool wasSent = true; + if (currentCommand == m_sentReliableCommands.end()) + { + currentCommand = m_outgoingReliableCommands.begin(); + commandList = &m_sentReliableCommands; + for (; currentCommand != m_outgoingReliableCommands.end(); ++currentCommand) + { + found = true; + + if (currentCommand->sendAttempts < 1) + return ENetProtocolCommand_None; + + if (currentCommand->reliableSequenceNumber == reliableSequenceNumber && + currentCommand->command.header.channelID == channelId) + break; + } + + if (currentCommand == m_outgoingReliableCommands.end()) + return ENetProtocolCommand_None; + + wasSent = false; + } + + if (!found) //< Really useful? + return ENetProtocolCommand_None; + + if (channelId < m_channels.size()) + { + Channel& channel = m_channels[channelId]; + + UInt16 reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + if (channel.reliableWindows[reliableWindow] > 0) + { + --channel.reliableWindows[reliableWindow]; + if (!channel.reliableWindows[reliableWindow]) + channel.usedReliableWindows &= ~(1 << reliableWindow); + } + } + + ENetProtocolCommand commandNumber = static_cast(currentCommand->command.header.command & ENetProtocolCommand_Mask); + + if (currentCommand->packet && wasSent) + m_reliableDataInTransit -= currentCommand->fragmentLength; + + commandList->erase(currentCommand); + + if (m_sentReliableCommands.empty()) + return commandNumber; + + currentCommand = m_sentReliableCommands.begin(); + m_nextTimeout = currentCommand->sentTime + currentCommand->roundTripTimeout; + + return commandNumber; + } + + void ENetPeer::RemoveSentUnreliableCommands() + { + m_sentUnreliableCommands.clear(); + } + + void ENetPeer::ResetQueues() + { + m_host->RemoveFromDispatchQueue(this); + + m_acknowledgements.clear(); + m_dispatchedCommands.clear(); + m_outgoingReliableCommands.clear(); + m_outgoingUnreliableCommands.clear(); + m_sentReliableCommands.clear(); + m_sentUnreliableCommands.clear(); + + m_channels.clear(); + } + + bool ENetPeer::QueueAcknowledgement(ENetProtocol& command, UInt16 sentTime) + { + if (command.header.channelID < m_channels.size()) + { + Channel& channel = m_channels[command.header.channelID]; + + UInt16 reliableWindow = command.header.reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (command.header.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1 && reliableWindow <= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows) + return false; + } + + Acknowledgement acknowledgment; + acknowledgment.command = command; + acknowledgment.sentTime = sentTime; + + m_outgoingDataTotal += sizeof(Acknowledgement); + + m_acknowledgements.emplace_back(acknowledgment); + + return true; + } + + ENetPeer::IncomingCommmand* ENetPeer::QueueIncomingCommand(ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount) + { + static IncomingCommmand dummyCommand; + + UInt32 reliableSequenceNumber = 0; + UInt32 unreliableSequenceNumber = 0; + UInt16 reliableWindow; + UInt16 currentWindow; + + auto discardCommand = [&]() -> IncomingCommmand* + { + if (fragmentCount > 0) + return nullptr; //< Error + + return &dummyCommand; + }; + + if (m_state == ENetPeerState::DisconnectLater) + return discardCommand(); + + Channel& channel = m_channels[command.header.channelID]; + + if ((command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnsequenced) + { + reliableSequenceNumber = command.header.reliableSequenceNumber; + reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (reliableSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) + return discardCommand(); + } + + std::list* commandList = nullptr; + std::list::reverse_iterator currentCommand; + + switch (command.header.command & ENetProtocolCommand_Mask) + { + case ENetProtocolCommand_SendFragment: + case ENetProtocolCommand_SendReliable: + { + if (reliableSequenceNumber == channel.incomingReliableSequenceNumber) + return discardCommand(); + + commandList = &channel.incomingReliableCommands; + + for (currentCommand = channel.incomingReliableCommands.rbegin(); currentCommand != channel.incomingReliableCommands.rend(); ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if (reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber <= reliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < reliableSequenceNumber) + break; + + return discardCommand(); + } + } + break; + } + + case ENetProtocolCommand_SendUnreliable: + case ENetProtocolCommand_SendUnreliableFragment: + { + unreliableSequenceNumber = NetToHost(command.sendUnreliable.unreliableSequenceNumber); + + if (reliableSequenceNumber == channel.incomingReliableSequenceNumber && unreliableSequenceNumber <= channel.incomingUnreliableSequenceNumber) + return discardCommand(); + + commandList = &channel.incomingUnreliableCommands; + + for (currentCommand = channel.incomingUnreliableCommands.rbegin(); currentCommand != channel.incomingUnreliableCommands.rend(); ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if ((command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_SendUnsequenced) //< wtf + continue; + + if (reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber < reliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber > reliableSequenceNumber) + continue; + + if (incomingCommand.unreliableSequenceNumber <= unreliableSequenceNumber) + { + if (incomingCommand.unreliableSequenceNumber < unreliableSequenceNumber) + break; + + return discardCommand(); + } + } + break; + } + + case ENetProtocolCommand_SendUnsequenced: + { + commandList = &channel.incomingUnreliableCommands; + + currentCommand = channel.incomingUnreliableCommands.rend(); + break; + } + + default: + return discardCommand(); + } + + if (m_totalWaitingData >= m_host->m_maximumWaitingData) + return nullptr; + + ENetPacket* packet = m_packetPool.New(); + packet->flags = flags; + packet->data.Reset(0, data, dataLength); + packet->owner = &m_packetPool; + + IncomingCommmand incomingCommand; + incomingCommand.reliableSequenceNumber = command.header.reliableSequenceNumber; + incomingCommand.unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; + incomingCommand.command = command; + incomingCommand.packet = packet; + incomingCommand.fragments.resize(fragmentCount, 0); + incomingCommand.fragmentsRemaining = fragmentCount; + + auto it = commandList->insert(currentCommand.base(), incomingCommand); + + switch (command.header.command & ENetProtocolCommand_Mask) + { + case ENetProtocolCommand_SendFragment: + case ENetProtocolCommand_SendReliable: + DispatchIncomingReliableCommands(channel); + break; + + default: + DispatchIncomingUnreliableCommands(channel); + break; + } + + return &(*it); + } + + void ENetPeer::QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length) + { + OutgoingCommand outgoingCommand; + outgoingCommand.command = command; + outgoingCommand.fragmentLength = length; + outgoingCommand.fragmentOffset = length; + outgoingCommand.packet = packet; + + SetupOutgoingCommand(outgoingCommand); + } + + void ENetPeer::SetupOutgoingCommand(OutgoingCommand& outgoingCommand) + { + m_outgoingDataTotal += enet_protocol_command_size(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength; + + if (outgoingCommand.command.header.channelID == 0xFF) + { + ++m_outgoingReliableSequenceNumber; + + outgoingCommand.reliableSequenceNumber = m_outgoingReliableSequenceNumber; + outgoingCommand.unreliableSequenceNumber = 0; + } + else + { + Channel* channel = &m_channels[outgoingCommand.command.header.channelID]; + if (outgoingCommand.command.header.command & ENetProtocolFlag_Acknowledge) + { + ++channel->outgoingReliableSequenceNumber; + channel->outgoingUnreliableSequenceNumber = 0; + + outgoingCommand.reliableSequenceNumber = channel->outgoingReliableSequenceNumber; + outgoingCommand.unreliableSequenceNumber = 0; + } + else if (outgoingCommand.command.header.command & ENetProtocolFlag_Unsequenced) + { + ++m_outgoingUnsequencedGroup; + + outgoingCommand.reliableSequenceNumber = 0; + outgoingCommand.unreliableSequenceNumber = 0; + } + else + { + if (outgoingCommand.fragmentOffset == 0) + ++channel->outgoingUnreliableSequenceNumber; + + outgoingCommand.reliableSequenceNumber = channel->outgoingReliableSequenceNumber; + outgoingCommand.unreliableSequenceNumber = channel->outgoingUnreliableSequenceNumber; + } + } + + outgoingCommand.sendAttempts = 0; + outgoingCommand.sentTime = 0; + outgoingCommand.roundTripTimeout = 0; + outgoingCommand.roundTripTimeoutLimit = 0; + outgoingCommand.command.header.reliableSequenceNumber = HostToNet(outgoingCommand.reliableSequenceNumber); + + switch (outgoingCommand.command.header.command & ENetProtocolCommand_Mask) + { + case ENetProtocolCommand_SendUnreliable: + outgoingCommand.command.sendUnreliable.unreliableSequenceNumber = HostToNet(outgoingCommand.unreliableSequenceNumber); + break; + + case ENetProtocolCommand_SendUnsequenced: + outgoingCommand.command.sendUnsequenced.unsequencedGroup = HostToNet(m_outgoingUnsequencedGroup); + break; + + default: + break; + } + + if (outgoingCommand.command.header.command & ENetProtocolCommand_Acknowledge) + m_outgoingReliableCommands.emplace_back(outgoingCommand); + else + m_outgoingUnreliableCommands.emplace_back(outgoingCommand); + } + + int ENetPeer::Throttle(UInt32 rtt) + { + if (m_lastRoundTripTime <= m_lastRoundTripTimeVariance) + m_packetThrottle = m_packetThrottleLimit; + else + { + if (rtt < m_lastRoundTripTime) + { + m_packetThrottle = std::max(m_packetThrottle + m_packetThrottleAcceleration, m_packetThrottleLimit); + return 1; + } + else if (rtt > m_lastRoundTripTime + 2 * m_lastRoundTripTimeVariance) + { + if (m_packetThrottle > m_packetThrottleDeceleration) + m_packetThrottle -= m_packetThrottleDeceleration; + else + m_packetThrottle = 0; + + return -1; + } + } + + return 0; + } +} \ No newline at end of file diff --git a/src/Nazara/Network/ENetSocket.cpp b/src/Nazara/Network/ENetSocket.cpp new file mode 100644 index 000000000..e86313fb4 --- /dev/null +++ b/src/Nazara/Network/ENetSocket.cpp @@ -0,0 +1,642 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz +{ + /*! + * \ingroup network + * \class Nz::ENetConnection + * \brief Network class that represents a reliable UDP connection, based on ENet library + */ + + /*! + * \brief Constructs a RUdpConnection object by default + */ + + ENetSocket::ENetSocket() : + m_bandwidthThrottleEpoch(0), + m_mtu(ENetConstants::DefaultMTU), + m_isSimulationEnabled(false), + m_shouldAcceptConnections(true) + { + m_randomSeed = *reinterpret_cast(this); + m_randomSeed += s_randomGenerator(); + m_randomSeed = (m_randomSeed << 16) | (m_randomSeed >> 16); + + } + + /*! + * \brief Connects to the IpAddress + * \return true + * + * \param remoteAddress Address to connect to + * + * \remark Produces a NazaraAssert if socket is not bound + * \remark Produces a NazaraAssert if remote is invalid + * \remark Produces a NazaraAssert if port is not specified + */ + + bool RUdpConnection::Connect(const IpAddress& remoteAddress) + { + NazaraAssert(m_socket.GetState() == SocketState_Bound, "Socket must be bound first"); + NazaraAssert(remoteAddress.IsValid(), "Invalid remote address"); + NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port"); + + PeerData& client = RegisterPeer(remoteAddress, PeerState_Connecting); + client.stateData1 = s_randomGenerator(); + + NetPacket connectionRequestPacket(NetCode_RequestConnection); + connectionRequestPacket << client.stateData1; + + EnqueuePacket(client, PacketPriority_Immediate, PacketReliability_Reliable, connectionRequestPacket); + return true; + } + + /*! + * \brief Connects to the hostname + * \return true If successful + * + * \param hostName Hostname of the remote + * \param protocol Net protocol to use + * \param service Specify the protocol used + * \param error Optional argument to get the error + */ + + bool RUdpConnection::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error) + { + std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); + if (results.empty()) + { + m_lastError = SocketError_ResolveError; + return false; + } + + IpAddress hostnameAddress; + for (const HostnameInfo& result : results) + { + if (!result.address) + continue; + + if (result.socketType != SocketType_UDP) + continue; + + hostnameAddress = result.address; + break; //< Take first valid address + } + + return Connect(hostnameAddress); + } + + /*! + * \brief Listens to a socket + * \return true If successfully bound + * + * \param remoteAddress Address to listen to + */ + + bool RUdpConnection::Listen(const IpAddress& address) + { + if (!InitSocket(address.GetProtocol())) + return false; + + return m_socket.Bind(address) == SocketState_Bound; + } + + /*! + * \brief Polls the message + * \return true If there is a message + * + * \param message Message to poll + * + * \remark Produces a NazaraAssert if message is invalid + */ + + bool RUdpConnection::PollMessage(RUdpMessage* message) + { + NazaraAssert(message, "Invalid message"); + + if (m_receivedMessages.empty()) + return false; + + *message = std::move(m_receivedMessages.front()); + m_receivedMessages.pop(); + return true; + } + + /*! + * \brief Sends the packet to a peer + * \return true If peer exists (false may result from disconnected client) + * + * \param peerIp IpAddress of the peer + * \param priority Priority of the packet + * \param reliability Policy of reliability of the packet + * \param packet Packet to send + */ + + bool RUdpConnection::Send(const IpAddress& peerIp, PacketPriority priority, PacketReliability reliability, const NetPacket& packet) + { + auto it = m_peerByIP.find(peerIp); + if (it == m_peerByIP.end()) + return false; /// Silently fail (probably a disconnected client) + + EnqueuePacket(m_peers[it->second], priority, reliability, packet); + return true; + } + + /*! + * \brief Updates the reliable connection + */ + + void RUdpConnection::Update() + { + m_currentTime = m_clock.GetMicroseconds(); + + NetPacket receivedPacket; + IpAddress senderIp; + while (m_socket.ReceivePacket(&receivedPacket, &senderIp)) + OnPacketReceived(senderIp, std::move(receivedPacket)); + + //for (unsigned int i = m_activeClients.FindFirst(); i != m_activeClients.npos; i = m_activeClients.FindNext(i)) + //{ + // PeerData& clientData = m_peers[i]; + + CallOnExit resetIterator([this] () { m_peerIterator = m_peers.size(); }); + + for (m_peerIterator = 0; m_peerIterator < m_peers.size(); ++m_peerIterator) + { + PeerData& peer = m_peers[m_peerIterator]; + + UInt32 timeSinceLastPacket = static_cast(m_currentTime - peer.lastPacketTime); + if (timeSinceLastPacket > m_timeBeforeTimeOut) + { + DisconnectPeer(peer.index); + continue; + } + else if (timeSinceLastPacket > m_timeBeforePing) + { + if (m_currentTime - peer.lastPingTime > m_pingInterval) + { + NetPacket pingPacket(NetCode_Ping); + EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Unreliable, pingPacket); + } + } + + if (peer.state == PeerState_WillAck && m_currentTime - peer.stateData1 > m_forceAckSendTime) + { + NetPacket acknowledgePacket(NetCode_Acknowledge); + EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Reliable, acknowledgePacket); + } + + for (unsigned int priority = PacketPriority_Highest; priority <= PacketPriority_Lowest; ++priority) + { + std::vector& pendingPackets = peer.pendingPackets[priority]; + for (PendingPacket& packetData : pendingPackets) + SendPacket(peer, std::move(packetData)); + + pendingPackets.clear(); + } + + auto it = peer.pendingAckQueue.begin(); + while (it != peer.pendingAckQueue.end()) + { + if (m_currentTime - it->timeSent > 2 * peer.roundTripTime) + { + OnPacketLost(peer, std::move(*it)); + it = peer.pendingAckQueue.erase(it); + } + else + ++it; + } + } + //m_activeClients.Reset(); + } + + /*! + * \brief Disconnects a peer + * + * \param peerIndex Index of the peer + * + * \remark Produces a NazaraNotice + */ + + void RUdpConnection::DisconnectPeer(std::size_t peerIndex) + { + PeerData& peer = m_peers[peerIndex]; + NazaraNotice(m_socket.GetBoundAddress().ToString() + ": " + peer.address.ToString() + " has been disconnected due to time-out"); + + OnPeerDisconnected(this, peer.address); + + // Remove from IP lookup table + m_peerByIP.erase(peer.address); + + // Can we safely "remove" this slot? + if (m_peerIterator >= m_peers.size() - 1 || peerIndex > m_peerIterator) + { + // Yes we can + PeerData& newSlot = m_peers[peerIndex]; + newSlot = std::move(m_peers.back()); + newSlot.index = peerIndex; //< Update the moved slot index before resizing (in case it's the last one) + } + else + { + // Nope, let's be tricky + PeerData& current = m_peers[m_peerIterator]; + PeerData& newSlot = m_peers[peerIndex]; + + newSlot = std::move(current); + newSlot.index = peerIndex; //< Update the moved slot index + + current = std::move(m_peers.back()); + current.index = m_peerIterator; //< Update the moved slot index + + --m_peerIterator; + } + + // Pop the last entry (from where we moved our slot) + m_peers.pop_back(); + } + + /*! + * \brief Enqueues a packet in the sending list + * + * \param peer Data relative to the peer + * \param priority Priority of the packet + * \param reliability Policy of reliability of the packet + * \param packet Packet to send + */ + + void RUdpConnection::EnqueuePacket(PeerData& peer, PacketPriority priority, PacketReliability reliability, const NetPacket& packet) + { + UInt16 protocolBegin = static_cast(m_protocol & 0xFFFF); + UInt16 protocolEnd = static_cast((m_protocol & 0xFFFF0000) >> 16); + + NetPacket data(packet.GetNetCode(), MessageHeader + packet.GetDataSize() + MessageFooter); + data << protocolBegin; + + data.GetStream()->SetCursorPos(NetPacket::HeaderSize + MessageHeader); + data.Write(packet.GetConstData() + NetPacket::HeaderSize, packet.GetDataSize()); + + data << protocolEnd; + EnqueuePacketInternal(peer, priority, reliability, std::move(data)); + } + + /*! + * \brief Enqueues internally a packet in the sending list + * + * \param peer Data relative to the peer + * \param priority Priority of the packet + * \param reliability Policy of reliability of the packet + * \param packet Packet to send + */ + + void RUdpConnection::EnqueuePacketInternal(PeerData& peer, PacketPriority priority, PacketReliability reliability, NetPacket&& data) + { + PendingPacket pendingPacket; + pendingPacket.data = std::move(data); + pendingPacket.priority = priority; + pendingPacket.reliability = reliability; + + peer.pendingPackets[priority].emplace_back(std::move(pendingPacket)); + m_activeClients.UnboundedSet(peer.index); + } + + /*! + * \brief Inits the internal socket + * \return true If successful + * + * \param protocol Net protocol to use + */ + + bool ENetSocket::InitSocket(NetProtocol protocol) + { + CallOnExit updateLastError([this] + { + m_lastError = m_socket.GetLastError(); + }); + + if (!m_socket.Create(protocol)) + return false; + + m_socket.EnableBlocking(false); + m_socket.SetReceiveBufferSize(ENetConstants::ReceiveBufferSize); + m_socket.SetSendBufferSize(ENetConstants::SendBufferSize); + + return true; + } + + /*! + * \brief Processes the acks + * + * \param peer Data relative to the peer + * \param lastAck Last index of the ack + * \param ackBits Bits for acking + */ + + void RUdpConnection::ProcessAcks(PeerData& peer, SequenceIndex lastAck, UInt32 ackBits) + { + auto it = peer.pendingAckQueue.begin(); + while (it != peer.pendingAckQueue.end()) + { + bool acked = false; + if (lastAck == it->sequenceId) + acked = true; + else if (!IsAckMoreRecent(it->sequenceId, lastAck)) + { + unsigned int difference = ComputeSequenceDifference(lastAck, it->sequenceId); + if (difference <= 32) + acked = (ackBits >> (difference - 1)) & 1; + } + + if (acked) + { + it = peer.pendingAckQueue.erase(it); + } + else + ++it; + } + } + + /*! + * \brief Registers a peer + * \return Data relative to the peer + * + * \param address Address of the peer + * \param state Status of the peer + */ + + RUdpConnection::PeerData& RUdpConnection::RegisterPeer(const IpAddress& address, PeerState state) + { + PeerData data; + data.address = address; + data.localSequence = 0; + data.remoteSequence = 0; + data.index = m_peers.size(); + data.lastPacketTime = m_currentTime; + data.lastPingTime = m_currentTime; + data.roundTripTime = 1'000'000; ///< Okay that's quite a lot + data.state = state; + + m_activeClients.UnboundedSet(data.index); + m_peerByIP[address] = data.index; + + m_peers.emplace_back(std::move(data)); + return m_peers.back(); + } + + /*! + * \brief Operation to do when client requests a connection + * + * \param address Address of the peer + * \param sequenceId Sequence index for the ack + * \param token Token for connection + */ + + void RUdpConnection::OnClientRequestingConnection(const IpAddress& address, SequenceIndex sequenceId, UInt64 token) + { + // Call hook to check if client should be accepted or not + OnPeerConnection(this, address); + + PeerData& client = RegisterPeer(address, PeerState_Aknowledged); + client.remoteSequence = sequenceId; + + /// Acknowledge connection + NetPacket connectionAcceptedPacket(NetCode_AcknowledgeConnection); + //connectionAcceptedPacket << address; + connectionAcceptedPacket << ~token; + + EnqueuePacket(client, PacketPriority_Immediate, PacketReliability_Reliable, connectionAcceptedPacket); + } + + /*! + * \brief Operation to do when a packet is lost + * + * \param peer Data relative to the peer + * \param packet Pending packet + */ + + void RUdpConnection::OnPacketLost(PeerData& peer, PendingAckPacket&& packet) + { + //NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Lost packet " + String::Number(packet.sequenceId)); + + if (IsReliable(packet.reliability)) + EnqueuePacketInternal(peer, packet.priority, packet.reliability, std::move(packet.data)); + } + + /*! + * \brief Operation to do when receiving a packet + * + * \param peerIndex Index of the peer + * + * \remark Produces a NazaraNotice + */ + + void RUdpConnection::OnPacketReceived(const IpAddress& peerIp, NetPacket&& packet) + { + UInt16 protocolBegin; + UInt16 protocolEnd; + SequenceIndex sequenceId; + SequenceIndex lastAck; + UInt32 ackBits; + + packet.GetStream()->SetCursorPos(packet.GetSize() - MessageFooter); + packet >> protocolEnd; + + packet.GetStream()->SetCursorPos(NetPacket::HeaderSize); + packet >> protocolBegin; + + UInt32 protocolId = static_cast(protocolEnd) << 16 | protocolBegin; + if (protocolId != m_protocol) + return; ///< Ignore + + packet >> sequenceId >> lastAck >> ackBits; + + auto it = m_peerByIP.find(peerIp); + if (it == m_peerByIP.end()) + { + switch (packet.GetNetCode()) + { + case NetCode_RequestConnection: + { + UInt64 token; + packet >> token; + + NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_RequestConnection from " + peerIp.ToString() + ": " + String::Number(token)); + if (!m_shouldAcceptConnections) + return; //< Ignore + + OnClientRequestingConnection(peerIp, sequenceId, token); + break; + } + + default: + return; //< Ignore + } + } + else + { + PeerData& peer = m_peers[it->second]; + peer.lastPacketTime = m_currentTime; + + if (peer.receivedQueue.find(sequenceId) != peer.receivedQueue.end()) + return; //< Ignore + + if (m_isSimulationEnabled && m_packetLossProbability(s_randomGenerator)) + { + NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Lost packet " + String::Number(sequenceId) + " from " + peerIp.ToString() + " for simulation purpose"); + return; + } + + ///< Receiving a packet from an acknowledged client means the connection works in both ways + if (peer.state == PeerState_Aknowledged && packet.GetNetCode() != NetCode_RequestConnection) + { + peer.state = PeerState_Connected; + OnPeerAcknowledged(this, peerIp); + } + + if (IsAckMoreRecent(sequenceId, peer.remoteSequence)) + peer.remoteSequence = sequenceId; + + ProcessAcks(peer, lastAck, ackBits); + + peer.receivedQueue.insert(sequenceId); + + switch (packet.GetNetCode()) + { + case NetCode_Acknowledge: + return; //< Do not switch to will ack mode (to prevent infinite replies, just let's ping/pong do that) + + case NetCode_AcknowledgeConnection: + { + if (peer.state == PeerState_Connected) + break; + + IpAddress externalAddress; + UInt64 token; + packet /*>> externalAddress*/ >> token; + + NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_AcknowledgeConnection from " + peerIp.ToString() + ": " + String::Number(token)); + if (token == ~peer.stateData1) + { + peer.state = PeerState_Connected; + OnConnectedToPeer(this); + } + else + { + NazaraNotice("Received wrong token (" + String::Number(token) + " instead of " + String::Number(~peer.stateData1) + ") from client " + peer.address); + return; //< Ignore + } + + break; + } + + case NetCode_RequestConnection: + NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_RequestConnection from " + peerIp.ToString()); + return; //< Ignore + + case NetCode_Ping: + { + NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_Ping from " + peerIp.ToString()); + + NetPacket pongPacket(NetCode_Pong); + EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Unreliable, pongPacket); + break; + } + + case NetCode_Pong: + NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_Pong from " + peerIp.ToString()); + break; + + default: + { + NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received 0x" + String::Number(packet.GetNetCode(), 16) + " from " + peerIp.ToString()); + RUdpMessage receivedMessage; + receivedMessage.from = peerIp; + receivedMessage.data = std::move(packet); + + m_receivedMessages.emplace(std::move(receivedMessage)); + break; + } + } + + if (!HasPendingPackets(peer)) + { + peer.state = PeerState_WillAck; + peer.stateData1 = m_currentTime; + } + } + } + + /*! + * \brief Sends a packet to a peer + * + * \param peer Data relative to the peer + * \param packet Pending packet + */ + + void RUdpConnection::SendPacket(PeerData& peer, PendingPacket&& packet) + { + if (peer.state == PeerState_WillAck) + peer.state = PeerState_Connected; + + SequenceIndex remoteSequence = peer.remoteSequence; + + UInt32 previousAcks = 0; + for (SequenceIndex ack : peer.receivedQueue) + { + if (ack == remoteSequence) + continue; + + unsigned int difference = ComputeSequenceDifference(remoteSequence, ack); + if (difference <= 32U) + previousAcks |= (1U << (difference - 1)); + } + + SequenceIndex sequenceId = ++peer.localSequence; + + packet.data.GetStream()->SetCursorPos(NetPacket::HeaderSize + sizeof(UInt16)); ///< Protocol begin has already been filled + packet.data << sequenceId; + packet.data << remoteSequence; + packet.data << previousAcks; + + m_socket.SendPacket(peer.address, packet.data); + + PendingAckPacket pendingAckPacket; + pendingAckPacket.data = std::move(packet.data); + pendingAckPacket.priority = packet.priority; + pendingAckPacket.reliability = packet.reliability; + pendingAckPacket.sequenceId = sequenceId; + pendingAckPacket.timeSent = m_currentTime; + + peer.pendingAckQueue.emplace_back(std::move(pendingAckPacket)); + } + + /*! + * \brief Initializes the RUdpConnection class + * \return true + */ + + bool RUdpConnection::Initialize() + { + std::random_device device; + s_randomGenerator.seed(device()); + + return true; + } + + /*! + * \brief Uninitializes the RUdpConnection class + */ + + void RUdpConnection::Uninitialize() + { + } + + std::mt19937_64 RUdpConnection::s_randomGenerator; +} From 12b4073033d3ef2a360a7cf61484ec7242ea7572 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 26 Jan 2017 09:28:41 +0100 Subject: [PATCH 02/73] Progress --- include/Nazara/Network/ENetHost.hpp | 8 +- include/Nazara/Network/ENetPeer.hpp | 8 +- src/Nazara/Network/ENetHost.cpp | 443 ++++++++++++++++++++++++++-- src/Nazara/Network/ENetPeer.cpp | 43 +-- 4 files changed, 433 insertions(+), 69 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 87d4dd37b..03d10d541 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -63,9 +63,15 @@ namespace Nz bool DispatchIncomingCommands(ENetEvent* event); + bool HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command); + bool HandleBandwidthLimit(ENetPeer* peer, const ENetProtocol* command); ENetPeer* HandleConnect(ENetProtocolHeader* header, ENetProtocol* command); + bool HandleDisconnect(ENetPeer* peer, const ENetProtocol* command); bool HandleIncomingCommands(ENetEvent* event); - bool HandleSendReliable(ENetPeer& peer, const ENetProtocol& command, UInt8** currentData); + bool HandlePing(ENetPeer* peer, const ENetProtocol* command); + bool HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); + bool HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command); + bool HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command); int ReceiveIncomingCommands(ENetEvent* event); diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 4ae8ca16b..7d522f203 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -74,15 +74,15 @@ namespace Nz void OnConnect(); void OnDisconnect(); - ENetProtocolCommand RemoveSentReliableCommands(UInt16 reliableSequenceNumber, UInt8 channelId); + ENetProtocolCommand RemoveSentReliableCommand(UInt16 reliableSequenceNumber, UInt8 channelId); void RemoveSentUnreliableCommands(); void ResetQueues(); - - bool QueueAcknowledgement(ENetProtocol& command, UInt16 sentTime); + + bool QueueAcknowledgement(ENetProtocol* command, UInt16 sentTime); IncomingCommmand* QueueIncomingCommand(ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount); void QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length); - + void SetupOutgoingCommand(OutgoingCommand& outgoingCommand); int Throttle(UInt32 rtt); diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 05179e615..5bb9b7bdf 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -27,7 +27,7 @@ namespace Nz return value; #endif } - + /// Temporary template T NetToHost(T value) @@ -39,6 +39,31 @@ namespace Nz #endif } + namespace + { + static std::size_t s_commandSizes[ENetProtocolCommand_Count] = + { + 0, + sizeof(ENetProtocolAcknowledge), + sizeof(ENetProtocolConnect), + sizeof(ENetProtocolVerifyConnect), + sizeof(ENetProtocolDisconnect), + sizeof(ENetProtocolPing), + sizeof(ENetProtocolSendReliable), + sizeof(ENetProtocolSendUnreliable), + sizeof(ENetProtocolSendFragment), + sizeof(ENetProtocolSendUnsequenced), + sizeof(ENetProtocolBandwidthLimit), + sizeof(ENetProtocolThrottleConfigure), + sizeof(ENetProtocolSendFragment) + }; + + std::size_t enet_protocol_command_size(UInt8 commandNumber) + { + return s_commandSizes[commandNumber & ENetProtocolCommand_Mask]; + } + } + void ENetHost::Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) { @@ -372,6 +397,116 @@ namespace Nz return false; } + bool ENetHost::HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command) + { + if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie) + return true; + + UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); + receivedSentTime |= m_serviceTime & 0xFFFF0000; + if ((receivedSentTime & 0x8000) > (m_serviceTime & 0x8000)) + receivedSentTime -= 0x10000; + + if (ENET_TIME_LESS(m_serviceTime, receivedSentTime)) + return true; + + peer->m_lastReceiveTime = m_serviceTime; + peer->m_earliestTimeout = 0; + + UInt32 roundTripTime = ENET_TIME_DIFFERENCE(m_serviceTime, receivedSentTime); + + peer->Throttle(roundTripTime); + + peer->m_roundTripTimeVariance -= peer->m_roundTripTimeVariance / 4; + + if (roundTripTime >= peer->m_roundTripTime) + { + peer->m_roundTripTime += (roundTripTime - peer->m_roundTripTime) / 8; + peer->m_roundTripTimeVariance += (roundTripTime - peer->m_roundTripTime) / 4; + } + else + { + peer->m_roundTripTime -= (peer->m_roundTripTime - roundTripTime) / 8; + peer->m_roundTripTimeVariance += (peer->m_roundTripTime - roundTripTime) / 4; + } + + if (peer->m_roundTripTime < peer->m_lowestRoundTripTime) + peer->m_lowestRoundTripTime = peer->m_roundTripTime; + + if (peer->m_roundTripTimeVariance > peer->m_highestRoundTripTimeVariance) + peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance; + + if (peer->m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_packetThrottleEpoch) >= peer->packetThrottleInterval) + { + peer->m_lastRoundTripTime = peer->m_lowestRoundTripTime; + peer->m_lastRoundTripTimeVariance = peer->m_highestRoundTripTimeVariance; + peer->m_lowestRoundTripTime = peer->m_roundTripTime; + peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance; + peer->m_packetThrottleEpoch = m_serviceTime; + } + + UInt16 receivedReliableSequenceNumber = NetToHost(command->acknowledge.receivedReliableSequenceNumber); + + ENetProtocolCommand commandNumber = peer->RemoveSentReliableCommand(receivedReliableSequenceNumber, command->header.channelID); + + switch (peer->m_state) + { + case ENetPeerState::AcknowledgingConnect: + if (commandNumber != ENetProtocolCommand_VerifyConnect) + return false; + + NotifyConnect(peer, event); + break; + + case ENetPeerState::Disconnecting: + if (commandNumber != ENetProtocolCommand_Disconnect) + return false; + + NotifyDisconnect(peer, event); + break; + + case ENetPeerState::DisconnectLater: + if (peer->m_outgoingReliableCommands.empty() && peer->m_outgoingUnreliableCommands.empty() && peer->m_sentReliableCommands.empty()) + peer->Disconnect(peer->m_eventData); + + break; + + default: + break; + } + + return true; + } + + bool ENetHost::HandleBandwidthLimit(ENetPeer* peer, const ENetProtocol* command) + { + if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + return false; + + if (peer->m_incomingBandwidth != 0) + --m_bandwidthLimitedPeers; + + peer->m_incomingBandwidth = NetToHost(command->bandwidthLimit.incomingBandwidth); + peer->m_outgoingBandwidth = NetToHost(command->bandwidthLimit.outgoingBandwidth); + + if (peer->m_incomingBandwidth != 0) + ++m_bandwidthLimitedPeers; + + if (peer->m_incomingBandwidth == 0 && m_outgoingBandwidth == 0) + peer->m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else + { + if (peer->m_incomingBandwidth == 0 || m_outgoingBandwidth == 0) + peer->m_windowSize = (std::max(peer->m_incomingBandwidth, m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + else + peer->m_windowSize = (std::min(peer->m_incomingBandwidth, m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + peer->m_windowSize = Clamp(peer->m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + return true; + } + ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* header, ENetProtocol* command) { UInt32 channelCount = NetToHost(command->connect.channelCount); @@ -410,7 +545,7 @@ namespace Nz if (!peer || duplicatePeers >= m_duplicatePeers) return nullptr; - channelCount = std::min(channelCount, m_channelLimit); + channelCount = std::min(channelCount, m_channelLimit); peer->InitIncoming(channelCount, m_receivedAddress, command->connect); @@ -444,6 +579,37 @@ namespace Nz return peer; } + bool ENetHost::HandleDisconnect(ENetPeer* peer, const ENetProtocol * command) + { + if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie || peer->m_state == ENetPeerState::AcknowledgingDisconnect) + return true; + + peer->ResetQueues(); + + if (peer->m_state == ENetPeerState::ConnectionSucceeded || peer->m_state == ENetPeerState::Disconnecting || peer->m_state == ENetPeerState::Connecting) + peer->DispatchState(ENetPeerState::Zombie); + else + { + if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + { + if (peer->m_state == ENetPeerState::ConnectionPending) + m_recalculateBandwidthLimits = true; + + peer->Reset(); + } + else + if (command->header.command & ENetProtocolFlag_Acknowledge) + peer->ChangeState(ENetPeerState::AcknowledgingDisconnect); + else + peer->DispatchState(ENetPeerState::Zombie); + } + + if (peer->m_state != ENetPeerState::Disconnected) + peer->m_eventData = NetToHost(command->disconnect.data); + + return true; + } + bool ENetHost::HandleIncomingCommands(ENetEvent* event) { if (m_receivedDataLength < NazaraOffsetOf(ENetProtocolHeader, sentTime)) @@ -451,58 +617,275 @@ namespace Nz ENetProtocolHeader* header = reinterpret_cast(m_receivedData); - peerID = NetToHost(header->peerID); - sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT; - flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK; - peerID &= ~(ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK); + UInt16 peerID = NetToHost(header->peerID); + UInt8 sessionID = (peerID & ENetProtocolHeaderSessionMask) >> ENetProtocolHeaderSessionShift; + UInt16 flags = peerID & ENetProtocolHeaderFlag_Mask; + peerID &= ~(ENetProtocolHeaderFlag_Mask | ENetProtocolHeaderSessionMask); - headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof(ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *)0)->sentTime); - if (host->checksum != NULL) - headerSize += sizeof(enet_uint32); + std::size_t headerSize = (flags & ENetProtocolHeaderFlag_SentTime ? sizeof(ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *)0)->sentTime); - if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) - peer = NULL; + ENetPeer* peer; + if (peerID == ENetConstants::ENetProtocol_MaximumPeerId) + peer = nullptr; else - if (peerID >= host->peerCount) - return 0; + { + if (peerID >= m_peers.size()) + return false; else { - peer = &host->peers[peerID]; + peer = &m_peers[peerID]; - if (peer->state == ENET_PEER_STATE_DISCONNECTED || - peer->state == ENET_PEER_STATE_ZOMBIE || - ((host->receivedAddress.host != peer->address.host || - host->receivedAddress.port != peer->address.port) && - peer->address.host != ENET_HOST_BROADCAST) || - (peer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && - sessionID != peer->incomingSessionID)) - return 0; + if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie) + return false; + + if (m_receivedAddress != peer->m_address && peer->m_address != IpAddress::BroadcastIpV4) + return false; + + if (peer->m_outgoingPeerID < ENetConstants::ENetProtocol_MaximumPeerId && sessionID != peer->m_incomingSessionID) + return false; + } + } + + // Compression handling + + // Checksum + + if (peer) + { + peer->m_address = m_receivedAddress; + peer->m_incomingDataTotal += m_receivedDataLength; + } + + auto commandError = [&]() -> bool + { + if (event && event->type != ENetEventType::None) + return true; + + return false; + }; + + UInt8* currentData = m_receivedData + headerSize; + + while (currentData < &m_receivedData[m_receivedDataLength]) + { + ENetProtocol* command = reinterpret_cast(currentData); + + if (currentData + sizeof(ENetProtocolCommandHeader) > &m_receivedData[m_receivedDataLength]) + break; + + UInt8 commandNumber = command->header.command & ENetProtocolCommand_Mask; + if (commandNumber >= ENetProtocolCommand_Count) + break; + + std::size_t commandSize = s_commandSizes[commandNumber]; + if (commandSize == 0 || currentData + commandSize > &m_receivedData[m_receivedDataLength]) + break; + + currentData += commandSize; + + if (!peer && commandNumber != ENetProtocolCommand_Connect) + break; + + command->header.reliableSequenceNumber = NetToHost(command->header.reliableSequenceNumber); + + switch (commandNumber) + { + case ENetProtocolCommand_Acknowledge: + if (!HandleAcknowledge(event, peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_Connect: + if (peer) + return commandError(); + + peer = HandleConnect(header, command); + if (!peer) + return commandError(); + + break; + + case ENetProtocolCommand_VerifyConnect: + if (!HandleVerifyConnect(event, peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_Disconnect: + if (!HandleDisconnect(peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_Ping: + if (!HandlePing(peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_SendReliable: + if (!HandleSendReliable(peer, command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_SendUnreliable: + if (!HandleSendUnreliable(peer, command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_SendUnsequenced: + if (!HandleSendUnsequenced(peer, command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_SendFragment: + if (!HandleSendFragment(peer, command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_BandwidthLimit: + if (!HandleBandwidthLimit(peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_ThrottleConfigure: + if (!HandleThrottleConfigure(peer, command)) + return commandError(); + + break; + + case ENetProtocolCommand_SendUnreliableFragment: + if (!HandleSendUnreliableFragment(peer, command, ¤tData)) + return commandError(); + + break; + + default: + return commandError(); } - return false; + if (peer && (command->header.command & ENetProtocolCommand_Acknowledge) != 0) + { + UInt16 sentTime; + + if (!(flags & ENetProtocolHeaderFlag_SentTime)) + break; + + sentTime = NetToHost(header->sentTime); + + switch (peer->m_state) + { + case ENetPeerState::Disconnecting: + case ENetPeerState::AcknowledgingConnect: + case ENetPeerState::Disconnected: + case ENetPeerState::Zombie: + break; + + case ENetPeerState::AcknowledgingDisconnect: + if ((command->header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_Disconnect) + peer->QueueAcknowledgement(command, sentTime); + break; + + default: + peer->QueueAcknowledgement(command, sentTime); + break; + } + } + } + + return commandError(); } - bool ENetHost::HandleSendReliable(ENetPeer& peer, const ENetProtocol& command, UInt8** currentData) + bool ENetHost::HandlePing(ENetPeer* peer, const ENetProtocol* command) { - if (command.header.channelID >= peer.m_channels.size() || (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater)) + if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) return false; - UInt16 dataLength = NetToHost(command.sendReliable.dataLength); + return true; + } + + bool ENetHost::HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) + { + if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) + return false; + + UInt16 dataLength = NetToHost(command->sendReliable.dataLength); *currentData += dataLength; if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) return false; - if (!peer.QueueIncomingCommand(command, co)) + if (!peer->QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendReliable), dataLength, ENetPacketFlag_Reliable, 0)) + return false; return true; } + bool ENetHost::HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command) + { + if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + return false; + + peer->m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); + peer->m_packetThrottleAcceleration = NetToHost(command->throttleConfigure.packetThrottleAcceleration); + peer->m_packetThrottleDeceleration = NetToHost(command->throttleConfigure.packetThrottleDeceleration); + + return true; + } + + bool ENetHost::HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command) + { + if (peer->m_state != ENetPeerState::Connecting) + return false; + + UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); + + if (channelCount < ENetConstants::ENetProtocol_MinimumChannelCount || channelCount > ENetConstants::ENetProtocol_MaximumChannelCount || + NetToHost(command->verifyConnect.packetThrottleInterval) != peer->m_packetThrottleInterval || + NetToHost(command->verifyConnect.packetThrottleAcceleration) != peer->m_packetThrottleAcceleration || + NetToHost(command->verifyConnect.packetThrottleDeceleration) != peer->m_packetThrottleDeceleration || + command->verifyConnect.connectID != peer->m_connectID) + { + peer->m_eventData = 0; + + peer->DispatchState(ENetPeerState::Zombie); + + return false; + } + + peer->RemoveSentReliableCommand(1, 0xFF); + + if (channelCount < peer->m_channels.size()) + peer->m_channels.resize(channelCount); + + peer->m_outgoingPeerID = NetToHost(command->verifyConnect.outgoingPeerID); + peer->m_incomingSessionID = command->verifyConnect.incomingSessionID; + peer->m_outgoingSessionID = command->verifyConnect.outgoingSessionID; + + UInt32 mtu = Clamp(NetToHost(command->verifyConnect.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + peer->m_mtu = std::min(peer->m_mtu, mtu); + + UInt32 windowSize = Clamp(NetToHost(command->verifyConnect.windowSize), ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + peer->m_windowSize = std::min(peer->m_windowSize, windowSize); + + peer->m_incomingBandwidth = NetToHost(command->verifyConnect.incomingBandwidth); + peer->m_outgoingBandwidth = NetToHost(command->verifyConnect.outgoingBandwidth); + + NotifyConnect(peer, event); + return true; + } + int ENetHost::ReceiveIncomingCommands(ENetEvent* event) { for (unsigned int i = 0; i < 256; ++i) { NetPacket packet; - + std::size_t receivedLength; if (!m_socket.Receive(m_packetData[0].data(), m_packetData[0].size(), &m_receivedAddress, &receivedLength)) return -1; //< Error @@ -525,7 +908,7 @@ namespace Nz case -1: return -1; - + default: break; } @@ -740,4 +1123,4 @@ namespace Nz std::mt19937 ENetHost::s_randomGenerator; std::mt19937_64 ENetHost::s_randomGenerator64; -} \ No newline at end of file +} diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 9e5471c21..6f7f33312 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -16,7 +16,7 @@ namespace Nz return value; #endif } - + /// Temporary template T NetToHost(T value) @@ -28,31 +28,6 @@ namespace Nz #endif } - namespace - { - static std::size_t commandSizes[ENetProtocolCommand_Count] = - { - 0, - sizeof(ENetProtocolAcknowledge), - sizeof(ENetProtocolConnect), - sizeof(ENetProtocolVerifyConnect), - sizeof(ENetProtocolDisconnect), - sizeof(ENetProtocolPing), - sizeof(ENetProtocolSendReliable), - sizeof(ENetProtocolSendUnreliable), - sizeof(ENetProtocolSendFragment), - sizeof(ENetProtocolSendUnsequenced), - sizeof(ENetProtocolBandwidthLimit), - sizeof(ENetProtocolThrottleConfigure), - sizeof(ENetProtocolSendFragment) - }; - - std::size_t enet_protocol_command_size(UInt8 commandNumber) - { - return commandSizes[commandNumber & ENetProtocolCommand_Mask]; - } - } - ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : m_packetPool(sizeof(ENetPacket)), m_host(host), @@ -505,8 +480,8 @@ namespace Nz } } - ENetProtocolCommand ENetPeer::RemoveSentReliableCommands(UInt16 reliableSequenceNumber, UInt8 channelId) - { + ENetProtocolCommand ENetPeer::RemoveSentReliableCommand(UInt16 reliableSequenceNumber, UInt8 channelId) + { std::list* commandList = nullptr; bool found = true; @@ -595,16 +570,16 @@ namespace Nz m_channels.clear(); } - bool ENetPeer::QueueAcknowledgement(ENetProtocol& command, UInt16 sentTime) + bool ENetPeer::QueueAcknowledgement(ENetProtocol*command, UInt16 sentTime) { - if (command.header.channelID < m_channels.size()) + if (command->header.channelID < m_channels.size()) { - Channel& channel = m_channels[command.header.channelID]; + Channel& channel = m_channels[command->header.channelID]; - UInt16 reliableWindow = command.header.reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 reliableWindow = command->header.reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; - if (command.header.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + if (command->header.reliableSequenceNumber < channel.incomingReliableSequenceNumber) reliableWindow += ENetConstants::ENetPeer_ReliableWindows; if (reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1 && reliableWindow <= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows) @@ -882,4 +857,4 @@ namespace Nz return 0; } -} \ No newline at end of file +} From 8a59dc88b844992f75fadb72492ea4ffe0515948 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 27 Jan 2017 14:48:31 +0100 Subject: [PATCH 03/73] Commit progression --- include/Nazara/Network/ENetHost.hpp | 30 +- include/Nazara/Network/ENetHost.inl | 12 +- include/Nazara/Network/ENetPacket.hpp | 33 +- include/Nazara/Network/ENetPeer.hpp | 129 ++--- include/Nazara/Network/ENetPeer.inl | 14 +- include/Nazara/Network/ENetProtocol.hpp | 47 +- include/Nazara/Network/Enums.hpp | 2 + src/Nazara/Network/ENetHost.cpp | 711 ++++++++++++++++++++++-- src/Nazara/Network/ENetPacket.cpp | 6 +- src/Nazara/Network/ENetPeer.cpp | 50 +- src/Nazara/Network/ENetSocket.cpp | 642 --------------------- 11 files changed, 865 insertions(+), 811 deletions(-) delete mode 100644 src/Nazara/Network/ENetSocket.cpp diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 03d10d541..3b86a1f25 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -40,8 +41,10 @@ namespace Nz void Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet); - bool Connect(const IpAddress& remoteAddress, std::size_t channelCount = 0, UInt32 data = 0); - bool Connect(const String& hostName, NetProtocol protocol = NetProtocol_Any, const String& service = "http", ResolveError* error = nullptr, std::size_t channelCount = 0, UInt32 data = 0); + bool CheckEvents(ENetEvent* event); + + ENetPeer* Connect(const IpAddress& remoteAddress, std::size_t channelCount = 0, UInt32 data = 0); + ENetPeer* Connect(const String& hostName, NetProtocol protocol = NetProtocol_Any, const String& service = "http", ResolveError* error = nullptr, std::size_t channelCount = 0, UInt32 data = 0); inline bool Create(NetProtocol protocol, UInt16 port, std::size_t peerCount, std::size_t channelCount = 0); bool Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount = 0); @@ -58,8 +61,10 @@ namespace Nz private: bool InitSocket(const IpAddress& address); - inline void AddToDispatchQueue(ENetPeer* peer); - inline void RemoveFromDispatchQueue(ENetPeer* peer); + void AddToDispatchQueue(ENetPeer* peer); + void RemoveFromDispatchQueue(ENetPeer* peer); + + bool CheckTimeouts(ENetPeer* peer, ENetEvent* event); bool DispatchIncomingCommands(ENetEvent* event); @@ -69,7 +74,11 @@ namespace Nz bool HandleDisconnect(ENetPeer* peer, const ENetProtocol* command); bool HandleIncomingCommands(ENetEvent* event); bool HandlePing(ENetPeer* peer, const ENetProtocol* command); + bool HandleSendFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); bool HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); + bool HandleSendUnreliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); + bool HandleSendUnreliableFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); + bool HandleSendUnsequenced(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); bool HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command); bool HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command); @@ -78,12 +87,19 @@ namespace Nz void NotifyConnect(ENetPeer* peer, ENetEvent* event); void NotifyDisconnect(ENetPeer*, ENetEvent* event); + void SendAcknowledgements(ENetPeer* peer); + bool SendReliableOutgoingCommands(ENetPeer* peer); + int SendOutgoingCommands(ENetEvent* event, bool checkForTimeouts); + void SendUnreliableOutgoingCommands(ENetPeer* peer); + void ThrottleBandwidth(); + static std::size_t GetCommandSize(UInt8 commandNumber); static bool Initialize(); static void Uninitialize(); std::array m_commands; + std::array m_buffers; std::array m_packetData[2]; std::bernoulli_distribution m_packetLossProbability; std::size_t m_bandwidthLimitedPeers; @@ -93,6 +109,8 @@ namespace Nz std::size_t m_duplicatePeers; std::size_t m_maximumPacketSize; std::size_t m_maximumWaitingData; + std::size_t m_packetSize; + std::size_t m_peerCount; std::size_t m_receivedDataLength; std::vector m_peers; Bitset m_dispatchQueue; @@ -101,6 +119,7 @@ namespace Nz IpAddress m_receivedAddress; SocketPoller m_poller; UdpSocket m_socket; + UInt16 m_headerFlags; UInt32 m_bandwidthThrottleEpoch; UInt32 m_connectedPeers; UInt32 m_mtu; @@ -113,6 +132,7 @@ namespace Nz UInt32 m_totalReceivedData; UInt32 m_totalReceivedPackets; UInt8* m_receivedData; + bool m_continueSending; bool m_isSimulationEnabled; bool m_shouldAcceptConnections; bool m_recalculateBandwidthLimits; diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index c4a077e8b..e547d4e5d 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -50,16 +50,6 @@ namespace Nz m_peers.clear(); m_socket.Close(); } - - inline void ENetHost::AddToDispatchQueue(ENetPeer* peer) - { - m_dispatchQueue.UnboundedSet(peer->m_incomingPeerID); - } - - inline void ENetHost::RemoveFromDispatchQueue(ENetPeer* peer) - { - m_dispatchQueue.UnboundedReset(peer->m_incomingPeerID); - } } #include diff --git a/include/Nazara/Network/ENetPacket.hpp b/include/Nazara/Network/ENetPacket.hpp index ad1610eb4..54a5d4676 100644 --- a/include/Nazara/Network/ENetPacket.hpp +++ b/include/Nazara/Network/ENetPacket.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -40,7 +40,7 @@ namespace Nz std::size_t referenceCount = 0; }; - struct ENetPacketRef + struct NAZARA_NETWORK_API ENetPacketRef { ENetPacketRef() = default; @@ -49,6 +49,18 @@ namespace Nz Reset(packet); } + ENetPacketRef(const ENetPacketRef& packet) : + ENetPacketRef() + { + Reset(packet); + } + + ENetPacketRef(ENetPacketRef&& packet) : + m_packet(packet.m_packet) + { + packet.m_packet = nullptr; + } + ~ENetPacketRef() { Reset(); @@ -69,6 +81,23 @@ namespace Nz ENetPacketRef& operator=(ENetPacket* packet) { Reset(packet); + + return *this; + } + + ENetPacketRef& operator=(const ENetPacketRef& packet) + { + Reset(packet); + + return *this; + } + + ENetPacketRef& operator=(ENetPacketRef&& packet) + { + m_packet = packet.m_packet; + packet.m_packet = nullptr; + + return *this; } ENetPacket* m_packet = nullptr; diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 7d522f203..e68b85de9 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -32,6 +32,7 @@ namespace Nz friend struct PacketRef; public: + ENetPeer(ENetHost* host, UInt16 peerId); ENetPeer(const ENetPeer&) = delete; ENetPeer(ENetPeer&&) = default; ~ENetPeer() = default; @@ -40,6 +41,8 @@ namespace Nz void DisconnectLater(UInt32 data); void DisconnectNow(UInt32 data); + inline const IpAddress& GetAddress() const; + void Ping(); bool Receive(ENetPacketRef* packet, UInt8* channelId); @@ -54,8 +57,6 @@ namespace Nz ENetPeer& operator=(ENetPeer&&) = default; private: - ENetPeer(ENetHost* host, UInt16 peerId); - void InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand); void InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize); @@ -66,7 +67,7 @@ namespace Nz // Protocol functions inline void ChangeState(ENetPeerState state); - inline void DispatchState(ENetPeerState state); + void DispatchState(ENetPeerState state); void DispatchIncomingReliableCommands(Channel& channel); void DispatchIncomingUnreliableCommands(Channel& channel); @@ -80,7 +81,7 @@ namespace Nz void ResetQueues(); bool QueueAcknowledgement(ENetProtocol* command, UInt16 sentTime); - IncomingCommmand* QueueIncomingCommand(ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount); + IncomingCommmand* QueueIncomingCommand(const ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount); void QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length); void SetupOutgoingCommand(OutgoingCommand& outgoingCommand); @@ -139,64 +140,66 @@ namespace Nz UInt32 sentTime; }; - ENetHost* m_host; - IpAddress m_address; /**< Internet address of the peer */ - std::vector m_channels; - std::list m_acknowledgements; - std::list m_dispatchedCommands; - std::list m_outgoingReliableCommands; - std::list m_outgoingUnreliableCommands; - std::list m_sentReliableCommands; - std::list m_sentUnreliableCommands; - MemoryPool m_packetPool; - //ENetListNode m_dispatchList; - ENetPeerState m_state; - UInt8 m_incomingSessionID; - UInt8 m_outgoingSessionID; - UInt16 m_incomingPeerID; - UInt16 m_incomingUnsequencedGroup; - UInt16 m_outgoingPeerID; - UInt16 m_outgoingReliableSequenceNumber; - UInt16 m_outgoingUnsequencedGroup; - UInt32 m_connectID; - UInt32 m_earliestTimeout; - UInt32 m_eventData; - UInt32 m_highestRoundTripTimeVariance; - UInt32 m_incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ - UInt32 m_incomingBandwidthThrottleEpoch; - UInt32 m_incomingDataTotal; - UInt32 m_lastReceiveTime; - UInt32 m_lastRoundTripTime; - UInt32 m_lastRoundTripTimeVariance; - UInt32 m_lastSendTime; - UInt32 m_lowestRoundTripTime; - UInt32 m_mtu; - UInt32 m_nextTimeout; - UInt32 m_outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ - UInt32 m_outgoingBandwidthThrottleEpoch; - UInt32 m_outgoingDataTotal; - UInt32 m_packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ - UInt32 m_packetLossEpoch; - UInt32 m_packetLossVariance; - UInt32 m_packetThrottle; - UInt32 m_packetThrottleAcceleration; - UInt32 m_packetThrottleCounter; - UInt32 m_packetThrottleDeceleration; - UInt32 m_packetThrottleEpoch; - UInt32 m_packetThrottleInterval; - UInt32 m_packetThrottleLimit; - UInt32 m_packetsLost; - UInt32 m_packetsSent; - UInt32 m_pingInterval; - UInt32 m_reliableDataInTransit; - UInt32 m_roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgment */ - UInt32 m_roundTripTimeVariance; - UInt32 m_timeoutLimit; - UInt32 m_timeoutMaximum; - UInt32 m_timeoutMinimum; - UInt32 m_unsequencedWindow[ENetPeer_ReliableWindowSize / 32]; - UInt32 m_windowSize; - std::size_t m_totalWaitingData; + static constexpr std::size_t unsequencedWindow = ENetPeer_ReliableWindowSize / 32; + + ENetHost* m_host; + IpAddress m_address; /**< Internet address of the peer */ + std::array m_unsequencedWindow; + std::list m_acknowledgements; + std::list m_dispatchedCommands; + std::list m_outgoingReliableCommands; + std::list m_outgoingUnreliableCommands; + std::list m_sentReliableCommands; + std::list m_sentUnreliableCommands; + std::size_t m_totalWaitingData; + std::vector m_channels; + MemoryPool m_packetPool; + //ENetListNode m_dispatchList; + ENetPeerState m_state; + UInt8 m_incomingSessionID; + UInt8 m_outgoingSessionID; + UInt16 m_incomingPeerID; + UInt16 m_incomingUnsequencedGroup; + UInt16 m_outgoingPeerID; + UInt16 m_outgoingReliableSequenceNumber; + UInt16 m_outgoingUnsequencedGroup; + UInt32 m_connectID; + UInt32 m_earliestTimeout; + UInt32 m_eventData; + UInt32 m_highestRoundTripTimeVariance; + UInt32 m_incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + UInt32 m_incomingBandwidthThrottleEpoch; + UInt32 m_incomingDataTotal; + UInt32 m_lastReceiveTime; + UInt32 m_lastRoundTripTime; + UInt32 m_lastRoundTripTimeVariance; + UInt32 m_lastSendTime; + UInt32 m_lowestRoundTripTime; + UInt32 m_mtu; + UInt32 m_nextTimeout; + UInt32 m_outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + UInt32 m_outgoingBandwidthThrottleEpoch; + UInt32 m_outgoingDataTotal; + UInt32 m_packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + UInt32 m_packetLossEpoch; + UInt32 m_packetLossVariance; + UInt32 m_packetThrottle; + UInt32 m_packetThrottleAcceleration; + UInt32 m_packetThrottleCounter; + UInt32 m_packetThrottleDeceleration; + UInt32 m_packetThrottleEpoch; + UInt32 m_packetThrottleInterval; + UInt32 m_packetThrottleLimit; + UInt32 m_packetsLost; + UInt32 m_packetsSent; + UInt32 m_pingInterval; + UInt32 m_reliableDataInTransit; + UInt32 m_roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgment */ + UInt32 m_roundTripTimeVariance; + UInt32 m_timeoutLimit; + UInt32 m_timeoutMaximum; + UInt32 m_timeoutMinimum; + UInt32 m_windowSize; }; } diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index a0cebbc4e..2c7044b6e 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -8,6 +8,11 @@ namespace Nz { + inline const IpAddress& ENetPeer::GetAddress() const + { + return m_address; + } + inline void ENetPeer::ChangeState(ENetPeerState state) { if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater) @@ -17,13 +22,6 @@ namespace Nz m_state = state; } - - inline void ENetPeer::DispatchState(ENetPeerState state) - { - ChangeState(state); - - m_host->AddToDispatchQueue(this); - } } #include diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp index d4d74fd01..8b62f7dc7 100644 --- a/include/Nazara/Network/ENetProtocol.hpp +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -13,6 +13,8 @@ namespace Nz { + class ENetPeer; + // Constants for the ENet implementation and protocol enum ENetConstants { @@ -140,27 +142,38 @@ namespace Nz ENetPacketRef packet; }; - struct ENetProtocolHeader + + #ifdef _MSC_VER + #pragma pack(push, 1) + #define NAZARA_PACKED + #elif defined(__GNUC__) || defined(__clang__) + #define NAZARA_PACKED __attribute__ ((packed)) + #else + #define NAZARA_PACKED + #endif + + + struct NAZARA_PACKED ENetProtocolHeader { UInt16 peerID; UInt16 sentTime; }; - struct ENetProtocolCommandHeader + struct NAZARA_PACKED ENetProtocolCommandHeader { UInt8 command; UInt8 channelID; UInt16 reliableSequenceNumber; }; - struct ENetProtocolAcknowledge + struct NAZARA_PACKED ENetProtocolAcknowledge { ENetProtocolCommandHeader header; UInt16 receivedReliableSequenceNumber; UInt16 receivedSentTime; }; - struct ENetProtocolConnect + struct NAZARA_PACKED ENetProtocolConnect { ENetProtocolCommandHeader header; UInt16 outgoingPeerID; @@ -178,25 +191,25 @@ namespace Nz UInt32 data; }; - struct ENetProtocolBandwidthLimit + struct NAZARA_PACKED ENetProtocolBandwidthLimit { ENetProtocolCommandHeader header; UInt32 incomingBandwidth; UInt32 outgoingBandwidth; }; - struct ENetProtocolDisconnect + struct NAZARA_PACKED ENetProtocolDisconnect { ENetProtocolCommandHeader header; UInt32 data; }; - struct ENetProtocolPing + struct NAZARA_PACKED ENetProtocolPing { ENetProtocolCommandHeader header; }; - struct ENetProtocolSendFragment + struct NAZARA_PACKED ENetProtocolSendFragment { ENetProtocolCommandHeader header; UInt16 startSequenceNumber; @@ -207,27 +220,27 @@ namespace Nz UInt32 fragmentOffset; }; - struct ENetProtocolSendReliable + struct NAZARA_PACKED ENetProtocolSendReliable { ENetProtocolCommandHeader header; UInt16 dataLength; }; - struct ENetProtocolSendUnreliable + struct NAZARA_PACKED ENetProtocolSendUnreliable { ENetProtocolCommandHeader header; UInt16 unreliableSequenceNumber; UInt16 dataLength; }; - struct ENetProtocolSendUnsequenced + struct NAZARA_PACKED ENetProtocolSendUnsequenced { ENetProtocolCommandHeader header; UInt16 unsequencedGroup; UInt16 dataLength; }; - struct ENetProtocolThrottleConfigure + struct NAZARA_PACKED ENetProtocolThrottleConfigure { ENetProtocolCommandHeader header; UInt32 packetThrottleInterval; @@ -235,7 +248,7 @@ namespace Nz UInt32 packetThrottleDeceleration; }; - struct ENetProtocolVerifyConnect + struct NAZARA_PACKED ENetProtocolVerifyConnect { ENetProtocolCommandHeader header; UInt16 outgoingPeerID; @@ -252,7 +265,7 @@ namespace Nz UInt32 connectID; }; - union ENetProtocol + union NAZARA_PACKED ENetProtocol { ENetProtocolCommandHeader header; ENetProtocolAcknowledge acknowledge; @@ -267,6 +280,10 @@ namespace Nz ENetProtocolThrottleConfigure throttleConfigure; ENetProtocolVerifyConnect verifyConnect; }; + + #ifdef _MSC_VER + #pragma pack(pop) + #endif } #endif // NAZARA_ENETPROTOCOL_HPP diff --git a/include/Nazara/Network/Enums.hpp b/include/Nazara/Network/Enums.hpp index 7dccd7dd1..f80ba6cd9 100644 --- a/include/Nazara/Network/Enums.hpp +++ b/include/Nazara/Network/Enums.hpp @@ -7,6 +7,8 @@ #ifndef NAZARA_ENUMS_NETWORK_HPP #define NAZARA_ENUMS_NETWORK_HPP +#include + namespace Nz { enum NetCode : UInt16 diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 5bb9b7bdf..ffe15635a 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1,9 +1,10 @@ -#include +#include #include #include #include #include #include +#include #include #define ENET_TIME_OVERFLOW 86400000 @@ -57,11 +58,6 @@ namespace Nz sizeof(ENetProtocolThrottleConfigure), sizeof(ENetProtocolSendFragment) }; - - std::size_t enet_protocol_command_size(UInt8 commandNumber) - { - return s_commandSizes[commandNumber & ENetProtocolCommand_Mask]; - } } @@ -81,7 +77,19 @@ namespace Nz } } - bool ENetHost::Connect(const IpAddress& remoteAddress, std::size_t channelCount, UInt32 data) + bool ENetHost::CheckEvents(ENetEvent* event) + { + if (!event) + return false; + + event->type = ENetEventType::None; + event->peer = nullptr; + event->packet.Reset(); + + return DispatchIncomingCommands(event); + } + + ENetPeer* ENetHost::Connect(const IpAddress& remoteAddress, std::size_t channelCount, UInt32 data) { NazaraAssert(remoteAddress.IsValid(), "Invalid remote address"); NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port"); @@ -96,7 +104,7 @@ namespace Nz if (peerId >= m_peers.size()) { NazaraError("Insufficient peers"); - return false; + return nullptr; } m_channelLimit = Clamp(channelCount, ENetConstants::ENetProtocol_MinimumChannelCount, ENetConstants::ENetProtocol_MaximumChannelCount); @@ -130,10 +138,10 @@ namespace Nz peer.QueueOutgoingCommand(command, nullptr, 0, 0); - return true; + return &peer; } - bool ENetHost::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error, std::size_t channelCount, UInt32 data) + ENetPeer* ENetHost::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error, std::size_t channelCount, UInt32 data) { std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); if (results.empty()) @@ -173,7 +181,9 @@ namespace Nz if (!InitSocket(address)) return false; - m_peers.resize(peerCount); + m_peers.reserve(peerCount); + for (std::size_t i = 0; i < peerCount; ++i) + m_peers.emplace_back(this, UInt16(i)); m_address = address; m_randomSeed = *reinterpret_cast(this); @@ -187,6 +197,7 @@ namespace Nz m_mtu = ENetConstants::ENetHost_DefaultMTU; m_commandCount = 0; m_bufferCount = 0; + m_peerCount = peerCount; m_receivedAddress = IpAddress::AnyIpV4; m_receivedData = nullptr; m_receivedDataLength = 0; @@ -214,8 +225,6 @@ namespace Nz int ENetHost::Service(ENetEvent* event, UInt32 timeout) { - UInt32 waitCondition; - if (event) { event->type = ENetEventType::None; @@ -265,7 +274,7 @@ namespace Nz break; } - switch (SendOutgoingCommands(event, 1)) + switch (SendOutgoingCommands(event, true)) { case 1: return 1; @@ -283,21 +292,8 @@ namespace Nz if (event) { - switch (DispatchIncomingCommands(event)) - { - case 1: - return 1; - - case -1: - #ifdef ENET_DEBUG - perror("Error dispatching incoming packets"); - #endif - - return -1; - - default: - break; - } + if (DispatchIncomingCommands(event)) + return 1; } if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) @@ -310,12 +306,8 @@ namespace Nz if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) return 0; - SocketError error; - if (m_poller.Wait(ENET_TIME_DIFFERENCE(timeout, m_serviceTime), &error)) + if (m_poller.Wait(ENET_TIME_DIFFERENCE(timeout, m_serviceTime))) break; - - if (error != SocketError_NoError) - return -1; } m_serviceTime = GetElapsedMilliseconds(); @@ -349,6 +341,62 @@ namespace Nz return true; } + void ENetHost::AddToDispatchQueue(ENetPeer* peer) + { + m_dispatchQueue.UnboundedSet(peer->m_incomingPeerID); + } + + void ENetHost::RemoveFromDispatchQueue(ENetPeer* peer) + { + m_dispatchQueue.UnboundedReset(peer->m_incomingPeerID); + } + + bool ENetHost::CheckTimeouts(ENetPeer* peer, ENetEvent* event) + { + auto currentCommand = peer->m_sentReliableCommands.begin(); + + while (currentCommand != peer->m_sentReliableCommands.end()) + { + auto outgoingCommand = currentCommand; + + ++currentCommand; + + if (ENET_TIME_DIFFERENCE(m_serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) + continue; + + if (peer->m_earliestTimeout == 0 || ENET_TIME_LESS(outgoingCommand->sentTime, peer->m_earliestTimeout)) + peer->m_earliestTimeout = outgoingCommand->sentTime; + + if (peer->m_earliestTimeout != 0 && (ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_earliestTimeout) >= peer->m_timeoutMaximum || + (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_earliestTimeout) >= peer->m_timeoutMinimum))) + { + NotifyDisconnect(peer, event); + return true; + } + + if (outgoingCommand->packet) + peer->m_reliableDataInTransit -= outgoingCommand->fragmentLength; + + ++peer->m_packetsLost; + + outgoingCommand->roundTripTimeout *= 2; + + peer->m_outgoingReliableCommands.emplace_front(std::move(*outgoingCommand)); + peer->m_sentReliableCommands.erase(outgoingCommand); + + // Okay this should just never procs, I don't see how it would be possible + /*if (currentCommand == enet_list_begin(&peer->sentReliableCommands) && + !enet_list_empty(&peer->sentReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + peer->nextTimeout = outgoingCommand->sentTime + outgoingCommand->roundTripTimeout; + }*/ + } + + return false; + } + bool ENetHost::DispatchIncomingCommands(ENetEvent* event) { for (std::size_t bit = m_dispatchQueue.FindFirst(); bit != m_dispatchQueue.npos; bit = m_dispatchQueue.FindNext(bit)) @@ -391,6 +439,9 @@ namespace Nz AddToDispatchQueue(&peer); return true; + + default: + break; } } @@ -436,7 +487,7 @@ namespace Nz if (peer->m_roundTripTimeVariance > peer->m_highestRoundTripTimeVariance) peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance; - if (peer->m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_packetThrottleEpoch) >= peer->packetThrottleInterval) + if (peer->m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_packetThrottleEpoch) >= peer->m_packetThrottleInterval) { peer->m_lastRoundTripTime = peer->m_lowestRoundTripTime; peer->m_lastRoundTripTimeVariance = peer->m_highestRoundTripTimeVariance; @@ -770,7 +821,7 @@ namespace Nz return commandError(); } - if (peer && (command->header.command & ENetProtocolCommand_Acknowledge) != 0) + if (peer && (command->header.command & ENetProtocolFlag_Acknowledge) != 0) { UInt16 sentTime; @@ -810,6 +861,90 @@ namespace Nz return true; } + bool ENetHost::HandleSendFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) + { + if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) + return false; + + UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); + *currentData += fragmentLength; + if (fragmentLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) + return false; + + ENetPeer::Channel& channel = peer->m_channels[command->header.channelID]; + UInt32 startSequenceNumber = NetToHost(command->sendFragment.startSequenceNumber); + UInt16 startWindow = startSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (startSequenceNumber < channel.incomingReliableSequenceNumber) + startWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (startWindow < currentWindow || startWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) + return true; + + UInt32 fragmentNumber = NetToHost(command->sendFragment.fragmentNumber); + UInt32 fragmentCount = NetToHost(command->sendFragment.fragmentCount); + UInt32 fragmentOffset = NetToHost(command->sendFragment.fragmentOffset); + UInt32 totalLength = NetToHost(command->sendFragment.totalLength); + + if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount || fragmentNumber >= fragmentCount || totalLength > m_maximumPacketSize || + fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset) + return false; + + ENetPeer::IncomingCommmand* startCommand = nullptr; + for (auto currentCommand = channel.incomingReliableCommands.rbegin(); currentCommand != channel.incomingReliableCommands.rend(); ++currentCommand) + { + ENetPeer::IncomingCommmand& incomingCommand = *currentCommand; + + if (startSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber <= startSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < startSequenceNumber) + break; + + if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendFragment || + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.size()) + return false; + + startCommand = &incomingCommand; + break; + } + } + + if (startCommand) + { + ENetProtocol hostCommand = *command; + hostCommand.header.reliableSequenceNumber = startSequenceNumber; + + if (!peer->QueueIncomingCommand(hostCommand, nullptr, totalLength, ENetPacketFlag_Reliable, fragmentCount)) + return false; + } + + if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) + { + --startCommand->fragmentsRemaining; + + startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + + if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) + fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; + + std::memcpy(startCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) + peer->DispatchIncomingReliableCommands(channel); + } + + return false; + } + bool ENetHost::HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) { if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) @@ -826,6 +961,152 @@ namespace Nz return true; } + bool ENetHost::HandleSendUnreliable(ENetPeer * peer, const ENetProtocol * command, UInt8 ** currentData) + { + if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) + return false; + + UInt16 dataLength = NetToHost(command->sendUnreliable.dataLength); + *currentData += dataLength; + if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) + return false; + + if (!peer->QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendUnreliable), dataLength, 0, 0)) + return false; + + return true; + } + + bool ENetHost::HandleSendUnreliableFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) + { + if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) + return false; + + UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); + *currentData += fragmentLength; + if (fragmentLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) + return false; + + ENetPeer::Channel& channel = peer->m_channels[command->header.channelID]; + UInt32 reliableSequenceNumber = command->header.reliableSequenceNumber; + UInt32 startSequenceNumber = NetToHost(command->sendFragment.startSequenceNumber); + + UInt16 reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (startSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) + return true; + + if (reliableSequenceNumber == channel.incomingReliableSequenceNumber && startSequenceNumber <= channel.incomingUnreliableSequenceNumber) + return true; + + UInt32 fragmentNumber = NetToHost(command->sendFragment.fragmentNumber); + UInt32 fragmentCount = NetToHost(command->sendFragment.fragmentCount); + UInt32 fragmentOffset = NetToHost(command->sendFragment.fragmentOffset); + UInt32 totalLength = NetToHost(command->sendFragment.totalLength); + + if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount || fragmentNumber >= fragmentCount || totalLength > m_maximumPacketSize || + fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset) + return false; + + ENetPeer::IncomingCommmand* startCommand = nullptr; + for (auto currentCommand = channel.incomingUnreliableCommands.rbegin(); currentCommand != channel.incomingUnreliableCommands.rend(); ++currentCommand) + { + ENetPeer::IncomingCommmand& incomingCommand = *currentCommand; + + if (startSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber < reliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber > reliableSequenceNumber) + continue; + + if (incomingCommand.unreliableSequenceNumber <= startSequenceNumber) + { + if (incomingCommand.unreliableSequenceNumber < startSequenceNumber) + break; + + if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnreliableFragment || + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.size()) + return false; + + startCommand = &incomingCommand; + break; + } + } + + if (startCommand) + { + if (!peer->QueueIncomingCommand(*command, nullptr, totalLength, ENetPacketFlag_UnreliableFragment, fragmentCount)) + return false; + } + + if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) + { + --startCommand->fragmentsRemaining; + + startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + + if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) + fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; + + std::memcpy(startCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) + peer->DispatchIncomingUnreliableCommands(channel); + } + + return true; + } + + bool ENetHost::HandleSendUnsequenced(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) + { + if (command->header.channelID >= peer->m_channels.size() || peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + return false; + + std::size_t dataLength = NetToHost(command->sendUnsequenced.dataLength); + *currentData += dataLength; + if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) + return false; + + UInt32 unsequencedGroup = NetToHost(command->sendUnsequenced.unsequencedGroup); + UInt32 index = unsequencedGroup % ENetConstants::ENetPeer_UnsequencedWindowSize; + + if (unsequencedGroup < peer->m_incomingUnsequencedGroup) + unsequencedGroup += 0x10000; + + if (unsequencedGroup >= static_cast(peer->m_incomingUnsequencedGroup) + ENetConstants::ENetPeer_UnsequencedWindows * ENetConstants::ENetPeer_UnsequencedWindowSize) + return true; + + unsequencedGroup &= 0xFFFF; + + if (unsequencedGroup - index != peer->m_incomingUnsequencedGroup) + { + peer->m_incomingUnsequencedGroup = unsequencedGroup - index; + + peer->m_unsequencedWindow.fill(0); + } + else if (peer->m_unsequencedWindow[index / 32] & (1 << (index % 32))) + return true; + + if (!peer->QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendUnsequenced), dataLength, ENetPacketFlag_Unsequenced, 0)) + return false; + + peer->m_unsequencedWindow[index / 32] |= 1 << (index % 32); + + return true; + } + bool ENetHost::HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command) { if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) @@ -901,17 +1182,8 @@ namespace Nz // Intercept - switch (HandleIncomingCommands(event)) - { - case 1: - return 1; - - case -1: - return -1; - - default: - break; - } + if (HandleIncomingCommands(event)) + return 1; } return -1; @@ -956,6 +1228,346 @@ namespace Nz } } + void ENetHost::SendAcknowledgements(ENetPeer* peer) + { + std::cout << "SendAcknowledgements " << peer->m_acknowledgements.size() << std::endl; + + auto currentAcknowledgement = peer->m_acknowledgements.begin(); + while (currentAcknowledgement != peer->m_acknowledgements.end()) + { + if (m_commandCount >= m_commands.size() || m_bufferCount >= m_buffers.size() || peer->m_mtu - m_packetSize < sizeof(ENetProtocolAcknowledge)) + { + m_continueSending = true; + break; + } + + ENetPeer::Acknowledgement& acknowledgement = *currentAcknowledgement; + + ENetProtocol& command = m_commands[m_commandCount]; + NetBuffer& buffer = m_buffers[m_bufferCount]; + + buffer.data = &command; + buffer.dataLength = sizeof(ENetProtocolAcknowledge); + + m_packetSize += buffer.dataLength; + + UInt16 reliableSequenceNumber = HostToNet(acknowledgement.command.header.reliableSequenceNumber); + + command.header.command = ENetProtocolCommand_Acknowledge; + command.header.channelID = acknowledgement.command.header.channelID; + command.header.reliableSequenceNumber = reliableSequenceNumber; + command.acknowledge.receivedReliableSequenceNumber = reliableSequenceNumber; + command.acknowledge.receivedSentTime = HostToNet(acknowledgement.sentTime); + + if ((acknowledgement.command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_Disconnect) + peer->DispatchState(ENetPeerState::Zombie); + + currentAcknowledgement = peer->m_acknowledgements.erase(currentAcknowledgement); + + ++m_bufferCount; + ++m_commandCount; + } + } + + bool ENetHost::SendReliableOutgoingCommands(ENetPeer* peer) + { + bool canPing = true; + bool windowExceeded = false; + bool windowWrap = false; + + auto currentCommand = peer->m_outgoingReliableCommands.begin(); + while (currentCommand != peer->m_outgoingReliableCommands.end()) + { + auto outgoingCommand = currentCommand; + + UInt16 reliableWindow = outgoingCommand->reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + ENetPeer::Channel* channel = (outgoingCommand->command.header.channelID < peer->m_channels.size()) ? &peer->m_channels[outgoingCommand->command.header.channelID] : nullptr; + if (channel) + { + if (!windowWrap && outgoingCommand->sendAttempts < 1 && !(outgoingCommand->reliableSequenceNumber % ENetPeer_ReliableWindowSize) && + ((channel->reliableWindows[(reliableWindow + ENetPeer_ReliableWindows - 1) % ENetPeer_ReliableWindows] >= ENetPeer_ReliableWindowSize) || + channel->usedReliableWindows & ((((1 << ENetPeer_ReliableWindows) - 1) << reliableWindow) | + (((1 << ENetPeer_FreeReliableWindows) - 1) >> (ENetPeer_ReliableWindows - reliableWindow))))) + windowWrap = true; + + if (windowWrap) + { + ++currentCommand; + continue; + } + } + + if (outgoingCommand->packet) + { + if (!windowExceeded) + { + UInt32 windowSize = (peer->m_packetThrottle * peer->m_windowSize) / ENetPeer_PacketThrottleScale; + + if (peer->m_reliableDataInTransit + outgoingCommand->fragmentLength > std::max(windowSize, peer->m_mtu)) + windowExceeded = true; + } + + if (windowExceeded) + { + ++currentCommand; + continue; + } + } + + canPing = false; + + std::size_t commandSize = s_commandSizes[outgoingCommand->command.header.command & ENetProtocolCommand_Mask]; + if (m_commandCount >= m_commands.size() || m_bufferCount + 1 >= m_buffers.size() || peer->m_mtu - m_packetSize < commandSize || + (outgoingCommand->packet && UInt16(peer->m_mtu - m_packetSize) < UInt16(commandSize + outgoingCommand->fragmentLength))) + { + m_continueSending = true; + break; + } + + ++currentCommand; + + if (channel && outgoingCommand->sendAttempts < 1) + { + channel->usedReliableWindows |= 1 << reliableWindow; + ++channel->reliableWindows[reliableWindow]; + } + + ++outgoingCommand->sendAttempts; + + if (outgoingCommand->roundTripTimeout == 0) + { + outgoingCommand->roundTripTimeout = peer->m_roundTripTime + 4 * peer->m_roundTripTimeVariance; + outgoingCommand->roundTripTimeoutLimit = peer->m_timeoutLimit * outgoingCommand->roundTripTimeout; + } + + if (peer->m_sentReliableCommands.empty()) + peer->m_nextTimeout = m_serviceTime + outgoingCommand->roundTripTimeout; + + peer->m_sentReliableCommands.emplace_back(std::move(*outgoingCommand)); + peer->m_outgoingReliableCommands.erase(outgoingCommand); + + outgoingCommand = peer->m_sentReliableCommands.end(); + --outgoingCommand; + + outgoingCommand->sentTime = m_serviceTime; + + ENetProtocol& command = m_commands[m_commandCount]; + NetBuffer& buffer = m_buffers[m_bufferCount]; + + buffer.data = &command; + buffer.dataLength = commandSize; + + m_packetSize += buffer.dataLength; + m_headerFlags |= ENetProtocolHeaderFlag_SentTime; + + command = outgoingCommand->command; + + if (outgoingCommand->packet) + { + ++m_bufferCount; + + NetBuffer& packetBuffer = m_buffers[m_bufferCount]; + packetBuffer.data = outgoingCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + outgoingCommand->fragmentOffset; + packetBuffer.dataLength = outgoingCommand->fragmentLength; + + m_packetSize += packetBuffer.dataLength; + + peer->m_reliableDataInTransit += outgoingCommand->fragmentLength; + } + + ++peer->m_packetsSent; + ++m_bufferCount; + ++m_commandCount; + } + + return canPing; + } + + int ENetHost::SendOutgoingCommands(ENetEvent* event, bool checkForTimeouts) + { + std::array headerData; + ENetProtocolHeader* header = reinterpret_cast(headerData.data()); + + m_continueSending = true; + + while (m_continueSending) + { + m_continueSending = false; + + for (std::size_t peer = 0; peer < m_peerCount; ++peer) + { + ENetPeer* currentPeer = &m_peers[peer]; + if (currentPeer->m_state == ENetPeerState::Disconnected || currentPeer->m_state == ENetPeerState::Zombie) + continue; + + m_headerFlags = 0; + m_commandCount = 0; + m_bufferCount = 1; + m_packetSize = sizeof(ENetProtocolHeader); + + if (!currentPeer->m_acknowledgements.empty()) + SendAcknowledgements(currentPeer); + + if (checkForTimeouts && !currentPeer->m_sentReliableCommands.empty() && ENET_TIME_GREATER_EQUAL(m_serviceTime, currentPeer->m_nextTimeout) && + CheckTimeouts(currentPeer, event)) + { + if (event && event->type != ENetEventType::None) + return 1; + else + continue; + } + + if ((currentPeer->m_outgoingReliableCommands.empty() || SendReliableOutgoingCommands(currentPeer)) && currentPeer->m_sentReliableCommands.empty() && + ENET_TIME_DIFFERENCE(m_serviceTime, currentPeer->m_lastReceiveTime) >= currentPeer->m_pingInterval && currentPeer->m_mtu - m_packetSize >= sizeof(ENetProtocolPing)) + { + currentPeer->Ping(); + SendReliableOutgoingCommands(currentPeer); + } + + if (!currentPeer->m_outgoingUnreliableCommands.empty()) + SendUnreliableOutgoingCommands(currentPeer); + + if (m_commandCount == 0) + continue; + + if (currentPeer->m_packetLossEpoch == 0) + currentPeer->m_packetLossEpoch = m_serviceTime; + else if (ENET_TIME_DIFFERENCE(m_serviceTime, currentPeer->m_packetLossEpoch) >= ENetPeer_PacketLossInterval && currentPeer->m_packetsSent > 0) + { + UInt32 packetLoss = currentPeer->m_packetsLost * ENetPeer_PacketLossScale / currentPeer->m_packetsSent; + + #ifdef ENET_DEBUG + printf("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer->incomingPeerID, currentPeer->packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer->packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer->roundTripTime, currentPeer->roundTripTimeVariance, currentPeer->packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size(¤tPeer->outgoingReliableCommands), enet_list_size(¤tPeer->outgoingUnreliableCommands), currentPeer->channels != NULL ? enet_list_size(¤tPeer->channels->incomingReliableCommands) : 0, currentPeer->channels != NULL ? enet_list_size(¤tPeer->channels->incomingUnreliableCommands) : 0); + #endif + + currentPeer->m_packetLossVariance -= currentPeer->m_packetLossVariance / 4; + + if (packetLoss >= currentPeer->m_packetLoss) + { + currentPeer->m_packetLoss += (packetLoss - currentPeer->m_packetLoss) / 8; + currentPeer->m_packetLossVariance += (packetLoss - currentPeer->m_packetLoss) / 4; + } + else + { + currentPeer->m_packetLoss -= (currentPeer->m_packetLoss - packetLoss) / 8; + currentPeer->m_packetLossVariance += (currentPeer->m_packetLoss - packetLoss) / 4; + } + + currentPeer->m_packetLossEpoch = m_serviceTime; + currentPeer->m_packetsSent = 0; + currentPeer->m_packetsLost = 0; + } + + + m_buffers[0].data = headerData.data(); + if (m_headerFlags & ENetProtocolHeaderFlag_SentTime) + { + header->sentTime = HostToNet(static_cast(m_serviceTime)); + + m_buffers[0].dataLength = sizeof(ENetProtocolHeader); + } + else + m_buffers[0].dataLength = NazaraOffsetOf(ENetProtocolHeader, sentTime); + + if (currentPeer->m_outgoingPeerID < ENetConstants::ENetProtocol_MaximumPeerId) + m_headerFlags |= currentPeer->m_outgoingSessionID << ENetProtocolHeaderSessionShift; + + header->peerID = HostToNet(static_cast(currentPeer->m_outgoingPeerID | m_headerFlags)); + + currentPeer->m_lastSendTime = m_serviceTime; + + std::size_t sentLength; + if (!m_socket.SendMultiple(currentPeer->m_address, m_buffers.data(), m_bufferCount, &sentLength)) + return -1; + + currentPeer->RemoveSentUnreliableCommands(); + + m_totalSentData += sentLength; + m_totalSentPackets++; + } + } + + return 0; + } + + void ENetHost::SendUnreliableOutgoingCommands(ENetPeer* peer) + { + auto currentCommand = peer->m_outgoingUnreliableCommands.begin(); + while (currentCommand != peer->m_outgoingUnreliableCommands.end()) + { + auto outgoingCommand = currentCommand; + + std::size_t commandSize = s_commandSizes[outgoingCommand->command.header.command & ENetProtocolCommand_Mask]; + + if (m_commandCount >= m_commands.size() || m_bufferCount + 1 >= m_buffers.size() || peer->m_mtu - m_packetSize < commandSize || + (outgoingCommand->packet && peer->m_mtu - m_packetSize < commandSize + outgoingCommand->fragmentLength)) + { + m_continueSending = true; + break; + } + + ++currentCommand; + + if (outgoingCommand->packet && outgoingCommand->fragmentOffset == 0) + { + peer->m_packetThrottleCounter += ENetConstants::ENetPeer_PacketThrottleCounter; + peer->m_packetThrottleCounter %= ENetConstants::ENetPeer_PacketThrottleScale; + + if (peer->m_packetThrottleCounter > peer->m_packetThrottle) + { + UInt16 reliableSequenceNumber = outgoingCommand->reliableSequenceNumber; + UInt16 unreliableSequenceNumber = outgoingCommand->unreliableSequenceNumber; + + for (;;) + { + peer->m_outgoingUnreliableCommands.erase(outgoingCommand); + + if (currentCommand == peer->m_outgoingUnreliableCommands.end()) + break; + + outgoingCommand = currentCommand; + if (outgoingCommand->reliableSequenceNumber != reliableSequenceNumber || outgoingCommand->unreliableSequenceNumber != unreliableSequenceNumber) + break; + + ++currentCommand; + } + + continue; + } + } + + ENetProtocol& command = m_commands[m_commandCount]; + NetBuffer& buffer = m_buffers[m_bufferCount]; + + buffer.data = &command; + buffer.dataLength = commandSize; + + command = outgoingCommand->command; + + if (outgoingCommand->packet) + { + ++m_bufferCount; + + NetBuffer& packetBuffer = m_buffers[m_bufferCount]; + packetBuffer.data = outgoingCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + outgoingCommand->fragmentOffset; + packetBuffer.dataLength = outgoingCommand->fragmentLength; + + m_packetSize += packetBuffer.dataLength; + + peer->m_sentUnreliableCommands.emplace_back(std::move(*outgoingCommand)); + } + + peer->m_outgoingUnreliableCommands.erase(outgoingCommand); + + ++m_bufferCount; + ++m_commandCount; + } + + if (peer->m_state == ENetPeerState::DisconnectLater && peer->m_outgoingReliableCommands.empty() && + peer->m_outgoingUnreliableCommands.empty() && peer->m_sentReliableCommands.empty()) + peer->Disconnect(peer->m_eventData); + } + void ENetHost::ThrottleBandwidth() { UInt32 currentTime = GetElapsedMilliseconds(); @@ -1108,6 +1720,11 @@ namespace Nz } } + std::size_t ENetHost::GetCommandSize(UInt8 commandNumber) + { + return s_commandSizes[commandNumber & ENetProtocolCommand_Mask]; + } + bool ENetHost::Initialize() { std::random_device device; diff --git a/src/Nazara/Network/ENetPacket.cpp b/src/Nazara/Network/ENetPacket.cpp index ec2bc4ab7..a22cc7fb8 100644 --- a/src/Nazara/Network/ENetPacket.cpp +++ b/src/Nazara/Network/ENetPacket.cpp @@ -1,11 +1,11 @@ -#include +#include #include #include namespace Nz { /// Temporary - void ENetPacketRef::Reset(ENetPacket* packet = nullptr) + void ENetPacketRef::Reset(ENetPacket* packet) { if (m_packet) { @@ -20,4 +20,4 @@ namespace Nz if (m_packet) m_packet->referenceCount++; } -} \ No newline at end of file +} diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 6f7f33312..2031755c4 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -1,7 +1,8 @@ -#include +#include #include #include #include +#include #include namespace Nz @@ -129,7 +130,7 @@ namespace Nz IncomingCommmand& incomingCommand = m_dispatchedCommands.front(); - m_totalWaitingData -= incomingCommand.packet->data.GetSize(); + m_totalWaitingData -= incomingCommand.packet->data.GetDataSize(); if (packet) *packet = std::move(incomingCommand.packet); @@ -192,7 +193,7 @@ namespace Nz m_eventData = 0; m_totalWaitingData = 0; - std::memset(m_unsequencedWindow, 0, sizeof(m_unsequencedWindow)); + m_unsequencedWindow.fill(0); ResetQueues(); } @@ -209,7 +210,7 @@ namespace Nz bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef) { - if (m_state != ENetPeerState::Connected || channelId >= m_channels.size() || packetRef->data.GetSize() > m_host->m_maximumPacketSize) + if (m_state != ENetPeerState::Connected || channelId >= m_channels.size() || packetRef->data.GetDataSize() > m_host->m_maximumPacketSize) return false; Channel& channel = m_channels[channelId]; @@ -218,7 +219,7 @@ namespace Nz //if (m_host->m_checksum != nullptr) // fragmentLength -= sizeof(UInt32); - UInt32 packetSize = static_cast(packetRef->data.GetSize()); + UInt32 packetSize = static_cast(packetRef->data.GetDataSize()); if (packetSize > fragmentLength) { UInt32 fragmentCount = (packetSize + fragmentLength - 1) / fragmentLength; @@ -254,7 +255,7 @@ namespace Nz OutgoingCommand outgoingCommand; outgoingCommand.fragmentOffset = fragmentOffset; - outgoingCommand.fragmentLength = fragmentLength; + outgoingCommand.fragmentLength = static_cast(fragmentLength); outgoingCommand.packet = packetRef; outgoingCommand.command.header.command = commandNumber; outgoingCommand.command.header.channelID = channelId; @@ -275,11 +276,20 @@ namespace Nz command.header.channelID = channelId; if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_Unsequenced)) == ENetPacketFlag_Unsequenced) + { command.header.command = ENetProtocolCommand_SendUnsequenced | ENetProtocolFlag_Unsequenced; + command.sendUnsequenced.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize())); + } else if (packetRef->flags & ENetPacketFlag_Reliable || channel.outgoingUnreliableSequenceNumber >= 0xFFFF) + { command.header.command = ENetProtocolCommand_SendReliable | ENetProtocolFlag_Acknowledge; + command.sendReliable.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize())); + } else + { command.header.command = ENetProtocolCommand_SendUnreliable; + command.sendUnreliable.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize())); + } QueueOutgoingCommand(command, packetRef, 0, packetSize); @@ -354,6 +364,13 @@ namespace Nz m_windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); } + void ENetPeer::DispatchState(ENetPeerState state) + { + ChangeState(state); + + m_host->AddToDispatchQueue(this); + } + void ENetPeer::DispatchIncomingReliableCommands(Channel& channel) { auto currentCommand = channel.incomingReliableCommands.begin(); @@ -375,7 +392,7 @@ namespace Nz channel.incomingUnreliableSequenceNumber = 0; - m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, channel.incomingReliableCommands.begin(), currentCommand); + m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingReliableCommands, channel.incomingReliableCommands.begin(), currentCommand); m_host->AddToDispatchQueue(this); @@ -408,7 +425,7 @@ namespace Nz if (startCommand != currentCommand) { - m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand); + m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingUnreliableCommands, startCommand, currentCommand); m_host->AddToDispatchQueue(this); @@ -436,7 +453,7 @@ namespace Nz if (startCommand != currentCommand) { - m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand); + m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingUnreliableCommands, startCommand, currentCommand); m_host->AddToDispatchQueue(this); } @@ -448,7 +465,7 @@ namespace Nz if (startCommand != currentCommand) { - m_dispatchedCommands.splice(m_dispatchedCommands.end(), m_dispatchedCommands, startCommand, currentCommand); + m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingUnreliableCommands, startCommand, currentCommand); m_host->AddToDispatchQueue(this); @@ -587,7 +604,7 @@ namespace Nz } Acknowledgement acknowledgment; - acknowledgment.command = command; + acknowledgment.command = *command; acknowledgment.sentTime = sentTime; m_outgoingDataTotal += sizeof(Acknowledgement); @@ -597,7 +614,7 @@ namespace Nz return true; } - ENetPeer::IncomingCommmand* ENetPeer::QueueIncomingCommand(ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount) + ENetPeer::IncomingCommmand* ENetPeer::QueueIncomingCommand(const ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount) { static IncomingCommmand dummyCommand; @@ -740,6 +757,9 @@ namespace Nz incomingCommand.fragments.resize(fragmentCount, 0); incomingCommand.fragmentsRemaining = fragmentCount; + if (packet) + m_totalWaitingData += packet->data.GetDataSize(); + auto it = commandList->insert(currentCommand.base(), incomingCommand); switch (command.header.command & ENetProtocolCommand_Mask) @@ -762,7 +782,7 @@ namespace Nz OutgoingCommand outgoingCommand; outgoingCommand.command = command; outgoingCommand.fragmentLength = length; - outgoingCommand.fragmentOffset = length; + outgoingCommand.fragmentOffset = offset; outgoingCommand.packet = packet; SetupOutgoingCommand(outgoingCommand); @@ -770,7 +790,7 @@ namespace Nz void ENetPeer::SetupOutgoingCommand(OutgoingCommand& outgoingCommand) { - m_outgoingDataTotal += enet_protocol_command_size(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength; + m_outgoingDataTotal += ENetHost::GetCommandSize(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength; if (outgoingCommand.command.header.channelID == 0xFF) { @@ -827,7 +847,7 @@ namespace Nz break; } - if (outgoingCommand.command.header.command & ENetProtocolCommand_Acknowledge) + if (outgoingCommand.command.header.command & ENetProtocolFlag_Acknowledge) m_outgoingReliableCommands.emplace_back(outgoingCommand); else m_outgoingUnreliableCommands.emplace_back(outgoingCommand); diff --git a/src/Nazara/Network/ENetSocket.cpp b/src/Nazara/Network/ENetSocket.cpp deleted file mode 100644 index e86313fb4..000000000 --- a/src/Nazara/Network/ENetSocket.cpp +++ /dev/null @@ -1,642 +0,0 @@ -// Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include - -namespace Nz -{ - /*! - * \ingroup network - * \class Nz::ENetConnection - * \brief Network class that represents a reliable UDP connection, based on ENet library - */ - - /*! - * \brief Constructs a RUdpConnection object by default - */ - - ENetSocket::ENetSocket() : - m_bandwidthThrottleEpoch(0), - m_mtu(ENetConstants::DefaultMTU), - m_isSimulationEnabled(false), - m_shouldAcceptConnections(true) - { - m_randomSeed = *reinterpret_cast(this); - m_randomSeed += s_randomGenerator(); - m_randomSeed = (m_randomSeed << 16) | (m_randomSeed >> 16); - - } - - /*! - * \brief Connects to the IpAddress - * \return true - * - * \param remoteAddress Address to connect to - * - * \remark Produces a NazaraAssert if socket is not bound - * \remark Produces a NazaraAssert if remote is invalid - * \remark Produces a NazaraAssert if port is not specified - */ - - bool RUdpConnection::Connect(const IpAddress& remoteAddress) - { - NazaraAssert(m_socket.GetState() == SocketState_Bound, "Socket must be bound first"); - NazaraAssert(remoteAddress.IsValid(), "Invalid remote address"); - NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port"); - - PeerData& client = RegisterPeer(remoteAddress, PeerState_Connecting); - client.stateData1 = s_randomGenerator(); - - NetPacket connectionRequestPacket(NetCode_RequestConnection); - connectionRequestPacket << client.stateData1; - - EnqueuePacket(client, PacketPriority_Immediate, PacketReliability_Reliable, connectionRequestPacket); - return true; - } - - /*! - * \brief Connects to the hostname - * \return true If successful - * - * \param hostName Hostname of the remote - * \param protocol Net protocol to use - * \param service Specify the protocol used - * \param error Optional argument to get the error - */ - - bool RUdpConnection::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error) - { - std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); - if (results.empty()) - { - m_lastError = SocketError_ResolveError; - return false; - } - - IpAddress hostnameAddress; - for (const HostnameInfo& result : results) - { - if (!result.address) - continue; - - if (result.socketType != SocketType_UDP) - continue; - - hostnameAddress = result.address; - break; //< Take first valid address - } - - return Connect(hostnameAddress); - } - - /*! - * \brief Listens to a socket - * \return true If successfully bound - * - * \param remoteAddress Address to listen to - */ - - bool RUdpConnection::Listen(const IpAddress& address) - { - if (!InitSocket(address.GetProtocol())) - return false; - - return m_socket.Bind(address) == SocketState_Bound; - } - - /*! - * \brief Polls the message - * \return true If there is a message - * - * \param message Message to poll - * - * \remark Produces a NazaraAssert if message is invalid - */ - - bool RUdpConnection::PollMessage(RUdpMessage* message) - { - NazaraAssert(message, "Invalid message"); - - if (m_receivedMessages.empty()) - return false; - - *message = std::move(m_receivedMessages.front()); - m_receivedMessages.pop(); - return true; - } - - /*! - * \brief Sends the packet to a peer - * \return true If peer exists (false may result from disconnected client) - * - * \param peerIp IpAddress of the peer - * \param priority Priority of the packet - * \param reliability Policy of reliability of the packet - * \param packet Packet to send - */ - - bool RUdpConnection::Send(const IpAddress& peerIp, PacketPriority priority, PacketReliability reliability, const NetPacket& packet) - { - auto it = m_peerByIP.find(peerIp); - if (it == m_peerByIP.end()) - return false; /// Silently fail (probably a disconnected client) - - EnqueuePacket(m_peers[it->second], priority, reliability, packet); - return true; - } - - /*! - * \brief Updates the reliable connection - */ - - void RUdpConnection::Update() - { - m_currentTime = m_clock.GetMicroseconds(); - - NetPacket receivedPacket; - IpAddress senderIp; - while (m_socket.ReceivePacket(&receivedPacket, &senderIp)) - OnPacketReceived(senderIp, std::move(receivedPacket)); - - //for (unsigned int i = m_activeClients.FindFirst(); i != m_activeClients.npos; i = m_activeClients.FindNext(i)) - //{ - // PeerData& clientData = m_peers[i]; - - CallOnExit resetIterator([this] () { m_peerIterator = m_peers.size(); }); - - for (m_peerIterator = 0; m_peerIterator < m_peers.size(); ++m_peerIterator) - { - PeerData& peer = m_peers[m_peerIterator]; - - UInt32 timeSinceLastPacket = static_cast(m_currentTime - peer.lastPacketTime); - if (timeSinceLastPacket > m_timeBeforeTimeOut) - { - DisconnectPeer(peer.index); - continue; - } - else if (timeSinceLastPacket > m_timeBeforePing) - { - if (m_currentTime - peer.lastPingTime > m_pingInterval) - { - NetPacket pingPacket(NetCode_Ping); - EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Unreliable, pingPacket); - } - } - - if (peer.state == PeerState_WillAck && m_currentTime - peer.stateData1 > m_forceAckSendTime) - { - NetPacket acknowledgePacket(NetCode_Acknowledge); - EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Reliable, acknowledgePacket); - } - - for (unsigned int priority = PacketPriority_Highest; priority <= PacketPriority_Lowest; ++priority) - { - std::vector& pendingPackets = peer.pendingPackets[priority]; - for (PendingPacket& packetData : pendingPackets) - SendPacket(peer, std::move(packetData)); - - pendingPackets.clear(); - } - - auto it = peer.pendingAckQueue.begin(); - while (it != peer.pendingAckQueue.end()) - { - if (m_currentTime - it->timeSent > 2 * peer.roundTripTime) - { - OnPacketLost(peer, std::move(*it)); - it = peer.pendingAckQueue.erase(it); - } - else - ++it; - } - } - //m_activeClients.Reset(); - } - - /*! - * \brief Disconnects a peer - * - * \param peerIndex Index of the peer - * - * \remark Produces a NazaraNotice - */ - - void RUdpConnection::DisconnectPeer(std::size_t peerIndex) - { - PeerData& peer = m_peers[peerIndex]; - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": " + peer.address.ToString() + " has been disconnected due to time-out"); - - OnPeerDisconnected(this, peer.address); - - // Remove from IP lookup table - m_peerByIP.erase(peer.address); - - // Can we safely "remove" this slot? - if (m_peerIterator >= m_peers.size() - 1 || peerIndex > m_peerIterator) - { - // Yes we can - PeerData& newSlot = m_peers[peerIndex]; - newSlot = std::move(m_peers.back()); - newSlot.index = peerIndex; //< Update the moved slot index before resizing (in case it's the last one) - } - else - { - // Nope, let's be tricky - PeerData& current = m_peers[m_peerIterator]; - PeerData& newSlot = m_peers[peerIndex]; - - newSlot = std::move(current); - newSlot.index = peerIndex; //< Update the moved slot index - - current = std::move(m_peers.back()); - current.index = m_peerIterator; //< Update the moved slot index - - --m_peerIterator; - } - - // Pop the last entry (from where we moved our slot) - m_peers.pop_back(); - } - - /*! - * \brief Enqueues a packet in the sending list - * - * \param peer Data relative to the peer - * \param priority Priority of the packet - * \param reliability Policy of reliability of the packet - * \param packet Packet to send - */ - - void RUdpConnection::EnqueuePacket(PeerData& peer, PacketPriority priority, PacketReliability reliability, const NetPacket& packet) - { - UInt16 protocolBegin = static_cast(m_protocol & 0xFFFF); - UInt16 protocolEnd = static_cast((m_protocol & 0xFFFF0000) >> 16); - - NetPacket data(packet.GetNetCode(), MessageHeader + packet.GetDataSize() + MessageFooter); - data << protocolBegin; - - data.GetStream()->SetCursorPos(NetPacket::HeaderSize + MessageHeader); - data.Write(packet.GetConstData() + NetPacket::HeaderSize, packet.GetDataSize()); - - data << protocolEnd; - EnqueuePacketInternal(peer, priority, reliability, std::move(data)); - } - - /*! - * \brief Enqueues internally a packet in the sending list - * - * \param peer Data relative to the peer - * \param priority Priority of the packet - * \param reliability Policy of reliability of the packet - * \param packet Packet to send - */ - - void RUdpConnection::EnqueuePacketInternal(PeerData& peer, PacketPriority priority, PacketReliability reliability, NetPacket&& data) - { - PendingPacket pendingPacket; - pendingPacket.data = std::move(data); - pendingPacket.priority = priority; - pendingPacket.reliability = reliability; - - peer.pendingPackets[priority].emplace_back(std::move(pendingPacket)); - m_activeClients.UnboundedSet(peer.index); - } - - /*! - * \brief Inits the internal socket - * \return true If successful - * - * \param protocol Net protocol to use - */ - - bool ENetSocket::InitSocket(NetProtocol protocol) - { - CallOnExit updateLastError([this] - { - m_lastError = m_socket.GetLastError(); - }); - - if (!m_socket.Create(protocol)) - return false; - - m_socket.EnableBlocking(false); - m_socket.SetReceiveBufferSize(ENetConstants::ReceiveBufferSize); - m_socket.SetSendBufferSize(ENetConstants::SendBufferSize); - - return true; - } - - /*! - * \brief Processes the acks - * - * \param peer Data relative to the peer - * \param lastAck Last index of the ack - * \param ackBits Bits for acking - */ - - void RUdpConnection::ProcessAcks(PeerData& peer, SequenceIndex lastAck, UInt32 ackBits) - { - auto it = peer.pendingAckQueue.begin(); - while (it != peer.pendingAckQueue.end()) - { - bool acked = false; - if (lastAck == it->sequenceId) - acked = true; - else if (!IsAckMoreRecent(it->sequenceId, lastAck)) - { - unsigned int difference = ComputeSequenceDifference(lastAck, it->sequenceId); - if (difference <= 32) - acked = (ackBits >> (difference - 1)) & 1; - } - - if (acked) - { - it = peer.pendingAckQueue.erase(it); - } - else - ++it; - } - } - - /*! - * \brief Registers a peer - * \return Data relative to the peer - * - * \param address Address of the peer - * \param state Status of the peer - */ - - RUdpConnection::PeerData& RUdpConnection::RegisterPeer(const IpAddress& address, PeerState state) - { - PeerData data; - data.address = address; - data.localSequence = 0; - data.remoteSequence = 0; - data.index = m_peers.size(); - data.lastPacketTime = m_currentTime; - data.lastPingTime = m_currentTime; - data.roundTripTime = 1'000'000; ///< Okay that's quite a lot - data.state = state; - - m_activeClients.UnboundedSet(data.index); - m_peerByIP[address] = data.index; - - m_peers.emplace_back(std::move(data)); - return m_peers.back(); - } - - /*! - * \brief Operation to do when client requests a connection - * - * \param address Address of the peer - * \param sequenceId Sequence index for the ack - * \param token Token for connection - */ - - void RUdpConnection::OnClientRequestingConnection(const IpAddress& address, SequenceIndex sequenceId, UInt64 token) - { - // Call hook to check if client should be accepted or not - OnPeerConnection(this, address); - - PeerData& client = RegisterPeer(address, PeerState_Aknowledged); - client.remoteSequence = sequenceId; - - /// Acknowledge connection - NetPacket connectionAcceptedPacket(NetCode_AcknowledgeConnection); - //connectionAcceptedPacket << address; - connectionAcceptedPacket << ~token; - - EnqueuePacket(client, PacketPriority_Immediate, PacketReliability_Reliable, connectionAcceptedPacket); - } - - /*! - * \brief Operation to do when a packet is lost - * - * \param peer Data relative to the peer - * \param packet Pending packet - */ - - void RUdpConnection::OnPacketLost(PeerData& peer, PendingAckPacket&& packet) - { - //NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Lost packet " + String::Number(packet.sequenceId)); - - if (IsReliable(packet.reliability)) - EnqueuePacketInternal(peer, packet.priority, packet.reliability, std::move(packet.data)); - } - - /*! - * \brief Operation to do when receiving a packet - * - * \param peerIndex Index of the peer - * - * \remark Produces a NazaraNotice - */ - - void RUdpConnection::OnPacketReceived(const IpAddress& peerIp, NetPacket&& packet) - { - UInt16 protocolBegin; - UInt16 protocolEnd; - SequenceIndex sequenceId; - SequenceIndex lastAck; - UInt32 ackBits; - - packet.GetStream()->SetCursorPos(packet.GetSize() - MessageFooter); - packet >> protocolEnd; - - packet.GetStream()->SetCursorPos(NetPacket::HeaderSize); - packet >> protocolBegin; - - UInt32 protocolId = static_cast(protocolEnd) << 16 | protocolBegin; - if (protocolId != m_protocol) - return; ///< Ignore - - packet >> sequenceId >> lastAck >> ackBits; - - auto it = m_peerByIP.find(peerIp); - if (it == m_peerByIP.end()) - { - switch (packet.GetNetCode()) - { - case NetCode_RequestConnection: - { - UInt64 token; - packet >> token; - - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_RequestConnection from " + peerIp.ToString() + ": " + String::Number(token)); - if (!m_shouldAcceptConnections) - return; //< Ignore - - OnClientRequestingConnection(peerIp, sequenceId, token); - break; - } - - default: - return; //< Ignore - } - } - else - { - PeerData& peer = m_peers[it->second]; - peer.lastPacketTime = m_currentTime; - - if (peer.receivedQueue.find(sequenceId) != peer.receivedQueue.end()) - return; //< Ignore - - if (m_isSimulationEnabled && m_packetLossProbability(s_randomGenerator)) - { - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Lost packet " + String::Number(sequenceId) + " from " + peerIp.ToString() + " for simulation purpose"); - return; - } - - ///< Receiving a packet from an acknowledged client means the connection works in both ways - if (peer.state == PeerState_Aknowledged && packet.GetNetCode() != NetCode_RequestConnection) - { - peer.state = PeerState_Connected; - OnPeerAcknowledged(this, peerIp); - } - - if (IsAckMoreRecent(sequenceId, peer.remoteSequence)) - peer.remoteSequence = sequenceId; - - ProcessAcks(peer, lastAck, ackBits); - - peer.receivedQueue.insert(sequenceId); - - switch (packet.GetNetCode()) - { - case NetCode_Acknowledge: - return; //< Do not switch to will ack mode (to prevent infinite replies, just let's ping/pong do that) - - case NetCode_AcknowledgeConnection: - { - if (peer.state == PeerState_Connected) - break; - - IpAddress externalAddress; - UInt64 token; - packet /*>> externalAddress*/ >> token; - - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_AcknowledgeConnection from " + peerIp.ToString() + ": " + String::Number(token)); - if (token == ~peer.stateData1) - { - peer.state = PeerState_Connected; - OnConnectedToPeer(this); - } - else - { - NazaraNotice("Received wrong token (" + String::Number(token) + " instead of " + String::Number(~peer.stateData1) + ") from client " + peer.address); - return; //< Ignore - } - - break; - } - - case NetCode_RequestConnection: - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_RequestConnection from " + peerIp.ToString()); - return; //< Ignore - - case NetCode_Ping: - { - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_Ping from " + peerIp.ToString()); - - NetPacket pongPacket(NetCode_Pong); - EnqueuePacket(peer, PacketPriority_Low, PacketReliability_Unreliable, pongPacket); - break; - } - - case NetCode_Pong: - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received NetCode_Pong from " + peerIp.ToString()); - break; - - default: - { - NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Received 0x" + String::Number(packet.GetNetCode(), 16) + " from " + peerIp.ToString()); - RUdpMessage receivedMessage; - receivedMessage.from = peerIp; - receivedMessage.data = std::move(packet); - - m_receivedMessages.emplace(std::move(receivedMessage)); - break; - } - } - - if (!HasPendingPackets(peer)) - { - peer.state = PeerState_WillAck; - peer.stateData1 = m_currentTime; - } - } - } - - /*! - * \brief Sends a packet to a peer - * - * \param peer Data relative to the peer - * \param packet Pending packet - */ - - void RUdpConnection::SendPacket(PeerData& peer, PendingPacket&& packet) - { - if (peer.state == PeerState_WillAck) - peer.state = PeerState_Connected; - - SequenceIndex remoteSequence = peer.remoteSequence; - - UInt32 previousAcks = 0; - for (SequenceIndex ack : peer.receivedQueue) - { - if (ack == remoteSequence) - continue; - - unsigned int difference = ComputeSequenceDifference(remoteSequence, ack); - if (difference <= 32U) - previousAcks |= (1U << (difference - 1)); - } - - SequenceIndex sequenceId = ++peer.localSequence; - - packet.data.GetStream()->SetCursorPos(NetPacket::HeaderSize + sizeof(UInt16)); ///< Protocol begin has already been filled - packet.data << sequenceId; - packet.data << remoteSequence; - packet.data << previousAcks; - - m_socket.SendPacket(peer.address, packet.data); - - PendingAckPacket pendingAckPacket; - pendingAckPacket.data = std::move(packet.data); - pendingAckPacket.priority = packet.priority; - pendingAckPacket.reliability = packet.reliability; - pendingAckPacket.sequenceId = sequenceId; - pendingAckPacket.timeSent = m_currentTime; - - peer.pendingAckQueue.emplace_back(std::move(pendingAckPacket)); - } - - /*! - * \brief Initializes the RUdpConnection class - * \return true - */ - - bool RUdpConnection::Initialize() - { - std::random_device device; - s_randomGenerator.seed(device()); - - return true; - } - - /*! - * \brief Uninitializes the RUdpConnection class - */ - - void RUdpConnection::Uninitialize() - { - } - - std::mt19937_64 RUdpConnection::s_randomGenerator; -} From 0e03aae6dcbae465ce69d65c5da1594eb0698565 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 27 Jan 2017 17:12:23 +0100 Subject: [PATCH 04/73] Network/ENetPeer: Fix compilation --- include/Nazara/Network/ENetPeer.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index e68b85de9..1099e4472 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -16,11 +16,9 @@ #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include namespace Nz { From 664e3a33ecab433978ca51bfe2013e377f51bf2f Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 27 Jan 2017 17:19:49 +0100 Subject: [PATCH 05/73] Network/ENet: Fix compilation and warnings --- src/Nazara/Network/ENetHost.cpp | 11 ++++------- src/Nazara/Network/ENetPeer.cpp | 6 +++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index ffe15635a..df77e25c9 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #define ENET_TIME_OVERFLOW 86400000 @@ -145,7 +144,7 @@ namespace Nz { std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); if (results.empty()) - return false; + return nullptr; IpAddress hostnameAddress; for (const HostnameInfo& result : results) @@ -558,7 +557,7 @@ namespace Nz return true; } - ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* header, ENetProtocol* command) + ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* /*header*/, ENetProtocol* command) { UInt32 channelCount = NetToHost(command->connect.channelCount); @@ -853,7 +852,7 @@ namespace Nz return commandError(); } - bool ENetHost::HandlePing(ENetPeer* peer, const ENetProtocol* command) + bool ENetHost::HandlePing(ENetPeer* peer, const ENetProtocol* /*command*/) { if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) return false; @@ -1071,7 +1070,7 @@ namespace Nz bool ENetHost::HandleSendUnsequenced(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) { - if (command->header.channelID >= peer->m_channels.size() || peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) return false; std::size_t dataLength = NetToHost(command->sendUnsequenced.dataLength); @@ -1230,8 +1229,6 @@ namespace Nz void ENetHost::SendAcknowledgements(ENetPeer* peer) { - std::cout << "SendAcknowledgements " << peer->m_acknowledgements.size() << std::endl; - auto currentAcknowledgement = peer->m_acknowledgements.begin(); while (currentAcknowledgement != peer->m_acknowledgements.end()) { diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 2031755c4..37afe8958 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -30,11 +30,11 @@ namespace Nz } ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : - m_packetPool(sizeof(ENetPacket)), m_host(host), - m_incomingPeerID(peerId), + m_packetPool(sizeof(ENetPacket)), m_incomingSessionID(0xFF), - m_outgoingSessionID(0xFF) + m_outgoingSessionID(0xFF), + m_incomingPeerID(peerId) { Reset(); } From 8fc734674dff80c25f36edd3565b7a273a04a669 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 11:06:09 +0100 Subject: [PATCH 06/73] Network/ENet: Fix fragments and cleanup --- include/Nazara/Network/ENetPeer.hpp | 18 ++++--- include/Nazara/Network/ENetPeer.inl | 15 ++++++ src/Nazara/Network/ENetHost.cpp | 82 ++++++++++++++--------------- src/Nazara/Network/ENetPeer.cpp | 19 +++---- 4 files changed, 73 insertions(+), 61 deletions(-) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 1099e4472..377d8f734 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -40,6 +40,11 @@ namespace Nz void DisconnectNow(UInt32 data); inline const IpAddress& GetAddress() const; + inline ENetPeerState GetState() const; + + inline bool HasPendingCommands(); + + inline bool IsConnected() const; void Ping(); @@ -116,12 +121,12 @@ namespace Nz struct IncomingCommmand { - ENetProtocol command; - UInt16 reliableSequenceNumber; - UInt16 unreliableSequenceNumber; - UInt32 fragmentsRemaining; - std::vector fragments; - ENetPacketRef packet; + ENetProtocol command; + Bitset<> fragments; + ENetPacketRef packet; + UInt16 reliableSequenceNumber; + UInt16 unreliableSequenceNumber; + UInt32 fragmentsRemaining; }; struct OutgoingCommand @@ -152,7 +157,6 @@ namespace Nz std::size_t m_totalWaitingData; std::vector m_channels; MemoryPool m_packetPool; - //ENetListNode m_dispatchList; ENetPeerState m_state; UInt8 m_incomingSessionID; UInt8 m_outgoingSessionID; diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index 2c7044b6e..5c0f76731 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -13,6 +13,21 @@ namespace Nz return m_address; } + inline ENetPeerState ENetPeer::GetState() const + { + return m_state; + } + + inline bool ENetPeer::HasPendingCommands() + { + return m_outgoingReliableCommands.empty() && m_outgoingUnreliableCommands.empty() && m_sentReliableCommands.empty(); + } + + inline bool ENetPeer::IsConnected() const + { + return m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater; + } + inline void ENetPeer::ChangeState(ENetPeerState state) { if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index df77e25c9..a6e98a0c4 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -69,7 +69,7 @@ namespace Nz for (ENetPeer& peer : m_peers) { - if (peer.m_state != ENetPeerState::Connected) + if (peer.GetState() != ENetPeerState::Connected) continue; peer.Send(channelId, enetPacket); @@ -96,7 +96,7 @@ namespace Nz std::size_t peerId; for (peerId = 0; peerId < m_peers.size(); ++peerId) { - if (m_peers[peerId].m_state == ENetPeerState::Disconnected) + if (m_peers[peerId].GetState() == ENetPeerState::Disconnected) break; } @@ -403,7 +403,7 @@ namespace Nz m_dispatchQueue.Reset(bit); ENetPeer& peer = m_peers[bit]; - switch (peer.m_state) + switch (peer.GetState()) { case ENetPeerState::ConnectionPending: case ENetPeerState::ConnectionSucceeded: @@ -449,7 +449,7 @@ namespace Nz bool ENetHost::HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command) { - if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie) + if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie) return true; UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); @@ -499,7 +499,7 @@ namespace Nz ENetProtocolCommand commandNumber = peer->RemoveSentReliableCommand(receivedReliableSequenceNumber, command->header.channelID); - switch (peer->m_state) + switch (peer->GetState()) { case ENetPeerState::AcknowledgingConnect: if (commandNumber != ENetProtocolCommand_VerifyConnect) @@ -516,7 +516,7 @@ namespace Nz break; case ENetPeerState::DisconnectLater: - if (peer->m_outgoingReliableCommands.empty() && peer->m_outgoingUnreliableCommands.empty() && peer->m_sentReliableCommands.empty()) + if (!peer->HasPendingCommands()) peer->Disconnect(peer->m_eventData); break; @@ -530,7 +530,7 @@ namespace Nz bool ENetHost::HandleBandwidthLimit(ENetPeer* peer, const ENetProtocol* command) { - if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + if (!peer->IsConnected()) return false; if (peer->m_incomingBandwidth != 0) @@ -568,12 +568,12 @@ namespace Nz ENetPeer* peer = nullptr; for (ENetPeer& currentPeer : m_peers) { - if (currentPeer.m_state == ENetPeerState::Disconnected) + if (currentPeer.GetState() == ENetPeerState::Disconnected) { if (!peer) peer = ¤tPeer; } - else if (currentPeer.m_state != ENetPeerState::Connecting) + else if (currentPeer.GetState() != ENetPeerState::Connecting) { // Compare users without comparing their port IpAddress first(currentPeer.m_address); @@ -631,18 +631,18 @@ namespace Nz bool ENetHost::HandleDisconnect(ENetPeer* peer, const ENetProtocol * command) { - if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie || peer->m_state == ENetPeerState::AcknowledgingDisconnect) + if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie || peer->GetState() == ENetPeerState::AcknowledgingDisconnect) return true; peer->ResetQueues(); - if (peer->m_state == ENetPeerState::ConnectionSucceeded || peer->m_state == ENetPeerState::Disconnecting || peer->m_state == ENetPeerState::Connecting) + if (peer->GetState() == ENetPeerState::ConnectionSucceeded || peer->GetState() == ENetPeerState::Disconnecting || peer->GetState() == ENetPeerState::Connecting) peer->DispatchState(ENetPeerState::Zombie); else { - if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + if (!peer->IsConnected()) { - if (peer->m_state == ENetPeerState::ConnectionPending) + if (peer->GetState() == ENetPeerState::ConnectionPending) m_recalculateBandwidthLimits = true; peer->Reset(); @@ -654,7 +654,7 @@ namespace Nz peer->DispatchState(ENetPeerState::Zombie); } - if (peer->m_state != ENetPeerState::Disconnected) + if (peer->GetState() != ENetPeerState::Disconnected) peer->m_eventData = NetToHost(command->disconnect.data); return true; @@ -685,7 +685,7 @@ namespace Nz { peer = &m_peers[peerID]; - if (peer->m_state == ENetPeerState::Disconnected || peer->m_state == ENetPeerState::Zombie) + if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie) return false; if (m_receivedAddress != peer->m_address && peer->m_address != IpAddress::BroadcastIpV4) @@ -829,7 +829,7 @@ namespace Nz sentTime = NetToHost(header->sentTime); - switch (peer->m_state) + switch (peer->GetState()) { case ENetPeerState::Disconnecting: case ENetPeerState::AcknowledgingConnect: @@ -854,7 +854,7 @@ namespace Nz bool ENetHost::HandlePing(ENetPeer* peer, const ENetProtocol* /*command*/) { - if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + if (!peer->IsConnected()) return false; return true; @@ -862,7 +862,7 @@ namespace Nz bool ENetHost::HandleSendFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) { - if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) + if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) return false; UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); @@ -909,7 +909,7 @@ namespace Nz break; if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendFragment || - totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.size()) + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) return false; startCommand = &incomingCommand; @@ -926,11 +926,11 @@ namespace Nz return false; } - if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) + if (!startCommand->fragments.Test(fragmentNumber)) { --startCommand->fragmentsRemaining; - startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + startCommand->fragments.Set(fragmentNumber); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; @@ -946,7 +946,7 @@ namespace Nz bool ENetHost::HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) { - if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) + if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) return false; UInt16 dataLength = NetToHost(command->sendReliable.dataLength); @@ -962,7 +962,7 @@ namespace Nz bool ENetHost::HandleSendUnreliable(ENetPeer * peer, const ENetProtocol * command, UInt8 ** currentData) { - if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) + if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) return false; UInt16 dataLength = NetToHost(command->sendUnreliable.dataLength); @@ -978,7 +978,7 @@ namespace Nz bool ENetHost::HandleSendUnreliableFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) { - if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) + if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) return false; UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); @@ -1050,11 +1050,11 @@ namespace Nz return false; } - if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) + if (!startCommand->fragments.Test(fragmentNumber)) { --startCommand->fragmentsRemaining; - startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + startCommand->fragments.Set(fragmentNumber); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; @@ -1070,7 +1070,7 @@ namespace Nz bool ENetHost::HandleSendUnsequenced(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) { - if (command->header.channelID >= peer->m_channels.size() || (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater)) + if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) return false; std::size_t dataLength = NetToHost(command->sendUnsequenced.dataLength); @@ -1108,7 +1108,7 @@ namespace Nz bool ENetHost::HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command) { - if (peer->m_state != ENetPeerState::Connected && peer->m_state != ENetPeerState::DisconnectLater) + if (!peer->IsConnected()) return false; peer->m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); @@ -1120,7 +1120,7 @@ namespace Nz bool ENetHost::HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command) { - if (peer->m_state != ENetPeerState::Connecting) + if (peer->GetState() != ENetPeerState::Connecting) return false; UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); @@ -1201,15 +1201,15 @@ namespace Nz event->data = peer->m_eventData; } else - peer->DispatchState(peer->m_state == ENetPeerState::Connecting ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); + peer->DispatchState(peer->GetState() == ENetPeerState::Connecting ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); } void ENetHost::NotifyDisconnect(ENetPeer* peer, ENetEvent* event) { - if (peer->m_state >= ENetPeerState::ConnectionPending) + if (peer->GetState() >= ENetPeerState::ConnectionPending) m_recalculateBandwidthLimits = true; - if (peer->m_state != ENetPeerState::Connecting && (peer->m_state < ENetPeerState::ConnectionSucceeded)) + if (peer->GetState() != ENetPeerState::Connecting && (peer->GetState() < ENetPeerState::ConnectionSucceeded)) peer->Reset(); else if (event) { @@ -1394,7 +1394,7 @@ namespace Nz for (std::size_t peer = 0; peer < m_peerCount; ++peer) { ENetPeer* currentPeer = &m_peers[peer]; - if (currentPeer->m_state == ENetPeerState::Disconnected || currentPeer->m_state == ENetPeerState::Zombie) + if (currentPeer->GetState() == ENetPeerState::Disconnected || currentPeer->GetState() == ENetPeerState::Zombie) continue; m_headerFlags = 0; @@ -1560,8 +1560,7 @@ namespace Nz ++m_commandCount; } - if (peer->m_state == ENetPeerState::DisconnectLater && peer->m_outgoingReliableCommands.empty() && - peer->m_outgoingUnreliableCommands.empty() && peer->m_sentReliableCommands.empty()) + if (peer->GetState() == ENetPeerState::DisconnectLater && !peer->HasPendingCommands()) peer->Disconnect(peer->m_eventData); } @@ -1588,7 +1587,7 @@ namespace Nz dataTotal = 0; for (ENetPeer& peer : m_peers) { - if (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) + if (peer.IsConnected()) continue; dataTotal += peer.m_outgoingDataTotal; @@ -1611,8 +1610,7 @@ namespace Nz for (ENetPeer& peer : m_peers) { - if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || - peer.m_incomingBandwidth == 0 || peer.m_outgoingBandwidthThrottleEpoch == currentTime) + if (!peer.IsConnected() || peer.m_incomingBandwidth == 0 || peer.m_outgoingBandwidthThrottleEpoch == currentTime) continue; UInt32 peerBandwidth = (peer.m_incomingBandwidth * elapsedTime) / 1000; @@ -1648,8 +1646,7 @@ namespace Nz for (ENetPeer& peer : m_peers) { - if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || - peer.m_outgoingBandwidthThrottleEpoch == currentTime) + if (!peer.IsConnected() || peer.m_outgoingBandwidthThrottleEpoch == currentTime) continue; peer.m_packetThrottleLimit = throttle; @@ -1681,8 +1678,7 @@ namespace Nz for (ENetPeer& peer : m_peers) { - if ((peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) || - peer.m_incomingBandwidthThrottleEpoch == currentTime) + if (!peer.IsConnected() || peer.m_incomingBandwidthThrottleEpoch == currentTime) continue; if (peer.m_outgoingBandwidth > 0 && peer.m_outgoingBandwidth >= bandwidthLimit) @@ -1699,7 +1695,7 @@ namespace Nz for (ENetPeer& peer : m_peers) { - if (peer.m_state != ENetPeerState::Connected && peer.m_state != ENetPeerState::DisconnectLater) + if (!peer.IsConnected()) continue; ENetProtocol command; diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 37afe8958..38025108f 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -54,14 +54,14 @@ namespace Nz command.header.channelID = 0xFF; command.disconnect.data = HostToNet(data); - if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + if (IsConnected()) command.header.command |= ENetProtocolFlag_Acknowledge; else command.header.command |= ENetProtocolFlag_Unsequenced; QueueOutgoingCommand(command, nullptr, 0, 0); - if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + if (IsConnected()) { OnDisconnect(); @@ -77,10 +77,7 @@ namespace Nz void ENetPeer::DisconnectLater(UInt32 data) { - if ((m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) && - !m_outgoingReliableCommands.empty() && - !m_outgoingUnreliableCommands.empty() && - !m_sentReliableCommands.empty()) + if (IsConnected() && !m_outgoingReliableCommands.empty() && !m_outgoingUnreliableCommands.empty() && !m_sentReliableCommands.empty()) { m_state = ENetPeerState::DisconnectLater; m_eventData = data; @@ -383,8 +380,8 @@ namespace Nz channel.incomingReliableSequenceNumber = incomingCommand.reliableSequenceNumber; - if (!incomingCommand.fragments.empty()) - channel.incomingReliableSequenceNumber += incomingCommand.fragments.size() - 1; + if (incomingCommand.fragments.GetSize() == 0) + channel.incomingReliableSequenceNumber += incomingCommand.fragments.GetSize() - 1; } if (currentCommand == channel.incomingReliableCommands.begin()) @@ -477,7 +474,7 @@ namespace Nz void ENetPeer::OnConnect() { - if (m_state != ENetPeerState::Connected && m_state != ENetPeerState::DisconnectLater) + if (!IsConnected()) { if (m_incomingBandwidth != 0) ++m_host->m_bandwidthLimitedPeers; @@ -488,7 +485,7 @@ namespace Nz void ENetPeer::OnDisconnect() { - if (m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater) + if (IsConnected()) { if (m_incomingBandwidth != 0) --m_host->m_bandwidthLimitedPeers; @@ -754,7 +751,7 @@ namespace Nz incomingCommand.unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; incomingCommand.command = command; incomingCommand.packet = packet; - incomingCommand.fragments.resize(fragmentCount, 0); + incomingCommand.fragments.Resize(fragmentCount); incomingCommand.fragmentsRemaining = fragmentCount; if (packet) From c9d5f2f1ac449f4026b16f02bbf87e253f975eaf Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 12:08:35 +0100 Subject: [PATCH 07/73] Network/ENet: More cleanup --- include/Nazara/Network/ENetHost.hpp | 2 - include/Nazara/Network/ENetPeer.hpp | 5 +- include/Nazara/Network/ENetPeer.inl | 5 + include/Nazara/Network/ENetProtocol.hpp | 8 ++ src/Nazara/Network/ENetHost.cpp | 89 ++----------- src/Nazara/Network/ENetPeer.cpp | 158 +++++++++++++++--------- 6 files changed, 130 insertions(+), 137 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 3b86a1f25..344ffce82 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -64,8 +64,6 @@ namespace Nz void AddToDispatchQueue(ENetPeer* peer); void RemoveFromDispatchQueue(ENetPeer* peer); - bool CheckTimeouts(ENetPeer* peer, ENetEvent* event); - bool DispatchIncomingCommands(ENetEvent* event); bool HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command); diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 377d8f734..7ccaf3d8d 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -68,8 +68,10 @@ namespace Nz struct IncomingCommmand; struct OutgoingCommand; - // Protocol functions inline void ChangeState(ENetPeerState state); + + bool CheckTimeouts(ENetEvent* event); + void DispatchState(ENetPeerState state); void DispatchIncomingReliableCommands(Channel& channel); @@ -85,6 +87,7 @@ namespace Nz bool QueueAcknowledgement(ENetProtocol* command, UInt16 sentTime); IncomingCommmand* QueueIncomingCommand(const ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount); + inline void QueueOutgoingCommand(ENetProtocol& command); void QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length); void SetupOutgoingCommand(OutgoingCommand& outgoingCommand); diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index 5c0f76731..1e74e0cae 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -37,6 +37,11 @@ namespace Nz m_state = state; } + + inline void ENetPeer::QueueOutgoingCommand(ENetProtocol& command) + { + QueueOutgoingCommand(command, ENetPacketRef(), 0, 0); + } } #include diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp index 8b62f7dc7..0434cafc2 100644 --- a/include/Nazara/Network/ENetProtocol.hpp +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -267,6 +267,14 @@ namespace Nz union NAZARA_PACKED ENetProtocol { + ENetProtocol() = default; + + ENetProtocol(UInt8 command, UInt8 channel) + { + header.command = command; + header.channelID = channel; + } + ENetProtocolCommandHeader header; ENetProtocolAcknowledge acknowledge; ENetProtocolBandwidthLimit bandwidthLimit; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index a6e98a0c4..afa870b12 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -117,10 +117,7 @@ namespace Nz ENetPeer& peer = m_peers[peerId]; peer.InitOutgoing(channelCount, remoteAddress, ++m_randomSeed, windowSize); - ENetProtocol command; - command.header.command = ENetProtocolCommand_Connect | ENetProtocolFlag_Acknowledge; - command.header.channelID = 0xFF; - + ENetProtocol command(ENetProtocolCommand_Connect | ENetProtocolFlag_Acknowledge, 0xFF); command.connect.channelCount = HostToNet(static_cast(channelCount)); command.connect.connectID = peer.m_connectID; command.connect.data = HostToNet(data); @@ -134,8 +131,7 @@ namespace Nz command.connect.packetThrottleDeceleration = HostToNet(peer.m_packetThrottleDeceleration); command.connect.packetThrottleInterval = HostToNet(peer.m_packetThrottleInterval); command.connect.windowSize = HostToNet(peer.m_windowSize); - - peer.QueueOutgoingCommand(command, nullptr, 0, 0); + peer.QueueOutgoingCommand(command); return &peer; } @@ -350,52 +346,6 @@ namespace Nz m_dispatchQueue.UnboundedReset(peer->m_incomingPeerID); } - bool ENetHost::CheckTimeouts(ENetPeer* peer, ENetEvent* event) - { - auto currentCommand = peer->m_sentReliableCommands.begin(); - - while (currentCommand != peer->m_sentReliableCommands.end()) - { - auto outgoingCommand = currentCommand; - - ++currentCommand; - - if (ENET_TIME_DIFFERENCE(m_serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) - continue; - - if (peer->m_earliestTimeout == 0 || ENET_TIME_LESS(outgoingCommand->sentTime, peer->m_earliestTimeout)) - peer->m_earliestTimeout = outgoingCommand->sentTime; - - if (peer->m_earliestTimeout != 0 && (ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_earliestTimeout) >= peer->m_timeoutMaximum || - (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_earliestTimeout) >= peer->m_timeoutMinimum))) - { - NotifyDisconnect(peer, event); - return true; - } - - if (outgoingCommand->packet) - peer->m_reliableDataInTransit -= outgoingCommand->fragmentLength; - - ++peer->m_packetsLost; - - outgoingCommand->roundTripTimeout *= 2; - - peer->m_outgoingReliableCommands.emplace_front(std::move(*outgoingCommand)); - peer->m_sentReliableCommands.erase(outgoingCommand); - - // Okay this should just never procs, I don't see how it would be possible - /*if (currentCommand == enet_list_begin(&peer->sentReliableCommands) && - !enet_list_empty(&peer->sentReliableCommands)) - { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - peer->nextTimeout = outgoingCommand->sentTime + outgoingCommand->roundTripTimeout; - }*/ - } - - return false; - } - bool ENetHost::DispatchIncomingCommands(ENetEvent* event) { for (std::size_t bit = m_dispatchQueue.FindFirst(); bit != m_dispatchQueue.npos; bit = m_dispatchQueue.FindNext(bit)) @@ -608,9 +558,7 @@ namespace Nz windowSize = std::max(windowSize, NetToHost(command->connect.windowSize)); windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); - ENetProtocol verifyCommand; - verifyCommand.header.command = ENetProtocolCommand_VerifyConnect | ENetProtocolFlag_Acknowledge; - verifyCommand.header.channelID = 0xFF; + ENetProtocol verifyCommand(ENetProtocolCommand_VerifyConnect | ENetProtocolFlag_Acknowledge, 0xFF); verifyCommand.verifyConnect.outgoingPeerID = HostToNet(peer->m_incomingPeerID); verifyCommand.verifyConnect.incomingSessionID = peer->m_outgoingSessionID; verifyCommand.verifyConnect.outgoingSessionID = peer->m_incomingSessionID; @@ -623,8 +571,7 @@ namespace Nz verifyCommand.verifyConnect.packetThrottleAcceleration = HostToNet(peer->m_packetThrottleAcceleration); verifyCommand.verifyConnect.packetThrottleDeceleration = HostToNet(peer->m_packetThrottleDeceleration); verifyCommand.verifyConnect.connectID = peer->m_connectID; - - peer->QueueOutgoingCommand(verifyCommand, nullptr, 0, 0); + peer->QueueOutgoingCommand(verifyCommand); return peer; } @@ -930,7 +877,7 @@ namespace Nz { --startCommand->fragmentsRemaining; - startCommand->fragments.Set(fragmentNumber); + startCommand->fragments.Set(fragmentNumber, true); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; @@ -1036,7 +983,7 @@ namespace Nz break; if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnreliableFragment || - totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.size()) + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) return false; startCommand = &incomingCommand; @@ -1054,7 +1001,7 @@ namespace Nz { --startCommand->fragmentsRemaining; - startCommand->fragments.Set(fragmentNumber); + startCommand->fragments.Set(fragmentNumber, true); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; @@ -1405,8 +1352,7 @@ namespace Nz if (!currentPeer->m_acknowledgements.empty()) SendAcknowledgements(currentPeer); - if (checkForTimeouts && !currentPeer->m_sentReliableCommands.empty() && ENET_TIME_GREATER_EQUAL(m_serviceTime, currentPeer->m_nextTimeout) && - CheckTimeouts(currentPeer, event)) + if (checkForTimeouts && !currentPeer->m_sentReliableCommands.empty() && ENET_TIME_GREATER_EQUAL(m_serviceTime, currentPeer->m_nextTimeout) && currentPeer->CheckTimeouts(event)) { if (event && event->type != ENetEventType::None) return 1; @@ -1617,14 +1563,7 @@ namespace Nz if ((throttle * peer.m_outgoingDataTotal) / ENetConstants::ENetPeer_PacketThrottleScale <= peerBandwidth) continue; - peer.m_packetThrottleLimit = (peerBandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / peer.m_outgoingDataTotal; - - if (peer.m_packetThrottleLimit == 0) - peer.m_packetThrottleLimit = 1; - - if (peer.m_packetThrottle > peer.m_packetThrottleLimit) - peer.m_packetThrottle = peer.m_packetThrottleLimit; - + peer.m_packetThrottleLimit = Clamp((peerBandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / peer.m_outgoingDataTotal, 0, peer.m_packetThrottleLimit); peer.m_outgoingBandwidthThrottleEpoch = currentTime; peer.m_incomingDataTotal = 0; @@ -1650,9 +1589,7 @@ namespace Nz continue; peer.m_packetThrottleLimit = throttle; - - if (peer.m_packetThrottle > peer.m_packetThrottleLimit) - peer.m_packetThrottle = peer.m_packetThrottleLimit; + peer.m_packetThrottle = std::min(peer.m_packetThrottle, peer.m_packetThrottleLimit); peer.m_incomingDataTotal = 0; peer.m_outgoingDataTotal = 0; @@ -1698,9 +1635,7 @@ namespace Nz if (!peer.IsConnected()) continue; - ENetProtocol command; - command.header.command = ENetProtocolCommand_BandwidthLimit | ENetProtocolFlag_Acknowledge; - command.header.channelID = 0xFF; + ENetProtocol command(ENetProtocolCommand_BandwidthLimit | ENetProtocolFlag_Acknowledge, 0xFF); command.bandwidthLimit.outgoingBandwidth = HostToNet(m_outgoingBandwidth); if (peer.m_incomingBandwidthThrottleEpoch == currentTime) @@ -1708,7 +1643,7 @@ namespace Nz else command.bandwidthLimit.incomingBandwidth = HostToNet(bandwidthLimit); - peer.QueueOutgoingCommand(command, nullptr, 0, 0); + peer.QueueOutgoingCommand(command); } } } diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 38025108f..e444a4d02 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -5,6 +5,15 @@ #include #include +#define ENET_TIME_OVERFLOW 86400000 + +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) + +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + namespace Nz { /// Temporary @@ -49,9 +58,7 @@ namespace Nz ResetQueues(); - ENetProtocol command; - command.header.command = ENetProtocolCommand_Disconnect; - command.header.channelID = 0xFF; + ENetProtocol command(ENetProtocolCommand_Disconnect, 0xFF); command.disconnect.data = HostToNet(data); if (IsConnected()) @@ -59,7 +66,7 @@ namespace Nz else command.header.command |= ENetProtocolFlag_Unsequenced; - QueueOutgoingCommand(command, nullptr, 0, 0); + QueueOutgoingCommand(command); if (IsConnected()) { @@ -95,12 +102,9 @@ namespace Nz { ResetQueues(); - ENetProtocol command; - command.header.command = ENetProtocolCommand_Disconnect | ENetProtocolFlag_Unsequenced; - command.header.channelID = 0xFF; + ENetProtocol command(ENetProtocolCommand_Disconnect | ENetProtocolFlag_Unsequenced, 0xFF); command.disconnect.data = HostToNet(data); - - QueueOutgoingCommand(command, nullptr, 0, 0); + QueueOutgoingCommand(command); m_host->Flush(); } @@ -116,8 +120,7 @@ namespace Nz ENetProtocol command; command.header.command = ENetProtocolCommand_Ping | ENetProtocolFlag_Acknowledge; command.header.channelID = 0xFF; - - QueueOutgoingCommand(command, nullptr, 0, 0); + QueueOutgoingCommand(command); } bool ENetPeer::Receive(ENetPacketRef* packet, UInt8* channelId) @@ -299,66 +302,56 @@ namespace Nz m_packetThrottleAcceleration = acceleration; m_packetThrottleDeceleration = deceleration; - ENetProtocol command; - command.header.command = ENetProtocolCommand_ThrottleConfigure | ENetProtocolFlag_Acknowledge; - command.header.channelID = 0xFF; - + ENetProtocol command(ENetProtocolCommand_ThrottleConfigure | ENetProtocolFlag_Acknowledge, 0xFF); command.throttleConfigure.packetThrottleInterval = HostToNet(interval); command.throttleConfigure.packetThrottleAcceleration = HostToNet(acceleration); command.throttleConfigure.packetThrottleDeceleration = HostToNet(deceleration); - - QueueOutgoingCommand(command, nullptr, 0, 0); + QueueOutgoingCommand(command); } - void ENetPeer::InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand) + bool ENetPeer::CheckTimeouts(ENetEvent* event) { - m_channels.resize(channelCount); - m_address = address; + auto currentCommand = m_sentReliableCommands.begin(); + while (currentCommand != m_sentReliableCommands.end()) + { + auto outgoingCommand = currentCommand; - m_connectID = incomingCommand.connectID; - m_eventData = NetToHost(incomingCommand.data); - m_incomingBandwidth = NetToHost(incomingCommand.incomingBandwidth); - m_outgoingBandwidth = NetToHost(incomingCommand.outgoingBandwidth); - m_packetThrottleInterval = NetToHost(incomingCommand.packetThrottleInterval); - m_packetThrottleAcceleration = NetToHost(incomingCommand.packetThrottleAcceleration); - m_packetThrottleDeceleration = NetToHost(incomingCommand.packetThrottleDeceleration); - m_outgoingPeerID = NetToHost(incomingCommand.outgoingPeerID); - m_state = ENetPeerState::AcknowledgingConnect; + ++currentCommand; - UInt8 incomingSessionId, outgoingSessionId; + if (ENET_TIME_DIFFERENCE(m_host->m_serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) + continue; - incomingSessionId = incomingCommand.incomingSessionID == 0xFF ? m_outgoingSessionID : incomingCommand.incomingSessionID; - incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); - if (incomingSessionId == m_outgoingSessionID) - incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); - m_outgoingSessionID = incomingSessionId; + if (m_earliestTimeout == 0 || ENET_TIME_LESS(outgoingCommand->sentTime, m_earliestTimeout)) + m_earliestTimeout = outgoingCommand->sentTime; - outgoingSessionId = incomingCommand.outgoingSessionID == 0xFF ? m_incomingSessionID : incomingCommand.outgoingSessionID; - outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); - if (outgoingSessionId == m_incomingSessionID) - outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); - m_incomingSessionID = outgoingSessionId; + if (m_earliestTimeout != 0 && (ENET_TIME_DIFFERENCE(m_host->m_serviceTime, m_earliestTimeout) >= m_timeoutMaximum || + (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENET_TIME_DIFFERENCE(m_host->m_serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) + { + m_host->NotifyDisconnect(this, event); + return true; + } - m_mtu = Clamp(NetToHost(incomingCommand.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + if (outgoingCommand->packet) + m_reliableDataInTransit -= outgoingCommand->fragmentLength; - if (m_host->m_outgoingBandwidth == 0 && m_incomingBandwidth == 0) - m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; - else if (m_host->m_outgoingBandwidth == 0 || m_incomingBandwidth == 0) - m_windowSize = (std::max(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; - else - m_windowSize = (std::min(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + ++m_packetsLost; - m_windowSize = Clamp(m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); - } + outgoingCommand->roundTripTimeout *= 2; - void ENetPeer::InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize) - { - m_channels.resize(channelCount); + m_outgoingReliableCommands.emplace_front(std::move(*outgoingCommand)); + m_sentReliableCommands.erase(outgoingCommand); - m_address = address; - m_connectID = connectId; - m_state = ENetPeerState::Connecting; - m_windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + // Okay this should just never procs, I don't see how it would be possible + /*if (currentCommand == enet_list_begin(&peer->sentReliableCommands) && + !enet_list_empty(&peer->sentReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + peer->nextTimeout = outgoingCommand->sentTime + outgoingCommand->roundTripTimeout; + }*/ + } + + return false; } void ENetPeer::DispatchState(ENetPeerState state) @@ -472,6 +465,57 @@ namespace Nz channel.incomingUnreliableCommands.erase(channel.incomingUnreliableCommands.begin(), droppedCommand); } + void ENetPeer::InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand) + { + m_channels.resize(channelCount); + m_address = address; + + m_connectID = incomingCommand.connectID; + m_eventData = NetToHost(incomingCommand.data); + m_incomingBandwidth = NetToHost(incomingCommand.incomingBandwidth); + m_outgoingBandwidth = NetToHost(incomingCommand.outgoingBandwidth); + m_packetThrottleInterval = NetToHost(incomingCommand.packetThrottleInterval); + m_packetThrottleAcceleration = NetToHost(incomingCommand.packetThrottleAcceleration); + m_packetThrottleDeceleration = NetToHost(incomingCommand.packetThrottleDeceleration); + m_outgoingPeerID = NetToHost(incomingCommand.outgoingPeerID); + m_state = ENetPeerState::AcknowledgingConnect; + + UInt8 incomingSessionId, outgoingSessionId; + + incomingSessionId = incomingCommand.incomingSessionID == 0xFF ? m_outgoingSessionID : incomingCommand.incomingSessionID; + incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + if (incomingSessionId == m_outgoingSessionID) + incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + m_outgoingSessionID = incomingSessionId; + + outgoingSessionId = incomingCommand.outgoingSessionID == 0xFF ? m_incomingSessionID : incomingCommand.outgoingSessionID; + outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + if (outgoingSessionId == m_incomingSessionID) + outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + m_incomingSessionID = outgoingSessionId; + + m_mtu = Clamp(NetToHost(incomingCommand.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + + if (m_host->m_outgoingBandwidth == 0 && m_incomingBandwidth == 0) + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else if (m_host->m_outgoingBandwidth == 0 || m_incomingBandwidth == 0) + m_windowSize = (std::max(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + else + m_windowSize = (std::min(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + m_windowSize = Clamp(m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + void ENetPeer::InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize) + { + m_channels.resize(channelCount); + + m_address = address; + m_connectID = connectId; + m_state = ENetPeerState::Connecting; + m_windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + void ENetPeer::OnConnect() { if (!IsConnected()) @@ -498,7 +542,7 @@ namespace Nz { std::list* commandList = nullptr; - bool found = true; + bool found = false; auto currentCommand = m_sentReliableCommands.begin(); commandList = &m_sentReliableCommands; for (; currentCommand != m_sentReliableCommands.end(); ++currentCommand) From 6ab6ec4f14f097849d2aef2a1d90dee7ad9dde59 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 12:14:41 +0100 Subject: [PATCH 08/73] Network/ENetPeer: Improved stability of connections http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html --- src/Nazara/Network/ENetPeer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index e444a4d02..d29860e4d 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -336,7 +336,9 @@ namespace Nz ++m_packetsLost; - outgoingCommand->roundTripTimeout *= 2; + // http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html + outgoingCommand->roundTripTimeout = m_roundTripTime + 4 * m_roundTripTimeVariance; + outgoingCommand->roundTripTimeoutLimit = m_timeoutLimit * outgoingCommand->roundTripTimeout; m_outgoingReliableCommands.emplace_front(std::move(*outgoingCommand)); m_sentReliableCommands.erase(outgoingCommand); From 9d9d7472ca3de240fffb6027c5b336468f062dbd Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 14:09:43 +0100 Subject: [PATCH 09/73] Network/ENetPacket: Fix a huge bug with packets --- src/Nazara/Network/ENetPacket.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Nazara/Network/ENetPacket.cpp b/src/Nazara/Network/ENetPacket.cpp index a22cc7fb8..494ae1a54 100644 --- a/src/Nazara/Network/ENetPacket.cpp +++ b/src/Nazara/Network/ENetPacket.cpp @@ -10,10 +10,7 @@ namespace Nz if (m_packet) { if (--m_packet->referenceCount == 0) - { m_packet->owner->Delete(m_packet); - return; - } } m_packet = packet; From 5207f2c821e79a5d82169a7bc889ea4eaa9269b6 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 17:15:33 +0100 Subject: [PATCH 10/73] Network/ENet: Fix some remaining bugs.... --- src/Nazara/Network/ENetHost.cpp | 4 ++-- src/Nazara/Network/ENetPeer.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index afa870b12..28f586307 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1082,7 +1082,7 @@ namespace Nz peer->DispatchState(ENetPeerState::Zombie); - return false; + return true; } peer->RemoveSentReliableCommand(1, 0xFF); @@ -1201,7 +1201,7 @@ namespace Nz command.header.channelID = acknowledgement.command.header.channelID; command.header.reliableSequenceNumber = reliableSequenceNumber; command.acknowledge.receivedReliableSequenceNumber = reliableSequenceNumber; - command.acknowledge.receivedSentTime = HostToNet(acknowledgement.sentTime); + command.acknowledge.receivedSentTime = HostToNet(acknowledgement.sentTime); if ((acknowledgement.command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_Disconnect) peer->DispatchState(ENetPeerState::Zombie); diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index d29860e4d..340c3152a 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -375,7 +375,7 @@ namespace Nz channel.incomingReliableSequenceNumber = incomingCommand.reliableSequenceNumber; - if (incomingCommand.fragments.GetSize() == 0) + if (incomingCommand.fragments.GetSize() > 0) channel.incomingReliableSequenceNumber += incomingCommand.fragments.GetSize() - 1; } From 34828929b2b545d6d9ce90251a97866a47563ba1 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 17:16:14 +0100 Subject: [PATCH 11/73] Network/ENetHost: Fix a bug --- src/Nazara/Network/ENetHost.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 28f586307..814f843ff 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -983,7 +983,7 @@ namespace Nz break; if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnreliableFragment || - totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) return false; startCommand = &incomingCommand; @@ -1068,7 +1068,7 @@ namespace Nz bool ENetHost::HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command) { if (peer->GetState() != ENetPeerState::Connecting) - return false; + return true; UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); @@ -1082,7 +1082,7 @@ namespace Nz peer->DispatchState(ENetPeerState::Zombie); - return true; + return false; } peer->RemoveSentReliableCommand(1, 0xFF); From 4e2a037d6b06cab659a3e9a1430b65c9d0feaca8 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 17:17:42 +0100 Subject: [PATCH 12/73] Network/ENetPeer: Add total packet lost/sent counter --- include/Nazara/Network/ENetPeer.hpp | 2 ++ src/Nazara/Network/ENetHost.cpp | 1 + src/Nazara/Network/ENetPeer.cpp | 3 +++ 3 files changed, 6 insertions(+) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 7ccaf3d8d..aa3c9f2da 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -205,6 +205,8 @@ namespace Nz UInt32 m_timeoutMaximum; UInt32 m_timeoutMinimum; UInt32 m_windowSize; + UInt64 m_totalPacketLost; + UInt64 m_totalPacketSent; }; } diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 814f843ff..d9a09d2c8 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1320,6 +1320,7 @@ namespace Nz } ++peer->m_packetsSent; + ++peer->m_totalPacketSent; ++m_bufferCount; ++m_commandCount; } diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 340c3152a..c969dde4b 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -191,6 +191,8 @@ namespace Nz m_incomingUnsequencedGroup = 0; m_outgoingUnsequencedGroup = 0; m_eventData = 0; + m_totalPacketLost = 0; + m_totalPacketSent = 0; m_totalWaitingData = 0; m_unsequencedWindow.fill(0); @@ -335,6 +337,7 @@ namespace Nz m_reliableDataInTransit -= outgoingCommand->fragmentLength; ++m_packetsLost; + ++m_totalPacketLost; // http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html outgoingCommand->roundTripTimeout = m_roundTripTime + 4 * m_roundTripTimeVariance; From 4e517bc1e3666be901fdb1cf3be08bfd037fdec7 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 28 Jan 2017 17:18:06 +0100 Subject: [PATCH 13/73] Network/ENetHost: Add network simulator --- include/Nazara/Network/ENetHost.hpp | 14 +++++- include/Nazara/Network/ENetHost.inl | 3 +- src/Nazara/Network/ENetHost.cpp | 70 ++++++++++++++++++++++++++--- src/Nazara/Network/ENetPeer.cpp | 1 - 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 344ffce82..0dcf58a86 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -55,6 +55,8 @@ namespace Nz int Service(ENetEvent* event, UInt32 timeout); + void SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay); + ENetHost& operator=(const ENetHost&) = delete; ENetHost& operator=(ENetHost&&) = default; @@ -96,6 +98,13 @@ namespace Nz static bool Initialize(); static void Uninitialize(); + struct PendingPacket + { + IpAddress from; + NetPacket data; + UInt32 deliveryTime; + }; + std::array m_commands; std::array m_buffers; std::array m_packetData[2]; @@ -110,7 +119,10 @@ namespace Nz std::size_t m_packetSize; std::size_t m_peerCount; std::size_t m_receivedDataLength; + std::uniform_int_distribution m_packetDelayDistribution; std::vector m_peers; + std::vector m_pendingPackets; + UInt8* m_receivedData; Bitset m_dispatchQueue; MemoryPool m_packetPool; IpAddress m_address; @@ -129,10 +141,8 @@ namespace Nz UInt32 m_totalSentPackets; UInt32 m_totalReceivedData; UInt32 m_totalReceivedPackets; - UInt8* m_receivedData; bool m_continueSending; bool m_isSimulationEnabled; - bool m_shouldAcceptConnections; bool m_recalculateBandwidthLimits; static std::mt19937 s_randomGenerator; diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index e547d4e5d..c7e65ab95 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -9,7 +9,8 @@ namespace Nz { inline ENetHost::ENetHost() : - m_packetPool(sizeof(ENetPacket)) + m_packetPool(sizeof(ENetPacket)), + m_isSimulationEnabled(false) { } diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index d9a09d2c8..3587e19d1 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -312,6 +312,20 @@ namespace Nz return 0; } + void ENetHost::SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay) + { + NazaraAssert(maxDelay >= minDelay, "Maximum delay cannot be greater than minimum delay"); + + if (packetLossProbability <= 0.0 && minDelay == 0 && maxDelay == 0) + m_isSimulationEnabled = false; + else + { + m_isSimulationEnabled = true; + m_packetDelayDistribution = std::uniform_int_distribution(minDelay, maxDelay); + m_packetLossProbability = std::bernoulli_distribution(packetLossProbability); + } + } + bool ENetHost::InitSocket(const IpAddress& address) { if (!m_socket.Create(address.GetProtocol())) @@ -1111,14 +1125,58 @@ namespace Nz { for (unsigned int i = 0; i < 256; ++i) { - NetPacket packet; - + bool shouldReceive = true; std::size_t receivedLength; - if (!m_socket.Receive(m_packetData[0].data(), m_packetData[0].size(), &m_receivedAddress, &receivedLength)) - return -1; //< Error - if (receivedLength == 0) - return 0; + if (m_isSimulationEnabled) + { + for (auto it = m_pendingPackets.begin(); it != m_pendingPackets.end(); ++it) + { + if (m_serviceTime >= it->deliveryTime) + { + shouldReceive = false; + + m_receivedAddress = it->from; + receivedLength = it->data.GetDataSize(); + std::memcpy(m_packetData[0].data(), it->data.GetConstData() + NetPacket::HeaderSize, receivedLength); + + m_pendingPackets.erase(it); + break; + } + } + } + + if (shouldReceive) + { + if (!m_socket.Receive(m_packetData[0].data(), m_packetData[0].size(), &m_receivedAddress, &receivedLength)) + return -1; //< Error + + if (receivedLength == 0) + return 0; + + if (m_isSimulationEnabled) + { + if (m_packetLossProbability(s_randomGenerator)) + continue; + + UInt16 delay = m_packetDelayDistribution(s_randomGenerator); + if (delay > 0) + { + PendingPacket pendingPacket; + pendingPacket.deliveryTime = m_serviceTime + delay; + pendingPacket.from = m_receivedAddress; + pendingPacket.data.Reset(0, m_packetData[0].data(), receivedLength); + + auto it = std::upper_bound(m_pendingPackets.begin(), m_pendingPackets.end(), pendingPacket, [] (const PendingPacket& first, const PendingPacket& second) + { + return first.deliveryTime < second.deliveryTime; + }); + + m_pendingPackets.emplace(it, std::move(pendingPacket)); + continue; + } + } + } m_receivedData = m_packetData[0].data(); m_receivedDataLength = receivedLength; diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index c969dde4b..d0181a01d 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #define ENET_TIME_OVERFLOW 86400000 From b5797dfa12b11a307c55525c64b8abbb5b9c16af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 30 Jan 2017 18:08:21 +0100 Subject: [PATCH 14/73] Network/ENetHost: Move handling to ENetPeer --- include/Nazara/Network/ENetHost.hpp | 13 +- include/Nazara/Network/ENetPeer.hpp | 15 +- src/Nazara/Network/ENetHost.cpp | 473 +--------------------------- src/Nazara/Network/ENetPeer.cpp | 449 +++++++++++++++++++++++++- 4 files changed, 475 insertions(+), 475 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 0dcf58a86..fe9956538 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -68,19 +68,8 @@ namespace Nz bool DispatchIncomingCommands(ENetEvent* event); - bool HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command); - bool HandleBandwidthLimit(ENetPeer* peer, const ENetProtocol* command); ENetPeer* HandleConnect(ENetProtocolHeader* header, ENetProtocol* command); - bool HandleDisconnect(ENetPeer* peer, const ENetProtocol* command); bool HandleIncomingCommands(ENetEvent* event); - bool HandlePing(ENetPeer* peer, const ENetProtocol* command); - bool HandleSendFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); - bool HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); - bool HandleSendUnreliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); - bool HandleSendUnreliableFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); - bool HandleSendUnsequenced(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData); - bool HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command); - bool HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command); int ReceiveIncomingCommands(ENetEvent* event); diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index aa3c9f2da..c0d24f6f6 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -77,6 +78,18 @@ namespace Nz void DispatchIncomingReliableCommands(Channel& channel); void DispatchIncomingUnreliableCommands(Channel& channel); + bool HandleAcknowledge(const ENetProtocol* command, ENetEvent* event); + bool HandleBandwidthLimit(const ENetProtocol* command); + bool HandleDisconnect(const ENetProtocol* command); + bool HandlePing(const ENetProtocol* command); + bool HandleSendFragment(const ENetProtocol* command, UInt8** data); + bool HandleSendReliable(const ENetProtocol* command, UInt8** data); + bool HandleSendUnreliable(const ENetProtocol* command, UInt8** data); + bool HandleSendUnreliableFragment(const ENetProtocol* command, UInt8** data); + bool HandleSendUnsequenced(const ENetProtocol* command, UInt8** data); + bool HandleThrottleConfigure(const ENetProtocol* command); + bool HandleVerifyConnect(const ENetProtocol* command, ENetEvent* event); + void OnConnect(); void OnDisconnect(); diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 3587e19d1..4da174baf 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -411,116 +411,6 @@ namespace Nz return false; } - bool ENetHost::HandleAcknowledge(ENetEvent* event, ENetPeer* peer, const ENetProtocol* command) - { - if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie) - return true; - - UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); - receivedSentTime |= m_serviceTime & 0xFFFF0000; - if ((receivedSentTime & 0x8000) > (m_serviceTime & 0x8000)) - receivedSentTime -= 0x10000; - - if (ENET_TIME_LESS(m_serviceTime, receivedSentTime)) - return true; - - peer->m_lastReceiveTime = m_serviceTime; - peer->m_earliestTimeout = 0; - - UInt32 roundTripTime = ENET_TIME_DIFFERENCE(m_serviceTime, receivedSentTime); - - peer->Throttle(roundTripTime); - - peer->m_roundTripTimeVariance -= peer->m_roundTripTimeVariance / 4; - - if (roundTripTime >= peer->m_roundTripTime) - { - peer->m_roundTripTime += (roundTripTime - peer->m_roundTripTime) / 8; - peer->m_roundTripTimeVariance += (roundTripTime - peer->m_roundTripTime) / 4; - } - else - { - peer->m_roundTripTime -= (peer->m_roundTripTime - roundTripTime) / 8; - peer->m_roundTripTimeVariance += (peer->m_roundTripTime - roundTripTime) / 4; - } - - if (peer->m_roundTripTime < peer->m_lowestRoundTripTime) - peer->m_lowestRoundTripTime = peer->m_roundTripTime; - - if (peer->m_roundTripTimeVariance > peer->m_highestRoundTripTimeVariance) - peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance; - - if (peer->m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(m_serviceTime, peer->m_packetThrottleEpoch) >= peer->m_packetThrottleInterval) - { - peer->m_lastRoundTripTime = peer->m_lowestRoundTripTime; - peer->m_lastRoundTripTimeVariance = peer->m_highestRoundTripTimeVariance; - peer->m_lowestRoundTripTime = peer->m_roundTripTime; - peer->m_highestRoundTripTimeVariance = peer->m_roundTripTimeVariance; - peer->m_packetThrottleEpoch = m_serviceTime; - } - - UInt16 receivedReliableSequenceNumber = NetToHost(command->acknowledge.receivedReliableSequenceNumber); - - ENetProtocolCommand commandNumber = peer->RemoveSentReliableCommand(receivedReliableSequenceNumber, command->header.channelID); - - switch (peer->GetState()) - { - case ENetPeerState::AcknowledgingConnect: - if (commandNumber != ENetProtocolCommand_VerifyConnect) - return false; - - NotifyConnect(peer, event); - break; - - case ENetPeerState::Disconnecting: - if (commandNumber != ENetProtocolCommand_Disconnect) - return false; - - NotifyDisconnect(peer, event); - break; - - case ENetPeerState::DisconnectLater: - if (!peer->HasPendingCommands()) - peer->Disconnect(peer->m_eventData); - - break; - - default: - break; - } - - return true; - } - - bool ENetHost::HandleBandwidthLimit(ENetPeer* peer, const ENetProtocol* command) - { - if (!peer->IsConnected()) - return false; - - if (peer->m_incomingBandwidth != 0) - --m_bandwidthLimitedPeers; - - peer->m_incomingBandwidth = NetToHost(command->bandwidthLimit.incomingBandwidth); - peer->m_outgoingBandwidth = NetToHost(command->bandwidthLimit.outgoingBandwidth); - - if (peer->m_incomingBandwidth != 0) - ++m_bandwidthLimitedPeers; - - if (peer->m_incomingBandwidth == 0 && m_outgoingBandwidth == 0) - peer->m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; - else - { - if (peer->m_incomingBandwidth == 0 || m_outgoingBandwidth == 0) - peer->m_windowSize = (std::max(peer->m_incomingBandwidth, m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; - else - peer->m_windowSize = (std::min(peer->m_incomingBandwidth, m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; - - peer->m_windowSize = Clamp(peer->m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); - } - - return true; - } - ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* /*header*/, ENetProtocol* command) { UInt32 channelCount = NetToHost(command->connect.channelCount); @@ -590,37 +480,6 @@ namespace Nz return peer; } - bool ENetHost::HandleDisconnect(ENetPeer* peer, const ENetProtocol * command) - { - if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie || peer->GetState() == ENetPeerState::AcknowledgingDisconnect) - return true; - - peer->ResetQueues(); - - if (peer->GetState() == ENetPeerState::ConnectionSucceeded || peer->GetState() == ENetPeerState::Disconnecting || peer->GetState() == ENetPeerState::Connecting) - peer->DispatchState(ENetPeerState::Zombie); - else - { - if (!peer->IsConnected()) - { - if (peer->GetState() == ENetPeerState::ConnectionPending) - m_recalculateBandwidthLimits = true; - - peer->Reset(); - } - else - if (command->header.command & ENetProtocolFlag_Acknowledge) - peer->ChangeState(ENetPeerState::AcknowledgingDisconnect); - else - peer->DispatchState(ENetPeerState::Zombie); - } - - if (peer->GetState() != ENetPeerState::Disconnected) - peer->m_eventData = NetToHost(command->disconnect.data); - - return true; - } - bool ENetHost::HandleIncomingCommands(ENetEvent* event) { if (m_receivedDataLength < NazaraOffsetOf(ENetProtocolHeader, sentTime)) @@ -702,7 +561,7 @@ namespace Nz switch (commandNumber) { case ENetProtocolCommand_Acknowledge: - if (!HandleAcknowledge(event, peer, command)) + if (!peer->HandleAcknowledge(command, event)) return commandError(); break; @@ -718,61 +577,61 @@ namespace Nz break; case ENetProtocolCommand_VerifyConnect: - if (!HandleVerifyConnect(event, peer, command)) + if (!peer->HandleVerifyConnect(command, event)) return commandError(); break; case ENetProtocolCommand_Disconnect: - if (!HandleDisconnect(peer, command)) + if (!peer->HandleDisconnect(command)) return commandError(); break; case ENetProtocolCommand_Ping: - if (!HandlePing(peer, command)) + if (!peer->HandlePing(command)) return commandError(); break; case ENetProtocolCommand_SendReliable: - if (!HandleSendReliable(peer, command, ¤tData)) + if (!peer->HandleSendReliable(command, ¤tData)) return commandError(); break; case ENetProtocolCommand_SendUnreliable: - if (!HandleSendUnreliable(peer, command, ¤tData)) + if (!peer->HandleSendUnreliable(command, ¤tData)) return commandError(); break; case ENetProtocolCommand_SendUnsequenced: - if (!HandleSendUnsequenced(peer, command, ¤tData)) + if (!peer->HandleSendUnsequenced(command, ¤tData)) return commandError(); break; case ENetProtocolCommand_SendFragment: - if (!HandleSendFragment(peer, command, ¤tData)) + if (!peer->HandleSendFragment(command, ¤tData)) return commandError(); break; case ENetProtocolCommand_BandwidthLimit: - if (!HandleBandwidthLimit(peer, command)) + if (!peer->HandleBandwidthLimit(command)) return commandError(); break; case ENetProtocolCommand_ThrottleConfigure: - if (!HandleThrottleConfigure(peer, command)) + if (!peer->HandleThrottleConfigure(command)) return commandError(); break; case ENetProtocolCommand_SendUnreliableFragment: - if (!HandleSendUnreliableFragment(peer, command, ¤tData)) + if (!peer->HandleSendUnreliableFragment(command, ¤tData)) return commandError(); break; @@ -813,314 +672,6 @@ namespace Nz return commandError(); } - bool ENetHost::HandlePing(ENetPeer* peer, const ENetProtocol* /*command*/) - { - if (!peer->IsConnected()) - return false; - - return true; - } - - bool ENetHost::HandleSendFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) - { - if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) - return false; - - UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); - *currentData += fragmentLength; - if (fragmentLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) - return false; - - ENetPeer::Channel& channel = peer->m_channels[command->header.channelID]; - UInt32 startSequenceNumber = NetToHost(command->sendFragment.startSequenceNumber); - UInt16 startWindow = startSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; - UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; - - if (startSequenceNumber < channel.incomingReliableSequenceNumber) - startWindow += ENetConstants::ENetPeer_ReliableWindows; - - if (startWindow < currentWindow || startWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) - return true; - - UInt32 fragmentNumber = NetToHost(command->sendFragment.fragmentNumber); - UInt32 fragmentCount = NetToHost(command->sendFragment.fragmentCount); - UInt32 fragmentOffset = NetToHost(command->sendFragment.fragmentOffset); - UInt32 totalLength = NetToHost(command->sendFragment.totalLength); - - if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount || fragmentNumber >= fragmentCount || totalLength > m_maximumPacketSize || - fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset) - return false; - - ENetPeer::IncomingCommmand* startCommand = nullptr; - for (auto currentCommand = channel.incomingReliableCommands.rbegin(); currentCommand != channel.incomingReliableCommands.rend(); ++currentCommand) - { - ENetPeer::IncomingCommmand& incomingCommand = *currentCommand; - - if (startSequenceNumber >= channel.incomingReliableSequenceNumber) - { - if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) - continue; - } - else if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) - break; - - if (incomingCommand.reliableSequenceNumber <= startSequenceNumber) - { - if (incomingCommand.reliableSequenceNumber < startSequenceNumber) - break; - - if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendFragment || - totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) - return false; - - startCommand = &incomingCommand; - break; - } - } - - if (startCommand) - { - ENetProtocol hostCommand = *command; - hostCommand.header.reliableSequenceNumber = startSequenceNumber; - - if (!peer->QueueIncomingCommand(hostCommand, nullptr, totalLength, ENetPacketFlag_Reliable, fragmentCount)) - return false; - } - - if (!startCommand->fragments.Test(fragmentNumber)) - { - --startCommand->fragmentsRemaining; - - startCommand->fragments.Set(fragmentNumber, true); - - if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) - fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; - - std::memcpy(startCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); - - if (startCommand->fragmentsRemaining <= 0) - peer->DispatchIncomingReliableCommands(channel); - } - - return false; - } - - bool ENetHost::HandleSendReliable(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) - { - if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) - return false; - - UInt16 dataLength = NetToHost(command->sendReliable.dataLength); - *currentData += dataLength; - if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) - return false; - - if (!peer->QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendReliable), dataLength, ENetPacketFlag_Reliable, 0)) - return false; - - return true; - } - - bool ENetHost::HandleSendUnreliable(ENetPeer * peer, const ENetProtocol * command, UInt8 ** currentData) - { - if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) - return false; - - UInt16 dataLength = NetToHost(command->sendUnreliable.dataLength); - *currentData += dataLength; - if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) - return false; - - if (!peer->QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendUnreliable), dataLength, 0, 0)) - return false; - - return true; - } - - bool ENetHost::HandleSendUnreliableFragment(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) - { - if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) - return false; - - UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); - *currentData += fragmentLength; - if (fragmentLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) - return false; - - ENetPeer::Channel& channel = peer->m_channels[command->header.channelID]; - UInt32 reliableSequenceNumber = command->header.reliableSequenceNumber; - UInt32 startSequenceNumber = NetToHost(command->sendFragment.startSequenceNumber); - - UInt16 reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; - UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; - - if (startSequenceNumber < channel.incomingReliableSequenceNumber) - reliableWindow += ENetConstants::ENetPeer_ReliableWindows; - - if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) - return true; - - if (reliableSequenceNumber == channel.incomingReliableSequenceNumber && startSequenceNumber <= channel.incomingUnreliableSequenceNumber) - return true; - - UInt32 fragmentNumber = NetToHost(command->sendFragment.fragmentNumber); - UInt32 fragmentCount = NetToHost(command->sendFragment.fragmentCount); - UInt32 fragmentOffset = NetToHost(command->sendFragment.fragmentOffset); - UInt32 totalLength = NetToHost(command->sendFragment.totalLength); - - if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount || fragmentNumber >= fragmentCount || totalLength > m_maximumPacketSize || - fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset) - return false; - - ENetPeer::IncomingCommmand* startCommand = nullptr; - for (auto currentCommand = channel.incomingUnreliableCommands.rbegin(); currentCommand != channel.incomingUnreliableCommands.rend(); ++currentCommand) - { - ENetPeer::IncomingCommmand& incomingCommand = *currentCommand; - - if (startSequenceNumber >= channel.incomingReliableSequenceNumber) - { - if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) - continue; - } - else if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) - break; - - if (incomingCommand.reliableSequenceNumber < reliableSequenceNumber) - break; - - if (incomingCommand.reliableSequenceNumber > reliableSequenceNumber) - continue; - - if (incomingCommand.unreliableSequenceNumber <= startSequenceNumber) - { - if (incomingCommand.unreliableSequenceNumber < startSequenceNumber) - break; - - if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnreliableFragment || - totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) - return false; - - startCommand = &incomingCommand; - break; - } - } - - if (startCommand) - { - if (!peer->QueueIncomingCommand(*command, nullptr, totalLength, ENetPacketFlag_UnreliableFragment, fragmentCount)) - return false; - } - - if (!startCommand->fragments.Test(fragmentNumber)) - { - --startCommand->fragmentsRemaining; - - startCommand->fragments.Set(fragmentNumber, true); - - if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) - fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; - - std::memcpy(startCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); - - if (startCommand->fragmentsRemaining <= 0) - peer->DispatchIncomingUnreliableCommands(channel); - } - - return true; - } - - bool ENetHost::HandleSendUnsequenced(ENetPeer* peer, const ENetProtocol* command, UInt8** currentData) - { - if (command->header.channelID >= peer->m_channels.size() || !peer->IsConnected()) - return false; - - std::size_t dataLength = NetToHost(command->sendUnsequenced.dataLength); - *currentData += dataLength; - if (dataLength >= m_maximumPacketSize || *currentData < m_receivedData || *currentData > &m_receivedData[m_receivedDataLength]) - return false; - - UInt32 unsequencedGroup = NetToHost(command->sendUnsequenced.unsequencedGroup); - UInt32 index = unsequencedGroup % ENetConstants::ENetPeer_UnsequencedWindowSize; - - if (unsequencedGroup < peer->m_incomingUnsequencedGroup) - unsequencedGroup += 0x10000; - - if (unsequencedGroup >= static_cast(peer->m_incomingUnsequencedGroup) + ENetConstants::ENetPeer_UnsequencedWindows * ENetConstants::ENetPeer_UnsequencedWindowSize) - return true; - - unsequencedGroup &= 0xFFFF; - - if (unsequencedGroup - index != peer->m_incomingUnsequencedGroup) - { - peer->m_incomingUnsequencedGroup = unsequencedGroup - index; - - peer->m_unsequencedWindow.fill(0); - } - else if (peer->m_unsequencedWindow[index / 32] & (1 << (index % 32))) - return true; - - if (!peer->QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendUnsequenced), dataLength, ENetPacketFlag_Unsequenced, 0)) - return false; - - peer->m_unsequencedWindow[index / 32] |= 1 << (index % 32); - - return true; - } - - bool ENetHost::HandleThrottleConfigure(ENetPeer* peer, const ENetProtocol* command) - { - if (!peer->IsConnected()) - return false; - - peer->m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); - peer->m_packetThrottleAcceleration = NetToHost(command->throttleConfigure.packetThrottleAcceleration); - peer->m_packetThrottleDeceleration = NetToHost(command->throttleConfigure.packetThrottleDeceleration); - - return true; - } - - bool ENetHost::HandleVerifyConnect(ENetEvent* event, ENetPeer* peer, ENetProtocol* command) - { - if (peer->GetState() != ENetPeerState::Connecting) - return true; - - UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); - - if (channelCount < ENetConstants::ENetProtocol_MinimumChannelCount || channelCount > ENetConstants::ENetProtocol_MaximumChannelCount || - NetToHost(command->verifyConnect.packetThrottleInterval) != peer->m_packetThrottleInterval || - NetToHost(command->verifyConnect.packetThrottleAcceleration) != peer->m_packetThrottleAcceleration || - NetToHost(command->verifyConnect.packetThrottleDeceleration) != peer->m_packetThrottleDeceleration || - command->verifyConnect.connectID != peer->m_connectID) - { - peer->m_eventData = 0; - - peer->DispatchState(ENetPeerState::Zombie); - - return false; - } - - peer->RemoveSentReliableCommand(1, 0xFF); - - if (channelCount < peer->m_channels.size()) - peer->m_channels.resize(channelCount); - - peer->m_outgoingPeerID = NetToHost(command->verifyConnect.outgoingPeerID); - peer->m_incomingSessionID = command->verifyConnect.incomingSessionID; - peer->m_outgoingSessionID = command->verifyConnect.outgoingSessionID; - - UInt32 mtu = Clamp(NetToHost(command->verifyConnect.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); - peer->m_mtu = std::min(peer->m_mtu, mtu); - - UInt32 windowSize = Clamp(NetToHost(command->verifyConnect.windowSize), ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); - peer->m_windowSize = std::min(peer->m_windowSize, windowSize); - - peer->m_incomingBandwidth = NetToHost(command->verifyConnect.incomingBandwidth); - peer->m_outgoingBandwidth = NetToHost(command->verifyConnect.outgoingBandwidth); - - NotifyConnect(peer, event); - return true; - } - int ENetHost::ReceiveIncomingCommands(ENetEvent* event) { for (unsigned int i = 0; i < 256; ++i) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index d0181a01d..e90d77954 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -469,6 +469,453 @@ namespace Nz channel.incomingUnreliableCommands.erase(channel.incomingUnreliableCommands.begin(), droppedCommand); } + bool ENetPeer::HandleAcknowledge(const ENetProtocol* command, ENetEvent* event) + { + if (m_state == ENetPeerState::Disconnected || m_state == ENetPeerState::Zombie) + return true; + + UInt32 serviceTime = m_host->m_serviceTime; + UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); + receivedSentTime |= serviceTime & 0xFFFF0000; + if ((receivedSentTime & 0x8000) > (serviceTime & 0x8000)) + receivedSentTime -= 0x10000; + + if (ENET_TIME_LESS(serviceTime, receivedSentTime)) + return true; + + m_lastReceiveTime = serviceTime; + m_earliestTimeout = 0; + + UInt32 roundTripTime = ENET_TIME_DIFFERENCE(serviceTime, receivedSentTime); + + Throttle(roundTripTime); + + m_roundTripTimeVariance -= m_roundTripTimeVariance / 4; + + if (roundTripTime >= m_roundTripTime) + { + m_roundTripTime += (roundTripTime - m_roundTripTime) / 8; + m_roundTripTimeVariance += (roundTripTime - m_roundTripTime) / 4; + } + else + { + m_roundTripTime -= (m_roundTripTime - roundTripTime) / 8; + m_roundTripTimeVariance += (m_roundTripTime - roundTripTime) / 4; + } + + m_lowestRoundTripTime = std::min(m_lowestRoundTripTime, m_roundTripTime); + m_highestRoundTripTimeVariance = std::max(m_highestRoundTripTimeVariance, m_roundTripTimeVariance); + + if (m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(serviceTime, m_packetThrottleEpoch) >= m_packetThrottleInterval) + { + m_lastRoundTripTime = m_lowestRoundTripTime; + m_lastRoundTripTimeVariance = m_highestRoundTripTimeVariance; + m_lowestRoundTripTime = m_roundTripTime; + m_highestRoundTripTimeVariance = m_roundTripTimeVariance; + m_packetThrottleEpoch = serviceTime; + } + + UInt16 receivedReliableSequenceNumber = NetToHost(command->acknowledge.receivedReliableSequenceNumber); + + ENetProtocolCommand commandNumber = RemoveSentReliableCommand(receivedReliableSequenceNumber, command->header.channelID); + + switch (m_state) + { + case ENetPeerState::AcknowledgingConnect: + if (commandNumber != ENetProtocolCommand_VerifyConnect) + return false; + + m_host->NotifyConnect(this, event); + break; + + case ENetPeerState::Disconnecting: + if (commandNumber != ENetProtocolCommand_Disconnect) + return false; + + m_host->NotifyDisconnect(this, event); + break; + + case ENetPeerState::DisconnectLater: + if (!HasPendingCommands()) + Disconnect(m_eventData); + + break; + + default: + break; + } + + return true; + } + + bool ENetPeer::HandleBandwidthLimit(const ENetProtocol* command) + { + if (!IsConnected()) + return false; + + if (m_incomingBandwidth != 0) + --m_host->m_bandwidthLimitedPeers; + + m_incomingBandwidth = NetToHost(command->bandwidthLimit.incomingBandwidth); + m_outgoingBandwidth = NetToHost(command->bandwidthLimit.outgoingBandwidth); + + if (m_incomingBandwidth != 0) + ++m_host->m_bandwidthLimitedPeers; + + if (m_incomingBandwidth == 0 && m_host->m_outgoingBandwidth == 0) + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else + { + if (m_incomingBandwidth == 0 || m_host->m_outgoingBandwidth == 0) + m_windowSize = (std::max(m_incomingBandwidth, m_host->m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + else + m_windowSize = (std::min(m_incomingBandwidth, m_host->m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + m_windowSize = Clamp(m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + return true; + } + + bool ENetPeer::HandleDisconnect(const ENetProtocol* command) + { + if (m_state == ENetPeerState::Disconnected || m_state == ENetPeerState::Zombie || m_state == ENetPeerState::AcknowledgingDisconnect) + return true; + + ResetQueues(); + + if (m_state == ENetPeerState::ConnectionSucceeded || m_state == ENetPeerState::Disconnecting || m_state == ENetPeerState::Connecting) + DispatchState(ENetPeerState::Zombie); + else + { + if (!IsConnected()) + { + if (m_state == ENetPeerState::ConnectionPending) + m_host->m_recalculateBandwidthLimits = true; + + Reset(); + } + else + if (command->header.command & ENetProtocolFlag_Acknowledge) + ChangeState(ENetPeerState::AcknowledgingDisconnect); + else + DispatchState(ENetPeerState::Zombie); + } + + if (m_state != ENetPeerState::Disconnected) + m_eventData = NetToHost(command->disconnect.data); + + return true; + } + + bool ENetPeer::HandlePing(const ENetProtocol* /*command*/) + { + if (!IsConnected()) + return false; + + return true; + } + + bool ENetPeer::HandleSendFragment(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); + *data += fragmentLength; + if (fragmentLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + ENetPeer::Channel& channel = m_channels[command->header.channelID]; + UInt32 startSequenceNumber = NetToHost(command->sendFragment.startSequenceNumber); + UInt16 startWindow = startSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (startSequenceNumber < channel.incomingReliableSequenceNumber) + startWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (startWindow < currentWindow || startWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) + return true; + + UInt32 fragmentNumber = NetToHost(command->sendFragment.fragmentNumber); + UInt32 fragmentCount = NetToHost(command->sendFragment.fragmentCount); + UInt32 fragmentOffset = NetToHost(command->sendFragment.fragmentOffset); + UInt32 totalLength = NetToHost(command->sendFragment.totalLength); + + if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount || fragmentNumber >= fragmentCount || totalLength > m_host->m_maximumPacketSize || + fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset) + return false; + + ENetPeer::IncomingCommmand* startCommand = nullptr; + for (auto currentCommand = channel.incomingReliableCommands.rbegin(); currentCommand != channel.incomingReliableCommands.rend(); ++currentCommand) + { + ENetPeer::IncomingCommmand& incomingCommand = *currentCommand; + + if (startSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber <= startSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < startSequenceNumber) + break; + + if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendFragment || + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) + return false; + + startCommand = &incomingCommand; + break; + } + } + + if (startCommand) + { + ENetProtocol hostCommand = *command; + hostCommand.header.reliableSequenceNumber = startSequenceNumber; + + if (!QueueIncomingCommand(hostCommand, nullptr, totalLength, ENetPacketFlag_Reliable, fragmentCount)) + return false; + } + + if (!startCommand->fragments.Test(fragmentNumber)) + { + --startCommand->fragmentsRemaining; + + startCommand->fragments.Set(fragmentNumber, true); + + if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) + fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; + + std::memcpy(startCommand->packet->data.GetData() + NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) + DispatchIncomingReliableCommands(channel); + } + + return false; + } + + bool ENetPeer::HandleSendReliable(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 dataLength = NetToHost(command->sendReliable.dataLength); + *data += dataLength; + if (dataLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + if (!QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendReliable), dataLength, ENetPacketFlag_Reliable, 0)) + return false; + + return true; + } + + bool ENetPeer::HandleSendUnreliable(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 dataLength = NetToHost(command->sendUnreliable.dataLength); + *data += dataLength; + if (dataLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + if (!QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendUnreliable), dataLength, 0, 0)) + return false; + + return true; + } + + bool ENetPeer::HandleSendUnreliableFragment(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); + *data += fragmentLength; + if (fragmentLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + ENetPeer::Channel& channel = m_channels[command->header.channelID]; + UInt32 reliableSequenceNumber = command->header.reliableSequenceNumber; + UInt32 startSequenceNumber = NetToHost(command->sendFragment.startSequenceNumber); + + UInt16 reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (startSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) + return true; + + if (reliableSequenceNumber == channel.incomingReliableSequenceNumber && startSequenceNumber <= channel.incomingUnreliableSequenceNumber) + return true; + + UInt32 fragmentNumber = NetToHost(command->sendFragment.fragmentNumber); + UInt32 fragmentCount = NetToHost(command->sendFragment.fragmentCount); + UInt32 fragmentOffset = NetToHost(command->sendFragment.fragmentOffset); + UInt32 totalLength = NetToHost(command->sendFragment.totalLength); + + if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount || fragmentNumber >= fragmentCount || totalLength > m_host->m_maximumPacketSize || + fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset) + return false; + + ENetPeer::IncomingCommmand* startCommand = nullptr; + for (auto currentCommand = channel.incomingUnreliableCommands.rbegin(); currentCommand != channel.incomingUnreliableCommands.rend(); ++currentCommand) + { + ENetPeer::IncomingCommmand& incomingCommand = *currentCommand; + + if (startSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber < reliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber > reliableSequenceNumber) + continue; + + if (incomingCommand.unreliableSequenceNumber <= startSequenceNumber) + { + if (incomingCommand.unreliableSequenceNumber < startSequenceNumber) + break; + + if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnreliableFragment || + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) + return false; + + startCommand = &incomingCommand; + break; + } + } + + if (startCommand) + { + if (!QueueIncomingCommand(*command, nullptr, totalLength, ENetPacketFlag_UnreliableFragment, fragmentCount)) + return false; + } + + if (!startCommand->fragments.Test(fragmentNumber)) + { + --startCommand->fragmentsRemaining; + + startCommand->fragments.Set(fragmentNumber, true); + + if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) + fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; + + std::memcpy(startCommand->packet->data.GetData() + NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) + DispatchIncomingUnreliableCommands(channel); + } + + return true; + } + + bool ENetPeer::HandleSendUnsequenced(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + std::size_t dataLength = NetToHost(command->sendUnsequenced.dataLength); + *data += dataLength; + if (dataLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + UInt32 unsequencedGroup = NetToHost(command->sendUnsequenced.unsequencedGroup); + UInt32 index = unsequencedGroup % ENetConstants::ENetPeer_UnsequencedWindowSize; + + if (unsequencedGroup < m_incomingUnsequencedGroup) + unsequencedGroup += 0x10000; + + if (unsequencedGroup >= static_cast(m_incomingUnsequencedGroup) + ENetConstants::ENetPeer_UnsequencedWindows * ENetConstants::ENetPeer_UnsequencedWindowSize) + return true; + + unsequencedGroup &= 0xFFFF; + + if (unsequencedGroup - index != m_incomingUnsequencedGroup) + { + m_incomingUnsequencedGroup = unsequencedGroup - index; + + m_unsequencedWindow.fill(0); + } + else if (m_unsequencedWindow[index / 32] & (1 << (index % 32))) + return true; + + if (!QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendUnsequenced), dataLength, ENetPacketFlag_Unsequenced, 0)) + return false; + + m_unsequencedWindow[index / 32] |= 1 << (index % 32); + + return true; + } + + bool ENetPeer::HandleThrottleConfigure(const ENetProtocol* command) + { + if (!IsConnected()) + return false; + + m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); + m_packetThrottleAcceleration = NetToHost(command->throttleConfigure.packetThrottleAcceleration); + m_packetThrottleDeceleration = NetToHost(command->throttleConfigure.packetThrottleDeceleration); + + return true; + } + + bool ENetPeer::HandleVerifyConnect(const ENetProtocol* command, ENetEvent* event) + { + if (m_state != ENetPeerState::Connecting) + return true; + + UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); + + if (channelCount < ENetConstants::ENetProtocol_MinimumChannelCount || channelCount > ENetConstants::ENetProtocol_MaximumChannelCount || + NetToHost(command->verifyConnect.packetThrottleInterval) != m_packetThrottleInterval || + NetToHost(command->verifyConnect.packetThrottleAcceleration) != m_packetThrottleAcceleration || + NetToHost(command->verifyConnect.packetThrottleDeceleration) != m_packetThrottleDeceleration || + command->verifyConnect.connectID != m_connectID) + { + m_eventData = 0; + + DispatchState(ENetPeerState::Zombie); + + return false; + } + + RemoveSentReliableCommand(1, 0xFF); + + if (channelCount < m_channels.size()) + m_channels.resize(channelCount); + + m_outgoingPeerID = NetToHost(command->verifyConnect.outgoingPeerID); + m_incomingSessionID = command->verifyConnect.incomingSessionID; + m_outgoingSessionID = command->verifyConnect.outgoingSessionID; + + UInt32 mtu = Clamp(NetToHost(command->verifyConnect.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + m_mtu = std::min(m_mtu, mtu); + + UInt32 windowSize = Clamp(NetToHost(command->verifyConnect.windowSize), ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + m_windowSize = std::min(m_windowSize, windowSize); + + m_incomingBandwidth = NetToHost(command->verifyConnect.incomingBandwidth); + m_outgoingBandwidth = NetToHost(command->verifyConnect.outgoingBandwidth); + + m_host->NotifyConnect(this, event); + return true; + } + void ENetPeer::InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand) { m_channels.resize(channelCount); From 3ff483d2f6e896e58d877e68b04aab74609b1881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 30 Jan 2017 18:08:38 +0100 Subject: [PATCH 15/73] Network/ENetPeer: Add GetPeerId() --- include/Nazara/Network/ENetPeer.hpp | 1 + include/Nazara/Network/ENetPeer.inl | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index c0d24f6f6..a6a00ba23 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -41,6 +41,7 @@ namespace Nz void DisconnectNow(UInt32 data); inline const IpAddress& GetAddress() const; + inline UInt16 GetPeerId() const; inline ENetPeerState GetState() const; inline bool HasPendingCommands(); diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index 1e74e0cae..324a1fb80 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -13,6 +13,11 @@ namespace Nz return m_address; } + inline UInt16 ENetPeer::GetPeerId() const + { + return m_incomingPeerID; + } + inline ENetPeerState ENetPeer::GetState() const { return m_state; From 4f1df53f075831fcd6154a54964d98559ef38964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 31 Jan 2017 15:31:11 +0100 Subject: [PATCH 16/73] Network/ENetPeer: Fix DisconnectLater not waiting for pending commands --- src/Nazara/Network/ENetPeer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index e90d77954..ae0952be5 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -83,7 +83,7 @@ namespace Nz void ENetPeer::DisconnectLater(UInt32 data) { - if (IsConnected() && !m_outgoingReliableCommands.empty() && !m_outgoingUnreliableCommands.empty() && !m_sentReliableCommands.empty()) + if (IsConnected() && HasPendingCommands()) { m_state = ENetPeerState::DisconnectLater; m_eventData = data; @@ -596,10 +596,12 @@ namespace Nz Reset(); } else + { if (command->header.command & ENetProtocolFlag_Acknowledge) ChangeState(ENetPeerState::AcknowledgingDisconnect); else DispatchState(ENetPeerState::Zombie); + } } if (m_state != ENetPeerState::Disconnected) From 2f057191aadf79265a27917be17dfd1e61127c33 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 31 Jan 2017 22:19:17 +0100 Subject: [PATCH 17/73] Network/ENetHost: Add GetServiceTime() --- include/Nazara/Network/ENetHost.hpp | 2 ++ include/Nazara/Network/ENetHost.inl | 5 +++++ src/Nazara/Network/ENetPeer.cpp | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index fe9956538..97b12f2c0 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -53,6 +53,8 @@ namespace Nz void Flush(); + inline UInt32 GetServiceTime() const; + int Service(ENetEvent* event, UInt32 timeout); void SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay); diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index c7e65ab95..8aa722771 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -51,6 +51,11 @@ namespace Nz m_peers.clear(); m_socket.Close(); } + + inline UInt32 Nz::ENetHost::GetServiceTime() const + { + return m_serviceTime; + } } #include diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index ae0952be5..6c5940629 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -474,7 +474,8 @@ namespace Nz if (m_state == ENetPeerState::Disconnected || m_state == ENetPeerState::Zombie) return true; - UInt32 serviceTime = m_host->m_serviceTime; + UInt32 serviceTime = m_host->GetServiceTime(); + UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); receivedSentTime |= serviceTime & 0xFFFF0000; if ((receivedSentTime & 0x8000) > (serviceTime & 0x8000)) From 6b8d9deb43907d4c5fcb4b3f69b24afac10500fa Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 31 Jan 2017 23:04:53 +0100 Subject: [PATCH 18/73] Network/ENet: Clean up time functions --- include/Nazara/Network/ENetProtocol.hpp | 10 ++++++++ include/Nazara/Network/ENetProtocol.inl | 34 +++++++++++++++++++++++++ src/Nazara/Network/ENetHost.cpp | 23 +++++------------ src/Nazara/Network/ENetPeer.cpp | 14 +++++----- 4 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 include/Nazara/Network/ENetProtocol.inl diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp index 0434cafc2..e3df5e092 100644 --- a/include/Nazara/Network/ENetProtocol.hpp +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -13,6 +13,14 @@ namespace Nz { + constexpr UInt32 ENetTimeOverflow = 24 * 60 * 60 * 1000; + + inline UInt32 ENetTimeDifference(UInt32 a, UInt32 b); + inline bool ENetTimeLess(UInt32 a, UInt32 b); + inline bool ENetTimeLessEqual(UInt32 a, UInt32 b); + inline bool ENetTimeGreater(UInt32 a, UInt32 b); + inline bool ENetTimeGreaterEqual(UInt32 a, UInt32 b); + class ENetPeer; // Constants for the ENet implementation and protocol @@ -294,4 +302,6 @@ namespace Nz #endif } +#include + #endif // NAZARA_ENETPROTOCOL_HPP diff --git a/include/Nazara/Network/ENetProtocol.inl b/include/Nazara/Network/ENetProtocol.inl new file mode 100644 index 000000000..b854f26c8 --- /dev/null +++ b/include/Nazara/Network/ENetProtocol.inl @@ -0,0 +1,34 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + UInt32 ENetTimeDifference(UInt32 a, UInt32 b) + { + return (ENetTimeLess(a, b)) ? b - a : a - b; + } + + bool ENetTimeLess(UInt32 a, UInt32 b) + { + return (a - b >= ENetTimeOverflow); + } + + bool ENetTimeLessEqual(UInt32 a, UInt32 b) + { + return !ENetTimeGreater(a, b); + } + + bool ENetTimeGreater(UInt32 a, UInt32 b) + { + return ENetTimeLess(b, a); + } + + bool ENetTimeGreaterEqual(UInt32 a, UInt32 b) + { + return !ENetTimeLess(a, b); + } +} diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 4da174baf..360142c37 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -6,15 +6,6 @@ #include #include -#define ENET_TIME_OVERFLOW 86400000 - -#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) -#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) - -#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) - namespace Nz { /// Temporary @@ -235,7 +226,7 @@ namespace Nz do { - if (ENET_TIME_DIFFERENCE(m_serviceTime, m_bandwidthThrottleEpoch) >= ENetConstants::ENetHost_BandwidthThrottleInterval) + if (ENetTimeDifference(m_serviceTime, m_bandwidthThrottleEpoch) >= ENetConstants::ENetHost_BandwidthThrottleInterval) ThrottleBandwidth(); switch (SendOutgoingCommands(event, true)) @@ -291,17 +282,17 @@ namespace Nz return 1; } - if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) + if (ENetTimeGreaterEqual(m_serviceTime, timeout)) return 0; for (;;) { m_serviceTime = GetElapsedMilliseconds(); - if (ENET_TIME_GREATER_EQUAL(m_serviceTime, timeout)) + if (ENetTimeGreaterEqual(m_serviceTime, timeout)) return 0; - if (m_poller.Wait(ENET_TIME_DIFFERENCE(timeout, m_serviceTime))) + if (m_poller.Wait(ENetTimeDifference(timeout, m_serviceTime))) break; } @@ -962,7 +953,7 @@ namespace Nz if (!currentPeer->m_acknowledgements.empty()) SendAcknowledgements(currentPeer); - if (checkForTimeouts && !currentPeer->m_sentReliableCommands.empty() && ENET_TIME_GREATER_EQUAL(m_serviceTime, currentPeer->m_nextTimeout) && currentPeer->CheckTimeouts(event)) + if (checkForTimeouts && !currentPeer->m_sentReliableCommands.empty() && ENetTimeGreaterEqual(m_serviceTime, currentPeer->m_nextTimeout) && currentPeer->CheckTimeouts(event)) { if (event && event->type != ENetEventType::None) return 1; @@ -971,7 +962,7 @@ namespace Nz } if ((currentPeer->m_outgoingReliableCommands.empty() || SendReliableOutgoingCommands(currentPeer)) && currentPeer->m_sentReliableCommands.empty() && - ENET_TIME_DIFFERENCE(m_serviceTime, currentPeer->m_lastReceiveTime) >= currentPeer->m_pingInterval && currentPeer->m_mtu - m_packetSize >= sizeof(ENetProtocolPing)) + ENetTimeDifference(m_serviceTime, currentPeer->m_lastReceiveTime) >= currentPeer->m_pingInterval && currentPeer->m_mtu - m_packetSize >= sizeof(ENetProtocolPing)) { currentPeer->Ping(); SendReliableOutgoingCommands(currentPeer); @@ -985,7 +976,7 @@ namespace Nz if (currentPeer->m_packetLossEpoch == 0) currentPeer->m_packetLossEpoch = m_serviceTime; - else if (ENET_TIME_DIFFERENCE(m_serviceTime, currentPeer->m_packetLossEpoch) >= ENetPeer_PacketLossInterval && currentPeer->m_packetsSent > 0) + else if (ENetTimeDifference(m_serviceTime, currentPeer->m_packetLossEpoch) >= ENetPeer_PacketLossInterval && currentPeer->m_packetsSent > 0) { UInt32 packetLoss = currentPeer->m_packetsLost * ENetPeer_PacketLossScale / currentPeer->m_packetsSent; diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 6c5940629..33c7fc465 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -319,14 +319,14 @@ namespace Nz ++currentCommand; - if (ENET_TIME_DIFFERENCE(m_host->m_serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) + if (ENetTimeDifference(serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) continue; - if (m_earliestTimeout == 0 || ENET_TIME_LESS(outgoingCommand->sentTime, m_earliestTimeout)) + if (m_earliestTimeout == 0 || ENetTimeLess(outgoingCommand->sentTime, m_earliestTimeout)) m_earliestTimeout = outgoingCommand->sentTime; - if (m_earliestTimeout != 0 && (ENET_TIME_DIFFERENCE(m_host->m_serviceTime, m_earliestTimeout) >= m_timeoutMaximum || - (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENET_TIME_DIFFERENCE(m_host->m_serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) + if (m_earliestTimeout != 0 && (ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMaximum || + (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) { m_host->NotifyDisconnect(this, event); return true; @@ -481,13 +481,13 @@ namespace Nz if ((receivedSentTime & 0x8000) > (serviceTime & 0x8000)) receivedSentTime -= 0x10000; - if (ENET_TIME_LESS(serviceTime, receivedSentTime)) + if (ENetTimeLess(serviceTime, receivedSentTime)) return true; m_lastReceiveTime = serviceTime; m_earliestTimeout = 0; - UInt32 roundTripTime = ENET_TIME_DIFFERENCE(serviceTime, receivedSentTime); + UInt32 roundTripTime = ENetTimeDifference(serviceTime, receivedSentTime); Throttle(roundTripTime); @@ -507,7 +507,7 @@ namespace Nz m_lowestRoundTripTime = std::min(m_lowestRoundTripTime, m_roundTripTime); m_highestRoundTripTimeVariance = std::max(m_highestRoundTripTimeVariance, m_roundTripTimeVariance); - if (m_packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE(serviceTime, m_packetThrottleEpoch) >= m_packetThrottleInterval) + if (m_packetThrottleEpoch == 0 || ENetTimeDifference(serviceTime, m_packetThrottleEpoch) >= m_packetThrottleInterval) { m_lastRoundTripTime = m_lowestRoundTripTime; m_lastRoundTripTimeVariance = m_highestRoundTripTimeVariance; From 85257da07e80da568c89b65af4bc09a0d90005f3 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 31 Jan 2017 23:05:18 +0100 Subject: [PATCH 19/73] Network/ENet: Fix some warnings --- include/Nazara/Network/ENetHost.hpp | 4 ++-- src/Nazara/Network/ENetHost.cpp | 4 ++-- src/Nazara/Network/ENetPeer.cpp | 23 +++++++---------------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 97b12f2c0..376e03002 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -128,10 +128,10 @@ namespace Nz UInt32 m_incomingBandwidth; UInt32 m_outgoingBandwidth; UInt32 m_serviceTime; - UInt32 m_totalSentData; UInt32 m_totalSentPackets; - UInt32 m_totalReceivedData; UInt32 m_totalReceivedPackets; + UInt64 m_totalSentData; + UInt64 m_totalReceivedData; bool m_continueSending; bool m_isSimulationEnabled; bool m_recalculateBandwidthLimits; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 360142c37..0b73a1491 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -440,7 +440,7 @@ namespace Nz if (!peer || duplicatePeers >= m_duplicatePeers) return nullptr; - channelCount = std::min(channelCount, m_channelLimit); + channelCount = std::min(channelCount, UInt32(m_channelLimit)); peer->InitIncoming(channelCount, m_receivedAddress, command->connect); @@ -514,7 +514,7 @@ namespace Nz if (peer) { peer->m_address = m_receivedAddress; - peer->m_incomingDataTotal += m_receivedDataLength; + peer->m_incomingDataTotal += UInt32(m_receivedDataLength); } auto commandError = [&]() -> bool diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 33c7fc465..a3946e56e 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -4,15 +4,6 @@ #include #include -#define ENET_TIME_OVERFLOW 86400000 - -#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) -#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) - -#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) - namespace Nz { /// Temporary @@ -216,9 +207,7 @@ namespace Nz Channel& channel = m_channels[channelId]; - std::size_t fragmentLength = m_mtu - sizeof(ENetProtocolHeader) - sizeof(ENetProtocolSendFragment); - //if (m_host->m_checksum != nullptr) - // fragmentLength -= sizeof(UInt32); + UInt16 fragmentLength = static_cast(m_mtu - sizeof(ENetProtocolHeader) - sizeof(ENetProtocolSendFragment)); UInt32 packetSize = static_cast(packetRef->data.GetDataSize()); if (packetSize > fragmentLength) @@ -252,11 +241,11 @@ namespace Nz fragmentOffset += fragmentLength) { if (packetSize - fragmentOffset < fragmentLength) - fragmentLength = packetSize - fragmentOffset; + fragmentLength = UInt16(packetSize - fragmentOffset); OutgoingCommand outgoingCommand; outgoingCommand.fragmentOffset = fragmentOffset; - outgoingCommand.fragmentLength = static_cast(fragmentLength); + outgoingCommand.fragmentLength = fragmentLength; outgoingCommand.packet = packetRef; outgoingCommand.command.header.command = commandNumber; outgoingCommand.command.header.channelID = channelId; @@ -312,6 +301,8 @@ namespace Nz bool ENetPeer::CheckTimeouts(ENetEvent* event) { + UInt32 serviceTime = m_host->GetServiceTime(); + auto currentCommand = m_sentReliableCommands.begin(); while (currentCommand != m_sentReliableCommands.end()) { @@ -816,7 +807,7 @@ namespace Nz startCommand->fragments.Set(fragmentNumber, true); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) - fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; + fragmentLength = static_cast(startCommand->packet->data.GetDataSize() - fragmentOffset); std::memcpy(startCommand->packet->data.GetData() + NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); @@ -1285,7 +1276,7 @@ namespace Nz void ENetPeer::SetupOutgoingCommand(OutgoingCommand& outgoingCommand) { - m_outgoingDataTotal += ENetHost::GetCommandSize(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength; + m_outgoingDataTotal += static_cast(ENetHost::GetCommandSize(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength); if (outgoingCommand.command.header.channelID == 0xFF) { From a087174bf8d6e79b21b4eee36eaa2d015ede121a Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 1 Feb 2017 00:13:08 +0100 Subject: [PATCH 20/73] Network/Algorithm: Add HostToNet and NetToHost --- include/Nazara/Network/Algorithm.hpp | 7 +++++++ include/Nazara/Network/Algorithm.inl | 25 +++++++++++++++++++++++++ src/Nazara/Network/ENetHost.cpp | 24 +----------------------- src/Nazara/Network/ENetPeer.cpp | 26 ++------------------------ 4 files changed, 35 insertions(+), 47 deletions(-) diff --git a/include/Nazara/Network/Algorithm.hpp b/include/Nazara/Network/Algorithm.hpp index 001d98059..f2d99b605 100644 --- a/include/Nazara/Network/Algorithm.hpp +++ b/include/Nazara/Network/Algorithm.hpp @@ -11,10 +11,17 @@ #include #include #include +#include namespace Nz { NAZARA_NETWORK_API bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port = nullptr, bool* isIPv6 = nullptr, const char** endOfRead = nullptr); + + template + std::enable_if_t::value, T> HostToNet(T value); + + template + std::enable_if_t::value, T> NetToHost(T value); } #include diff --git a/include/Nazara/Network/Algorithm.inl b/include/Nazara/Network/Algorithm.inl index 5364298d4..4cba24136 100644 --- a/include/Nazara/Network/Algorithm.inl +++ b/include/Nazara/Network/Algorithm.inl @@ -2,6 +2,31 @@ // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include +#include #include +namespace Nz +{ + template + std::enable_if_t::value, T> HostToNet(T value) + { +#ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); +#else + return value; +#endif + } + + template + std::enable_if_t::value, T> NetToHost(T value) + { +#ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); +#else + return value; +#endif + } +} + #include diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 0b73a1491..0461b1053 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1,35 +1,13 @@ #include #include -#include #include +#include #include #include #include namespace Nz { - /// Temporary - template - T HostToNet(T value) - { - #ifdef NAZARA_LITTLE_ENDIAN - return SwapBytes(value); - #else - return value; - #endif - } - - /// Temporary - template - T NetToHost(T value) - { - #ifdef NAZARA_LITTLE_ENDIAN - return SwapBytes(value); - #else - return value; - #endif - } - namespace { static std::size_t s_commandSizes[ENetProtocolCommand_Count] = diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index a3946e56e..152f1b4ef 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -1,33 +1,11 @@ #include -#include +#include #include #include #include namespace Nz { - /// Temporary - template - T HostToNet(T value) - { - #ifdef NAZARA_LITTLE_ENDIAN - return SwapBytes(value); - #else - return value; - #endif - } - - /// Temporary - template - T NetToHost(T value) - { - #ifdef NAZARA_LITTLE_ENDIAN - return SwapBytes(value); - #else - return value; - #endif - } - ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : m_host(host), m_packetPool(sizeof(ENetPacket)), @@ -683,7 +661,7 @@ namespace Nz startCommand->fragments.Set(fragmentNumber, true); if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) - fragmentLength = startCommand->packet->data.GetDataSize() - fragmentOffset; + fragmentLength = static_cast(startCommand->packet->data.GetDataSize() - fragmentOffset); std::memcpy(startCommand->packet->data.GetData() + NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); From 7b8100dafe2577a878357ad00ed72271976bb66e Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 1 Feb 2017 00:20:22 +0100 Subject: [PATCH 21/73] Network/ENet: Add ENet licence --- include/Nazara/Network/ENetHost.hpp | 12 +++++++++++- include/Nazara/Network/ENetPeer.hpp | 12 +++++++++++- src/Nazara/Network/ENetHost.cpp | 16 +++++++++++++++- src/Nazara/Network/ENetPacket.cpp | 4 ++++ src/Nazara/Network/ENetPeer.cpp | 16 +++++++++++++++- 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 376e03002..06d8259c5 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -1,4 +1,14 @@ -// Copyright (C) 2017 Jérôme Leclercq +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index a6a00ba23..4c4248ad8 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -1,4 +1,14 @@ -// Copyright (C) 2017 Jérôme Leclercq +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 0461b1053..3659139ac 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1,4 +1,18 @@ -#include +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include #include #include #include diff --git a/src/Nazara/Network/ENetPacket.cpp b/src/Nazara/Network/ENetPacket.cpp index 494ae1a54..4b4157ac4 100644 --- a/src/Nazara/Network/ENetPacket.cpp +++ b/src/Nazara/Network/ENetPacket.cpp @@ -1,3 +1,7 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + #include #include #include diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 152f1b4ef..88b5568ff 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -1,4 +1,18 @@ -#include +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include #include #include #include From 0f2d315c1d127be6f2f1e698ef77006e61d5dedb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 1 Feb 2017 17:51:41 +0100 Subject: [PATCH 22/73] Network/ENet: Fix header dependency --- include/Nazara/Network/ENetHost.hpp | 6 ++---- include/Nazara/Network/ENetPeer.hpp | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 06d8259c5..83e8fd147 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -36,8 +36,6 @@ namespace Nz { - class ENetPeer; - class NAZARA_NETWORK_API ENetHost { friend ENetPeer; @@ -153,4 +151,4 @@ namespace Nz #include -#endif // NAZARA_RUDPSERVER_HPP +#endif // NAZARA_ENETHOST_HPP diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 4c4248ad8..e2b76c54a 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include From 41d06fed38bccae3183dd720ba4d343dec6ca3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 1 Feb 2017 17:52:01 +0100 Subject: [PATCH 23/73] Network/ENetHost: Fix packet leak when broadcasting with no peer connected --- src/Nazara/Network/ENetHost.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 3659139ac..aff71c9c3 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -45,7 +45,7 @@ namespace Nz void ENetHost::Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) { - ENetPacket* enetPacket = m_packetPool.New(); + ENetPacketRef enetPacket = m_packetPool.New(); enetPacket->flags = flags; enetPacket->data = std::move(packet); enetPacket->owner = &m_packetPool; From 414779b53c2f582b6307b3f9f8ac43917fdd4494 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 12 Feb 2017 02:18:38 +0100 Subject: [PATCH 24/73] Network/ENetPacket: Remove unused flags --- include/Nazara/Network/ENetPacket.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/Nazara/Network/ENetPacket.hpp b/include/Nazara/Network/ENetPacket.hpp index 54a5d4676..5aecb0edd 100644 --- a/include/Nazara/Network/ENetPacket.hpp +++ b/include/Nazara/Network/ENetPacket.hpp @@ -14,18 +14,16 @@ namespace Nz { enum ENetPacketFlag { - ENetPacketFlag_NoAllocate, ENetPacketFlag_Reliable, ENetPacketFlag_Unsequenced, - ENetPacketFlag_UnreliableFragment, - ENetPacketFlag_Sent + ENetPacketFlag_UnreliableFragment }; template<> struct EnumAsFlags { static constexpr bool value = true; - static constexpr int max = ENetPacketFlag_Sent; + static constexpr int max = ENetPacketFlag_UnreliableFragment; }; using ENetPacketFlags = Flags; From 5655ff3fcf51de82a2cb8c9d984aed4d2956cd7a Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 12 Feb 2017 02:19:27 +0100 Subject: [PATCH 25/73] Network/ENetPacketFlags: Add Unreliable flag typedef for zero --- include/Nazara/Network/ENetPacket.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/Nazara/Network/ENetPacket.hpp b/include/Nazara/Network/ENetPacket.hpp index 5aecb0edd..54b0c42c6 100644 --- a/include/Nazara/Network/ENetPacket.hpp +++ b/include/Nazara/Network/ENetPacket.hpp @@ -28,6 +28,8 @@ namespace Nz using ENetPacketFlags = Flags; + constexpr ENetPacketFlags ENetPacketFlag_Unreliable = 0; + class MemoryPool; struct ENetPacket From 1904ce1576d914e1f265eb575c8a8d7b5ad9fb16 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 12 Feb 2017 02:21:00 +0100 Subject: [PATCH 26/73] Network/ENetPeer: Fix fragmented packet handling --- src/Nazara/Network/ENetPeer.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 88b5568ff..6f0824af6 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -205,32 +205,24 @@ namespace Nz if (packetSize > fragmentLength) { UInt32 fragmentCount = (packetSize + fragmentLength - 1) / fragmentLength; - UInt32 fragmentNumber; - UInt32 fragmentOffset; - - UInt8 commandNumber; - UInt16 startSequenceNumber; - if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount) return false; + UInt8 commandNumber; + UInt16 startSequenceNumber; if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_UnreliableFragment)) == ENetPacketFlag_UnreliableFragment && channel.outgoingUnreliableSequenceNumber < 0xFFFF) { commandNumber = ENetProtocolCommand_SendUnreliable; - startSequenceNumber = HostToNet(channel.outgoingUnreliableSequenceNumber + 1); + startSequenceNumber = HostToNet(channel.outgoingUnreliableSequenceNumber + 1); } else { commandNumber = ENetProtocolCommand_SendFragment | ENetProtocolFlag_Acknowledge; - startSequenceNumber = HostToNet(channel.outgoingReliableSequenceNumber + 1); + startSequenceNumber = HostToNet(channel.outgoingReliableSequenceNumber + 1); } - for (fragmentNumber = 0, - fragmentOffset = 0; - fragmentOffset < packetSize; - ++fragmentNumber, - fragmentOffset += fragmentLength) + for (UInt32 fragmentNumber = 0, fragmentOffset = 0; fragmentOffset < packetSize; ++fragmentNumber, fragmentOffset += fragmentLength) { if (packetSize - fragmentOffset < fragmentLength) fragmentLength = UInt16(packetSize - fragmentOffset); From 890b06bfcb796feb8bd8935a7f07fda205731c7a Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 15 Feb 2017 08:26:56 +0100 Subject: [PATCH 27/73] Network/ENet: Refactor --- include/Nazara/Network/ENetPeer.hpp | 4 ++++ include/Nazara/Network/ENetPeer.inl | 20 ++++++++++++++++++++ src/Nazara/Network/ENetHost.cpp | 28 +++++++++++++++------------- src/Nazara/Network/ENetPeer.cpp | 2 +- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index e2b76c54a..2d11f17a0 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -50,6 +50,10 @@ namespace Nz void DisconnectNow(UInt32 data); inline const IpAddress& GetAddress() const; + inline UInt32 GetMtu() const; + inline UInt32 GetPacketThrottleAcceleration() const; + inline UInt32 GetPacketThrottleDeceleration() const; + inline UInt32 GetPacketThrottleInterval() const; inline UInt16 GetPeerId() const; inline ENetPeerState GetState() const; diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index 324a1fb80..fdac3ab4d 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -13,6 +13,26 @@ namespace Nz return m_address; } + inline UInt32 ENetPeer::GetMtu() const + { + return m_mtu; + } + + inline UInt32 ENetPeer::GetPacketThrottleAcceleration() const + { + return m_packetThrottleAcceleration; + } + + inline UInt32 ENetPeer::GetPacketThrottleDeceleration() const + { + return m_packetThrottleDeceleration; + } + + inline UInt32 ENetPeer::GetPacketThrottleInterval() const + { + return m_packetThrottleInterval; + } + inline UInt16 ENetPeer::GetPeerId() const { return m_incomingPeerID; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index aff71c9c3..c4223653c 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -335,12 +335,12 @@ namespace Nz void ENetHost::AddToDispatchQueue(ENetPeer* peer) { - m_dispatchQueue.UnboundedSet(peer->m_incomingPeerID); + m_dispatchQueue.UnboundedSet(peer->GetPeerId()); } void ENetHost::RemoveFromDispatchQueue(ENetPeer* peer) { - m_dispatchQueue.UnboundedReset(peer->m_incomingPeerID); + m_dispatchQueue.UnboundedReset(peer->GetPeerId()); } bool ENetHost::DispatchIncomingCommands(ENetEvent* event) @@ -446,18 +446,20 @@ namespace Nz windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); ENetProtocol verifyCommand(ENetProtocolCommand_VerifyConnect | ENetProtocolFlag_Acknowledge, 0xFF); - verifyCommand.verifyConnect.outgoingPeerID = HostToNet(peer->m_incomingPeerID); + verifyCommand.verifyConnect.connectID = peer->m_connectID; verifyCommand.verifyConnect.incomingSessionID = peer->m_outgoingSessionID; verifyCommand.verifyConnect.outgoingSessionID = peer->m_incomingSessionID; - verifyCommand.verifyConnect.mtu = HostToNet(peer->m_mtu); - verifyCommand.verifyConnect.windowSize = HostToNet(windowSize); + verifyCommand.verifyConnect.channelCount = HostToNet(channelCount); verifyCommand.verifyConnect.incomingBandwidth = HostToNet(m_incomingBandwidth); + verifyCommand.verifyConnect.mtu = HostToNet(peer->GetMtu()); verifyCommand.verifyConnect.outgoingBandwidth = HostToNet(m_outgoingBandwidth); - verifyCommand.verifyConnect.packetThrottleInterval = HostToNet(peer->m_packetThrottleInterval); - verifyCommand.verifyConnect.packetThrottleAcceleration = HostToNet(peer->m_packetThrottleAcceleration); - verifyCommand.verifyConnect.packetThrottleDeceleration = HostToNet(peer->m_packetThrottleDeceleration); - verifyCommand.verifyConnect.connectID = peer->m_connectID; + verifyCommand.verifyConnect.outgoingPeerID = HostToNet(peer->GetPeerId()); + verifyCommand.verifyConnect.packetThrottleAcceleration = HostToNet(peer->GetPacketThrottleAcceleration()); + verifyCommand.verifyConnect.packetThrottleDeceleration = HostToNet(peer->GetPacketThrottleDeceleration()); + verifyCommand.verifyConnect.packetThrottleInterval = HostToNet(peer->GetPacketThrottleInterval()); + verifyCommand.verifyConnect.windowSize = HostToNet(windowSize); + peer->QueueOutgoingCommand(verifyCommand); return peer; @@ -475,7 +477,7 @@ namespace Nz UInt16 flags = peerID & ENetProtocolHeaderFlag_Mask; peerID &= ~(ENetProtocolHeaderFlag_Mask | ENetProtocolHeaderSessionMask); - std::size_t headerSize = (flags & ENetProtocolHeaderFlag_SentTime ? sizeof(ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *)0)->sentTime); + std::size_t headerSize = (flags & ENetProtocolHeaderFlag_SentTime) ? sizeof(ENetProtocolHeader) : NazaraOffsetOf(ENetProtocolHeader, sentTime); ENetPeer* peer; if (peerID == ENetConstants::ENetProtocol_MaximumPeerId) @@ -491,7 +493,7 @@ namespace Nz if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie) return false; - if (m_receivedAddress != peer->m_address && peer->m_address != IpAddress::BroadcastIpV4) + if (m_receivedAddress != peer->GetAddress() && peer->GetAddress() != IpAddress::BroadcastIpV4) return false; if (peer->m_outgoingPeerID < ENetConstants::ENetProtocol_MaximumPeerId && sessionID != peer->m_incomingSessionID) @@ -771,7 +773,7 @@ namespace Nz auto currentAcknowledgement = peer->m_acknowledgements.begin(); while (currentAcknowledgement != peer->m_acknowledgements.end()) { - if (m_commandCount >= m_commands.size() || m_bufferCount >= m_buffers.size() || peer->m_mtu - m_packetSize < sizeof(ENetProtocolAcknowledge)) + if (m_commandCount >= m_commands.size() || m_bufferCount >= m_buffers.size() || peer->GetMtu() - m_packetSize < sizeof(ENetProtocolAcknowledge)) { m_continueSending = true; break; @@ -1013,7 +1015,7 @@ namespace Nz currentPeer->m_lastSendTime = m_serviceTime; std::size_t sentLength; - if (!m_socket.SendMultiple(currentPeer->m_address, m_buffers.data(), m_bufferCount, &sentLength)) + if (!m_socket.SendMultiple(currentPeer->GetAddress(), m_buffers.data(), m_bufferCount, &sentLength)) return -1; currentPeer->RemoveSentUnreliableCommands(); diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 6f0824af6..0408e6c50 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -845,7 +845,7 @@ namespace Nz if (!IsConnected()) return false; - m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); + m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); m_packetThrottleAcceleration = NetToHost(command->throttleConfigure.packetThrottleAcceleration); m_packetThrottleDeceleration = NetToHost(command->throttleConfigure.packetThrottleDeceleration); From 8225ad3b41708724bbfbce62a62943698e6e8c75 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 15 Feb 2017 08:27:15 +0100 Subject: [PATCH 28/73] Network/ENetHost: Optimize acknowledgements handling --- include/Nazara/Network/ENetPeer.hpp | 2 +- src/Nazara/Network/ENetHost.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 2d11f17a0..a9f2a0219 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -178,13 +178,13 @@ namespace Nz ENetHost* m_host; IpAddress m_address; /**< Internet address of the peer */ std::array m_unsequencedWindow; - std::list m_acknowledgements; std::list m_dispatchedCommands; std::list m_outgoingReliableCommands; std::list m_outgoingUnreliableCommands; std::list m_sentReliableCommands; std::list m_sentUnreliableCommands; std::size_t m_totalWaitingData; + std::vector m_acknowledgements; std::vector m_channels; MemoryPool m_packetPool; ENetPeerState m_state; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index c4223653c..6f6c740ad 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -770,8 +770,8 @@ namespace Nz void ENetHost::SendAcknowledgements(ENetPeer* peer) { - auto currentAcknowledgement = peer->m_acknowledgements.begin(); - while (currentAcknowledgement != peer->m_acknowledgements.end()) + auto it = peer->m_acknowledgements.begin(); + for (; it != peer->m_acknowledgements.end(); ++it) { if (m_commandCount >= m_commands.size() || m_bufferCount >= m_buffers.size() || peer->GetMtu() - m_packetSize < sizeof(ENetProtocolAcknowledge)) { @@ -779,7 +779,7 @@ namespace Nz break; } - ENetPeer::Acknowledgement& acknowledgement = *currentAcknowledgement; + ENetPeer::Acknowledgement& acknowledgement = *it; ENetProtocol& command = m_commands[m_commandCount]; NetBuffer& buffer = m_buffers[m_bufferCount]; @@ -800,11 +800,11 @@ namespace Nz if ((acknowledgement.command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_Disconnect) peer->DispatchState(ENetPeerState::Zombie); - currentAcknowledgement = peer->m_acknowledgements.erase(currentAcknowledgement); - ++m_bufferCount; ++m_commandCount; } + + peer->m_acknowledgements.erase(peer->m_acknowledgements.begin(), it); } bool ENetHost::SendReliableOutgoingCommands(ENetPeer* peer) From dee5986de5af8d1d31e3db897ed7dcd0e5e3d103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 16 Feb 2017 16:14:24 +0100 Subject: [PATCH 29/73] Network/NetPacket: Allow empty pointer for NetPacket creating (won't initialize memory) --- include/Nazara/Network/NetPacket.inl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/Nazara/Network/NetPacket.inl b/include/Nazara/Network/NetPacket.inl index 6d55831d4..eb68d1e53 100644 --- a/include/Nazara/Network/NetPacket.inl +++ b/include/Nazara/Network/NetPacket.inl @@ -155,7 +155,9 @@ namespace Nz { InitStream(HeaderSize + size, HeaderSize, OpenMode_ReadOnly); m_buffer->Resize(HeaderSize + size); - std::memcpy(m_buffer->GetBuffer() + HeaderSize, ptr, size); + + if (ptr) + std::memcpy(m_buffer->GetBuffer() + HeaderSize, ptr, size); m_netCode = netCode; } From 7b49b3dd0e342db9ac6e6b092779d70bbe09d57b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 16 Feb 2017 16:14:40 +0100 Subject: [PATCH 30/73] Network/ENetPeer: Fix crash when handling fragment packets --- src/Nazara/Network/ENetPeer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 6f0824af6..c343e7913 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -651,12 +651,13 @@ namespace Nz } } - if (startCommand) + if (!startCommand) { ENetProtocol hostCommand = *command; hostCommand.header.reliableSequenceNumber = startSequenceNumber; - if (!QueueIncomingCommand(hostCommand, nullptr, totalLength, ENetPacketFlag_Reliable, fragmentCount)) + startCommand = QueueIncomingCommand(hostCommand, nullptr, totalLength, ENetPacketFlag_Reliable, fragmentCount); + if (!startCommand) return false; } From b7ee6d7b29e7466ce012523d70bf63164c8de55c Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 16 Feb 2017 23:26:00 +0100 Subject: [PATCH 31/73] Network/ENet: Move all packet allocation to host --- include/Nazara/Network/ENetHost.hpp | 3 +++ include/Nazara/Network/ENetHost.inl | 8 ++++++++ include/Nazara/Network/ENetPeer.hpp | 4 +--- include/Nazara/Network/ENetPeer.inl | 9 +++++++++ src/Nazara/Network/ENetHost.cpp | 21 ++++++++++++++------- src/Nazara/Network/ENetPeer.cpp | 21 ++------------------- 6 files changed, 37 insertions(+), 29 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 83e8fd147..b1304ab81 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -71,6 +71,9 @@ namespace Nz ENetHost& operator=(ENetHost&&) = default; private: + ENetPacketRef AllocatePacket(ENetPacketFlags flags); + inline ENetPacketRef AllocatePacket(ENetPacketFlags flags, NetPacket&& data); + bool InitSocket(const IpAddress& address); void AddToDispatchQueue(ENetPeer* peer); diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index 8aa722771..9a70d9b78 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -56,6 +56,14 @@ namespace Nz { return m_serviceTime; } + + inline ENetPacketRef ENetHost::AllocatePacket(ENetPacketFlags flags, NetPacket&& data) + { + ENetPacketRef ref = AllocatePacket(flags); + ref->data = std::move(data); + + return ref; + } } #include diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index a9f2a0219..19144c2f2 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +39,7 @@ namespace Nz friend struct PacketRef; public: - ENetPeer(ENetHost* host, UInt16 peerId); + inline ENetPeer(ENetHost* host, UInt16 peerId); ENetPeer(const ENetPeer&) = delete; ENetPeer(ENetPeer&&) = default; ~ENetPeer() = default; @@ -186,7 +185,6 @@ namespace Nz std::size_t m_totalWaitingData; std::vector m_acknowledgements; std::vector m_channels; - MemoryPool m_packetPool; ENetPeerState m_state; UInt8 m_incomingSessionID; UInt8 m_outgoingSessionID; diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index fdac3ab4d..e9c15fe35 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -8,6 +8,15 @@ namespace Nz { + inline ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : + m_host(host), + m_incomingSessionID(0xFF), + m_outgoingSessionID(0xFF), + m_incomingPeerID(peerId) + { + Reset(); + } + inline const IpAddress& ENetPeer::GetAddress() const { return m_address; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 6f6c740ad..76c81eb38 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -45,10 +45,7 @@ namespace Nz void ENetHost::Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) { - ENetPacketRef enetPacket = m_packetPool.New(); - enetPacket->flags = flags; - enetPacket->data = std::move(packet); - enetPacket->owner = &m_packetPool; + ENetPacketRef enetPacket = AllocatePacket(flags, std::move(packet)); for (ENetPeer& peer : m_peers) { @@ -309,6 +306,15 @@ namespace Nz } } + ENetPacketRef ENetHost::AllocatePacket(ENetPacketFlags flags) + { + ENetPacketRef enetPacket = m_packetPool.New(); + enetPacket->flags = flags; + enetPacket->owner = &m_packetPool; + + return enetPacket; + } + bool ENetHost::InitSocket(const IpAddress& address) { if (!m_socket.Create(address.GetProtocol())) @@ -841,7 +847,7 @@ namespace Nz { UInt32 windowSize = (peer->m_packetThrottle * peer->m_windowSize) / ENetPeer_PacketThrottleScale; - if (peer->m_reliableDataInTransit + outgoingCommand->fragmentLength > std::max(windowSize, peer->m_mtu)) + if (peer->m_reliableDataInTransit + outgoingCommand->fragmentLength > std::max(windowSize, peer->GetMtu())) windowExceeded = true; } @@ -855,8 +861,8 @@ namespace Nz canPing = false; std::size_t commandSize = s_commandSizes[outgoingCommand->command.header.command & ENetProtocolCommand_Mask]; - if (m_commandCount >= m_commands.size() || m_bufferCount + 1 >= m_buffers.size() || peer->m_mtu - m_packetSize < commandSize || - (outgoingCommand->packet && UInt16(peer->m_mtu - m_packetSize) < UInt16(commandSize + outgoingCommand->fragmentLength))) + if (m_commandCount >= m_commands.size() || m_bufferCount + 1 >= m_buffers.size() || peer->GetMtu() - m_packetSize < commandSize || + (outgoingCommand->packet && UInt16(peer->GetMtu() - m_packetSize) < UInt16(commandSize + outgoingCommand->fragmentLength))) { m_continueSending = true; break; @@ -1092,6 +1098,7 @@ namespace Nz m_packetSize += packetBuffer.dataLength; + // In order to keep the packet buffer alive until we send it, place it into a temporary queue peer->m_sentUnreliableCommands.emplace_back(std::move(*outgoingCommand)); } diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 0408e6c50..3bdfb7537 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -20,16 +20,6 @@ namespace Nz { - ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : - m_host(host), - m_packetPool(sizeof(ENetPacket)), - m_incomingSessionID(0xFF), - m_outgoingSessionID(0xFF), - m_incomingPeerID(peerId) - { - Reset(); - } - void ENetPeer::Disconnect(UInt32 data) { if (m_state == ENetPeerState::Disconnecting || @@ -184,12 +174,7 @@ namespace Nz bool ENetPeer::Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) { - ENetPacket* enetPacket = m_packetPool.New(); - enetPacket->flags = flags; - enetPacket->data = std::move(packet); - enetPacket->owner = &m_packetPool; - - return Send(channelId, enetPacket); + return Send(channelId, m_host->AllocatePacket(flags, std::move(packet)); } bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef) @@ -1214,10 +1199,8 @@ namespace Nz if (m_totalWaitingData >= m_host->m_maximumWaitingData) return nullptr; - ENetPacket* packet = m_packetPool.New(); - packet->flags = flags; + ENetPacketRef packet = m_host->AllocatePacket(flags); packet->data.Reset(0, data, dataLength); - packet->owner = &m_packetPool; IncomingCommmand incomingCommand; incomingCommand.reliableSequenceNumber = command.header.reliableSequenceNumber; From e0dca1b043a8af9d08248456877205936a2178e7 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 16 Feb 2017 23:26:28 +0100 Subject: [PATCH 32/73] Network/ENetPeer: Optimize CheckTimeouts function --- src/Nazara/Network/ENetPeer.cpp | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 3bdfb7537..d9ca262cb 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -271,39 +271,38 @@ namespace Nz bool ENetPeer::CheckTimeouts(ENetEvent* event) { UInt32 serviceTime = m_host->GetServiceTime(); + bool timedOut = false; - auto currentCommand = m_sentReliableCommands.begin(); - while (currentCommand != m_sentReliableCommands.end()) + auto it = m_sentReliableCommands.begin(); + for (; it != m_sentReliableCommands.end(); ++it) { - auto outgoingCommand = currentCommand; + OutgoingCommand& command = *it; - ++currentCommand; - - if (ENetTimeDifference(serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) + if (ENetTimeDifference(serviceTime, command.sentTime) < command.roundTripTimeout) continue; - if (m_earliestTimeout == 0 || ENetTimeLess(outgoingCommand->sentTime, m_earliestTimeout)) - m_earliestTimeout = outgoingCommand->sentTime; + if (m_earliestTimeout == 0 || ENetTimeLess(command.sentTime, m_earliestTimeout)) + m_earliestTimeout = command.sentTime; if (m_earliestTimeout != 0 && (ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMaximum || - (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) + (command.roundTripTimeout >= command.roundTripTimeoutLimit && ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) { m_host->NotifyDisconnect(this, event); - return true; + timedOut = true; + break; } - if (outgoingCommand->packet) - m_reliableDataInTransit -= outgoingCommand->fragmentLength; + if (command.packet) + m_reliableDataInTransit -= command.fragmentLength; ++m_packetsLost; ++m_totalPacketLost; // http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html - outgoingCommand->roundTripTimeout = m_roundTripTime + 4 * m_roundTripTimeVariance; - outgoingCommand->roundTripTimeoutLimit = m_timeoutLimit * outgoingCommand->roundTripTimeout; + command.roundTripTimeout = m_roundTripTime + 4 * m_roundTripTimeVariance; + command.roundTripTimeoutLimit = m_timeoutLimit * command.roundTripTimeout; - m_outgoingReliableCommands.emplace_front(std::move(*outgoingCommand)); - m_sentReliableCommands.erase(outgoingCommand); + m_outgoingReliableCommands.emplace_front(std::move(command)); // Okay this should just never procs, I don't see how it would be possible /*if (currentCommand == enet_list_begin(&peer->sentReliableCommands) && @@ -315,7 +314,9 @@ namespace Nz }*/ } - return false; + m_sentReliableCommands.erase(m_sentReliableCommands.begin(), it); + + return timedOut; } void ENetPeer::DispatchState(ENetPeerState state) From 490f6becb21446bcfc9732c5727409d30a7f6511 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 16 Feb 2017 23:37:28 +0100 Subject: [PATCH 33/73] Fix compilation... That parenthesis probably didn't make it to GitHub, damn you packet losses! --- src/Nazara/Network/ENetPeer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 94e223ae9..9e7b3802d 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -174,7 +174,7 @@ namespace Nz bool ENetPeer::Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) { - return Send(channelId, m_host->AllocatePacket(flags, std::move(packet)); + return Send(channelId, m_host->AllocatePacket(flags, std::move(packet))); } bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef) From cc57fed42e0d4605c50f46a96de778d60db9a64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 17 Feb 2017 17:30:27 +0100 Subject: [PATCH 34/73] Network/ENetPeer: Fix crash --- src/Nazara/Network/ENetPeer.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 9e7b3802d..e7a39e3e5 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -271,7 +271,6 @@ namespace Nz bool ENetPeer::CheckTimeouts(ENetEvent* event) { UInt32 serviceTime = m_host->GetServiceTime(); - bool timedOut = false; auto it = m_sentReliableCommands.begin(); for (; it != m_sentReliableCommands.end(); ++it) @@ -288,8 +287,7 @@ namespace Nz (command.roundTripTimeout >= command.roundTripTimeoutLimit && ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) { m_host->NotifyDisconnect(this, event); - timedOut = true; - break; + return true; } if (command.packet) @@ -316,7 +314,7 @@ namespace Nz m_sentReliableCommands.erase(m_sentReliableCommands.begin(), it); - return timedOut; + return false; } void ENetPeer::DispatchState(ENetPeerState state) From b0d0a63fcac4b3d67bd2f16a7dc25dc3754899da Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 20 Feb 2017 23:37:31 +0100 Subject: [PATCH 35/73] Network/ENet: Add peer-side lag simulation --- include/Nazara/Network/ENetHost.hpp | 12 +++- include/Nazara/Network/ENetPeer.hpp | 7 +++ include/Nazara/Network/ENetPeer.inl | 8 ++- include/Nazara/Network/ENetProtocol.hpp | 2 +- src/Nazara/Network/ENetHost.cpp | 75 +++++++++++++++++++++---- src/Nazara/Network/ENetPeer.cpp | 14 +++++ 6 files changed, 104 insertions(+), 14 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index b1304ab81..edb9155ab 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -100,13 +100,20 @@ namespace Nz static bool Initialize(); static void Uninitialize(); - struct PendingPacket + struct PendingIncomingPacket { IpAddress from; NetPacket data; UInt32 deliveryTime; }; + struct PendingOutgoingPacket + { + IpAddress to; + NetPacket data; + UInt32 deliveryTime; + }; + std::array m_commands; std::array m_buffers; std::array m_packetData[2]; @@ -123,7 +130,8 @@ namespace Nz std::size_t m_receivedDataLength; std::uniform_int_distribution m_packetDelayDistribution; std::vector m_peers; - std::vector m_pendingPackets; + std::vector m_pendingIncomingPackets; + std::vector m_pendingOutgoingPackets; UInt8* m_receivedData; Bitset m_dispatchQueue; MemoryPool m_packetPool; diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index 19144c2f2..e3538e6fb 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include namespace Nz @@ -59,6 +60,7 @@ namespace Nz inline bool HasPendingCommands(); inline bool IsConnected() const; + inline bool IsSimulationEnabled() const; void Ping(); @@ -68,6 +70,8 @@ namespace Nz bool Send(UInt8 channelId, ENetPacketRef packetRef); bool Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet); + void SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay); + void ThrottleConfigure(UInt32 interval, UInt32 acceleration, UInt32 deceleration); ENetPeer& operator=(const ENetPeer&) = delete; @@ -177,12 +181,14 @@ namespace Nz ENetHost* m_host; IpAddress m_address; /**< Internet address of the peer */ std::array m_unsequencedWindow; + std::bernoulli_distribution m_packetLossProbability; std::list m_dispatchedCommands; std::list m_outgoingReliableCommands; std::list m_outgoingUnreliableCommands; std::list m_sentReliableCommands; std::list m_sentUnreliableCommands; std::size_t m_totalWaitingData; + std::uniform_int_distribution m_packetDelayDistribution; std::vector m_acknowledgements; std::vector m_channels; ENetPeerState m_state; @@ -232,6 +238,7 @@ namespace Nz UInt32 m_windowSize; UInt64 m_totalPacketLost; UInt64 m_totalPacketSent; + bool m_isSimulationEnabled; }; } diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index e9c15fe35..bcec4a8c1 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -12,7 +12,8 @@ namespace Nz m_host(host), m_incomingSessionID(0xFF), m_outgoingSessionID(0xFF), - m_incomingPeerID(peerId) + m_incomingPeerID(peerId), + m_isSimulationEnabled(false) { Reset(); } @@ -62,6 +63,11 @@ namespace Nz return m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater; } + inline bool ENetPeer::IsSimulationEnabled() const + { + return m_isSimulationEnabled; + } + inline void ENetPeer::ChangeState(ENetPeerState state) { if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater) diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp index e3df5e092..7cd613ab0 100644 --- a/include/Nazara/Network/ENetProtocol.hpp +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -28,7 +28,7 @@ namespace Nz { ENetHost_BandwidthThrottleInterval = 1000, ENetHost_DefaultMaximumPacketSize = 32 * 1024 * 1024, - ENetHost_DefaultMaximumWaitingData = 32 * 1024 * 1024, + ENetHost_DefaultMaximumWaitingData = 32 * 1024 * 1024, ENetHost_DefaultMTU = 1400, ENetHost_ReceiveBufferSize = 256 * 1024, ENetHost_SendBufferSize = 256 * 1024, diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 76c81eb38..84083b24d 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -672,7 +672,7 @@ namespace Nz if (m_isSimulationEnabled) { - for (auto it = m_pendingPackets.begin(); it != m_pendingPackets.end(); ++it) + for (auto it = m_pendingIncomingPackets.begin(); it != m_pendingIncomingPackets.end(); ++it) { if (m_serviceTime >= it->deliveryTime) { @@ -682,7 +682,7 @@ namespace Nz receivedLength = it->data.GetDataSize(); std::memcpy(m_packetData[0].data(), it->data.GetConstData() + NetPacket::HeaderSize, receivedLength); - m_pendingPackets.erase(it); + m_pendingIncomingPackets.erase(it); break; } } @@ -704,17 +704,17 @@ namespace Nz UInt16 delay = m_packetDelayDistribution(s_randomGenerator); if (delay > 0) { - PendingPacket pendingPacket; + PendingIncomingPacket pendingPacket; pendingPacket.deliveryTime = m_serviceTime + delay; pendingPacket.from = m_receivedAddress; pendingPacket.data.Reset(0, m_packetData[0].data(), receivedLength); - auto it = std::upper_bound(m_pendingPackets.begin(), m_pendingPackets.end(), pendingPacket, [] (const PendingPacket& first, const PendingPacket& second) + auto it = std::upper_bound(m_pendingIncomingPackets.begin(), m_pendingIncomingPackets.end(), pendingPacket, [] (const PendingIncomingPacket& first, const PendingIncomingPacket& second) { return first.deliveryTime < second.deliveryTime; }); - m_pendingPackets.emplace(it, std::move(pendingPacket)); + m_pendingIncomingPackets.emplace(it, std::move(pendingPacket)); continue; } } @@ -1020,17 +1020,72 @@ namespace Nz currentPeer->m_lastSendTime = m_serviceTime; - std::size_t sentLength; - if (!m_socket.SendMultiple(currentPeer->GetAddress(), m_buffers.data(), m_bufferCount, &sentLength)) - return -1; + // Simulate network by adding delay to packet sending and losing some packets + bool sendNow = true; + if (!currentPeer->IsSimulationEnabled()) + { + sendNow = false; + if (!currentPeer->m_packetLossProbability(s_randomGenerator)) + { + Nz::UInt16 delay = currentPeer->m_packetDelayDistribution(s_randomGenerator); + if (delay == 0) + sendNow = true; + else + { + PendingOutgoingPacket outgoingPacket; + outgoingPacket.deliveryTime = m_serviceTime + delay; + outgoingPacket.to = currentPeer->GetAddress(); + + // Accumulate every temporary buffer into a datagram + for (std::size_t i = 0; i < m_bufferCount; ++i) + { + NetBuffer& buffer = m_buffers[i]; + outgoingPacket.data.Write(buffer.data, buffer.dataLength); + } + + m_totalSentData += outgoingPacket.data.GetDataSize(); + + // Add it to the right place + auto it = std::upper_bound(m_pendingOutgoingPackets.begin(), m_pendingOutgoingPackets.end(), outgoingPacket, [](const PendingOutgoingPacket& first, const PendingOutgoingPacket& second) + { + return first.deliveryTime < second.deliveryTime; + }); + + m_pendingOutgoingPackets.emplace(it, std::move(outgoingPacket)); + } + } + } + + if (sendNow) + { + std::size_t sentLength = 0; + + if (!m_socket.SendMultiple(currentPeer->GetAddress(), m_buffers.data(), m_bufferCount, &sentLength)) + return -1; + + m_totalSentData += sentLength; + } currentPeer->RemoveSentUnreliableCommands(); - - m_totalSentData += sentLength; m_totalSentPackets++; } } + if (!m_pendingOutgoingPackets.empty()) + { + auto it = m_pendingOutgoingPackets.begin(); + for (; it != m_pendingOutgoingPackets.end(); ++it) + { + if (m_serviceTime < it->deliveryTime) + break; + + if (!m_socket.Send(it->to, it->data.GetConstData() + NetPacket::HeaderSize, it->data.GetDataSize(), nullptr)) + return -1; + } + + m_pendingOutgoingPackets.erase(m_pendingOutgoingPackets.begin(), it); + } + return 0; } diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index e7a39e3e5..1d28cae42 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -177,6 +177,20 @@ namespace Nz return Send(channelId, m_host->AllocatePacket(flags, std::move(packet))); } + void ENetPeer::SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay) + { + NazaraAssert(maxDelay >= minDelay, "Maximum delay cannot be greater than minimum delay"); + + if (packetLossProbability <= 0.0 && minDelay == 0 && maxDelay == 0) + m_isSimulationEnabled = false; + else + { + m_isSimulationEnabled = true; + m_packetDelayDistribution = std::uniform_int_distribution(minDelay, maxDelay); + m_packetLossProbability = std::bernoulli_distribution(packetLossProbability); + } + } + bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef) { if (m_state != ENetPeerState::Connected || channelId >= m_channels.size() || packetRef->data.GetDataSize() > m_host->m_maximumPacketSize) From 218d9f3974f627355dbf04c7a81994871f467e43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 21 Feb 2017 15:58:02 +0100 Subject: [PATCH 36/73] Network/ENetHost: Add GetBoundAddress() --- include/Nazara/Network/ENetHost.hpp | 1 + include/Nazara/Network/ENetHost.inl | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index edb9155ab..4941df353 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -61,6 +61,7 @@ namespace Nz void Flush(); + inline Nz::IpAddress GetBoundAddress() const; inline UInt32 GetServiceTime() const; int Service(ENetEvent* event, UInt32 timeout); diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index 9a70d9b78..3f35a8f39 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -52,6 +52,11 @@ namespace Nz m_socket.Close(); } + inline Nz::IpAddress ENetHost::GetBoundAddress() const + { + return m_address; + } + inline UInt32 Nz::ENetHost::GetServiceTime() const { return m_serviceTime; From a53a916399058c326e58fcf846ac89481197a169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 21 Feb 2017 16:55:05 +0100 Subject: [PATCH 37/73] Network/ENetHost: Fix simulation being always active --- src/Nazara/Network/ENetHost.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 84083b24d..d32b6d5f9 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -1022,7 +1022,7 @@ namespace Nz // Simulate network by adding delay to packet sending and losing some packets bool sendNow = true; - if (!currentPeer->IsSimulationEnabled()) + if (currentPeer->IsSimulationEnabled()) { sendNow = false; if (!currentPeer->m_packetLossProbability(s_randomGenerator)) From 14022ccee25e702fd4685eccaa644eb1ec651190 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 24 Feb 2017 10:15:13 +0100 Subject: [PATCH 38/73] Network/ENetPeer: Fix crash --- src/Nazara/Network/ENetPeer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 1d28cae42..5407fec35 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -986,7 +986,7 @@ namespace Nz if (currentCommand == m_sentReliableCommands.end()) { currentCommand = m_outgoingReliableCommands.begin(); - commandList = &m_sentReliableCommands; + commandList = &m_outgoingReliableCommands; for (; currentCommand != m_outgoingReliableCommands.end(); ++currentCommand) { found = true; From f2fb0f62c2dbb66270d0cbde3cc14dc37d60cf0f Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 2 Mar 2017 16:18:34 +0100 Subject: [PATCH 39/73] Switch ENet errors to Nazara --- src/Nazara/Network/ENetHost.cpp | 37 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index d32b6d5f9..6f726b644 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -224,9 +224,7 @@ namespace Nz return 1; case -1: - #ifdef ENET_DEBUG - perror("Error sending outgoing packets"); - #endif + NazaraError("Error sending outgoing packets"); return -1; default: @@ -235,34 +233,29 @@ namespace Nz switch (ReceiveIncomingCommands(event)) { - case 1: - return 1; + case 1: + return 1; - case -1: -#ifdef ENET_DEBUG - perror("Error receiving incoming packets"); -#endif + case -1: + NazaraError("Error receiving incoming packets"); + return -1; - return -1; - - default: - break; + default: + break; } switch (SendOutgoingCommands(event, true)) { - case 1: - return 1; + case 1: + return 1; - case -1: -#ifdef ENET_DEBUG - perror("Error sending outgoing packets"); -#endif + case -1: + NazaraError("Error sending outgoing packets"); - return -1; + return -1; - default: - break; + default: + break; } if (event) From b2e4296cc78f640c853b004b607654187ab35b2f Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 8 Mar 2017 21:05:56 +0100 Subject: [PATCH 40/73] Network/ENetHost: Fix peers default values not being initialized --- src/Nazara/Network/ENetHost.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 6f726b644..d4d1be9f9 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -156,10 +156,6 @@ namespace Nz if (!InitSocket(address)) return false; - m_peers.reserve(peerCount); - for (std::size_t i = 0; i < peerCount; ++i) - m_peers.emplace_back(this, UInt16(i)); - m_address = address; m_randomSeed = *reinterpret_cast(this); m_randomSeed += s_randomGenerator(); @@ -188,6 +184,10 @@ namespace Nz m_maximumPacketSize = ENetConstants::ENetHost_DefaultMaximumPacketSize; m_maximumWaitingData = ENetConstants::ENetHost_DefaultMaximumWaitingData; + m_peers.reserve(peerCount); + for (std::size_t i = 0; i < peerCount; ++i) + m_peers.emplace_back(this, UInt16(i)); + return true; } From 1917a0e8dd9a578bdc32bb8141029aab0e77fac0 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 8 Mar 2017 21:06:09 +0100 Subject: [PATCH 41/73] Network/ENetPeer: Fix fragments handling --- src/Nazara/Network/ENetPeer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 5407fec35..2a9adfcbf 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -674,7 +674,7 @@ namespace Nz DispatchIncomingReliableCommands(channel); } - return false; + return true; } bool ENetPeer::HandleSendReliable(const ENetProtocol* command, UInt8** data) From a4fe005e3b0a203610df2f4c780d561740a23009 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 8 Mar 2017 22:40:15 +0100 Subject: [PATCH 42/73] Network/ENetPeer: Fix packets not being resend after timeout sometimes --- src/Nazara/Network/ENetPeer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 2a9adfcbf..5ce92a1e4 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -287,12 +287,15 @@ namespace Nz UInt32 serviceTime = m_host->GetServiceTime(); auto it = m_sentReliableCommands.begin(); - for (; it != m_sentReliableCommands.end(); ++it) + for (; it != m_sentReliableCommands.end();) { OutgoingCommand& command = *it; if (ENetTimeDifference(serviceTime, command.sentTime) < command.roundTripTimeout) + { + ++it; continue; + } if (m_earliestTimeout == 0 || ENetTimeLess(command.sentTime, m_earliestTimeout)) m_earliestTimeout = command.sentTime; @@ -315,6 +318,7 @@ namespace Nz command.roundTripTimeoutLimit = m_timeoutLimit * command.roundTripTimeout; m_outgoingReliableCommands.emplace_front(std::move(command)); + it = m_sentReliableCommands.erase(it); // Okay this should just never procs, I don't see how it would be possible /*if (currentCommand == enet_list_begin(&peer->sentReliableCommands) && @@ -326,8 +330,6 @@ namespace Nz }*/ } - m_sentReliableCommands.erase(m_sentReliableCommands.begin(), it); - return false; } From c9969d1b579934d2fe742fc4d053be76186a1ff7 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 11 May 2017 21:21:25 +0200 Subject: [PATCH 43/73] Sdk/BaseComponent: Disable implicit copying --- SDK/include/NDK/BaseComponent.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/SDK/include/NDK/BaseComponent.hpp b/SDK/include/NDK/BaseComponent.hpp index d9fdcba45..e6dfb5ed9 100644 --- a/SDK/include/NDK/BaseComponent.hpp +++ b/SDK/include/NDK/BaseComponent.hpp @@ -23,7 +23,6 @@ namespace Ndk using Factory = std::function; BaseComponent(ComponentIndex componentIndex); - BaseComponent(const BaseComponent&) = default; BaseComponent(BaseComponent&&) = default; virtual ~BaseComponent(); @@ -34,7 +33,7 @@ namespace Ndk inline static ComponentIndex GetMaxComponentIndex(); - BaseComponent& operator=(const BaseComponent&) = default; + BaseComponent& operator=(const BaseComponent&) = delete; BaseComponent& operator=(BaseComponent&&) = default; protected: @@ -44,6 +43,8 @@ namespace Ndk static ComponentIndex RegisterComponent(ComponentId id, Factory factoryFunc); private: + BaseComponent(const BaseComponent&) = default; + virtual void OnAttached(); virtual void OnComponentAttached(BaseComponent& component); virtual void OnComponentDetached(BaseComponent& component); From 4a0cb4e1f13c7e6082ebda206a9e07b7629915ed Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 11 May 2017 21:26:01 +0200 Subject: [PATCH 44/73] Sdk/World: Get rid of now useless trick in Clone method EntityHandle can no longer move in memory until a world update --- SDK/src/NDK/World.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDK/src/NDK/World.cpp b/SDK/src/NDK/World.cpp index 81b862df9..8b7b51186 100644 --- a/SDK/src/NDK/World.cpp +++ b/SDK/src/NDK/World.cpp @@ -152,7 +152,7 @@ namespace Ndk clone->AddComponent(std::move(component)); } - return GetEntity(clone->GetId()); + return clone; } /*! From 3d25501f9fb8e568fba36a6b3f4cfe79917a0216 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 13 May 2017 20:00:15 +0200 Subject: [PATCH 45/73] Sdk: Fix compilation --- SDK/include/NDK/BaseComponent.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDK/include/NDK/BaseComponent.hpp b/SDK/include/NDK/BaseComponent.hpp index e6dfb5ed9..427fb017e 100644 --- a/SDK/include/NDK/BaseComponent.hpp +++ b/SDK/include/NDK/BaseComponent.hpp @@ -37,14 +37,14 @@ namespace Ndk BaseComponent& operator=(BaseComponent&&) = default; protected: + BaseComponent(const BaseComponent&) = default; + ComponentIndex m_componentIndex; EntityHandle m_entity; static ComponentIndex RegisterComponent(ComponentId id, Factory factoryFunc); private: - BaseComponent(const BaseComponent&) = default; - virtual void OnAttached(); virtual void OnComponentAttached(BaseComponent& component); virtual void OnComponentDetached(BaseComponent& component); From bb3eebb9ccf21adc9e29ce4f9eb0f99952791888 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 14 May 2017 22:13:31 +0200 Subject: [PATCH 46/73] Sdk/EntityList: Automatically remove entities from lists on destruction --- SDK/include/NDK/Entity.hpp | 8 +++- SDK/include/NDK/Entity.inl | 20 +++++++--- SDK/include/NDK/EntityList.hpp | 5 ++- SDK/include/NDK/EntityList.inl | 55 ++++++++++++++++++++++++---- SDK/src/NDK/Entity.cpp | 9 ++++- SDK/src/NDK/Systems/RenderSystem.cpp | 6 --- 6 files changed, 81 insertions(+), 22 deletions(-) diff --git a/SDK/include/NDK/Entity.hpp b/SDK/include/NDK/Entity.hpp index e386100f8..5419da0d2 100644 --- a/SDK/include/NDK/Entity.hpp +++ b/SDK/include/NDK/Entity.hpp @@ -17,14 +17,17 @@ namespace Ndk { class BaseComponent; + class BaseSystem; class Entity; + class EntityList; class World; using EntityHandle = Nz::ObjectHandle; class NDK_API Entity : public Nz::HandledObject { - friend class BaseSystem; + friend BaseSystem; + friend EntityList; friend World; public: @@ -78,13 +81,16 @@ namespace Ndk inline Nz::Bitset<>& GetRemovedComponentBits(); + inline void RegisterEntityList(EntityList* list); inline void RegisterSystem(SystemIndex index); inline void SetWorld(World* world) noexcept; + inline void UnregisterEntityList(EntityList* list); inline void UnregisterSystem(SystemIndex index); std::vector> m_components; + std::vector m_containedInLists; Nz::Bitset<> m_componentBits; Nz::Bitset<> m_removedComponentBits; Nz::Bitset<> m_systemBits; diff --git a/SDK/include/NDK/Entity.inl b/SDK/include/NDK/Entity.inl index e6f997226..adb2153d8 100644 --- a/SDK/include/NDK/Entity.inl +++ b/SDK/include/NDK/Entity.inl @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -257,11 +258,10 @@ namespace Ndk return m_removedComponentBits; } - /*! - * \brief Registers a system for the entity - * - * \param index Index of the system - */ + inline void Entity::RegisterEntityList(EntityList* list) + { + m_containedInLists.push_back(list); + } inline void Entity::RegisterSystem(SystemIndex index) { @@ -289,6 +289,16 @@ namespace Ndk * \param index Index of the system */ + inline void Entity::UnregisterEntityList(EntityList* list) + { + auto it = std::find(m_containedInLists.begin(), m_containedInLists.end(), list); + assert(it != m_containedInLists.end()); + + // Swap and pop idiom + *it = m_containedInLists.back(); + m_containedInLists.pop_back(); + } + inline void Entity::UnregisterSystem(SystemIndex index) { m_systemBits.UnboundedReset(index); diff --git a/SDK/include/NDK/EntityList.hpp b/SDK/include/NDK/EntityList.hpp index 76097f87b..b659b15fb 100644 --- a/SDK/include/NDK/EntityList.hpp +++ b/SDK/include/NDK/EntityList.hpp @@ -15,6 +15,8 @@ namespace Ndk { class NDK_API EntityList { + friend Entity; + public: class iterator; friend iterator; @@ -23,7 +25,7 @@ namespace Ndk inline EntityList(); inline EntityList(const EntityList& entityList); inline EntityList(EntityList&& entityList) noexcept; - ~EntityList() = default; + inline ~EntityList(); inline void Clear(); @@ -46,6 +48,7 @@ namespace Ndk private: inline std::size_t FindNext(std::size_t currentId) const; inline World* GetWorld() const; + inline void NotifyEntityDestruction(const Entity* entity); Nz::Bitset m_entityBits; World* m_world; diff --git a/SDK/include/NDK/EntityList.inl b/SDK/include/NDK/EntityList.inl index f5a751323..d178d2b09 100644 --- a/SDK/include/NDK/EntityList.inl +++ b/SDK/include/NDK/EntityList.inl @@ -5,7 +5,6 @@ #include #include #include -#include "EntityList.hpp" namespace Ndk { @@ -30,6 +29,8 @@ namespace Ndk m_entityBits(entityList.m_entityBits), m_world(entityList.m_world) { + for (const Ndk::EntityHandle& entity : *this) + entity->RegisterEntityList(this); } /*! @@ -39,6 +40,17 @@ namespace Ndk m_entityBits(std::move(entityList.m_entityBits)), m_world(entityList.m_world) { + for (const Ndk::EntityHandle& entity : *this) + { + entity->UnregisterEntityList(&entityList); + entity->RegisterEntityList(this); + } + } + + inline EntityList::~EntityList() + { + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); } @@ -49,6 +61,9 @@ namespace Ndk */ inline void EntityList::Clear() { + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + m_entityBits.Clear(); m_world = nullptr; } @@ -88,15 +103,18 @@ namespace Ndk * * \remark If entity is already contained, no action is performed * \remark If any entity has been inserted since construction (or last Clear call), the entity must belong to the same world as the previously inserted entities - * \remark It's up to the programmer to remove an entity from this list before its deletion */ inline void EntityList::Insert(Entity* entity) { NazaraAssert(entity, "Invalid entity"); - NazaraAssert(!m_world || entity->GetWorld() == m_world, "Incompatible world"); - m_entityBits.UnboundedSet(entity->GetId(), true); - m_world = entity->GetWorld(); + if (!Has(entity)) + { + entity->RegisterEntityList(this); + + m_entityBits.UnboundedSet(entity->GetId(), true); + m_world = entity->GetWorld(); + } } /*! @@ -111,7 +129,12 @@ namespace Ndk */ inline void EntityList::Remove(Entity* entity) { - m_entityBits.UnboundedSet(entity->GetId(), false); + if (Has(entity)) + { + m_entityBits.Reset(entity->GetId()); + + entity->UnregisterEntityList(this); + } } // STL Interface @@ -140,14 +163,23 @@ namespace Ndk m_entityBits = entityList.m_entityBits; m_world = entityList.m_world; + for (const Ndk::EntityHandle& entity : *this) + entity->RegisterEntityList(this); + return *this; } - inline EntityList& EntityList::operator=(EntityList && entityList) noexcept + inline EntityList& EntityList::operator=(EntityList&& entityList) noexcept { m_entityBits = std::move(entityList.m_entityBits); m_world = entityList.m_world; + for (const Ndk::EntityHandle& entity : *this) + { + entity->UnregisterEntityList(&entityList); + entity->RegisterEntityList(this); + } + return *this; } @@ -161,6 +193,13 @@ namespace Ndk return m_world; } + inline void EntityList::NotifyEntityDestruction(const Entity* entity) + { + assert(Has(entity)); + + m_entityBits.Reset(entity->GetId()); + } + inline EntityList::iterator::iterator(const EntityList* list, std::size_t nextId) : m_nextEntityId(nextId), @@ -216,6 +255,6 @@ namespace Ndk using std::swap; - std::swap(lhs.m_nextEntityId, rhs.m_nextEntityId); + swap(lhs.m_nextEntityId, rhs.m_nextEntityId); } } diff --git a/SDK/src/NDK/Entity.cpp b/SDK/src/NDK/Entity.cpp index 7419ac627..fab08b237 100644 --- a/SDK/src/NDK/Entity.cpp +++ b/SDK/src/NDK/Entity.cpp @@ -23,6 +23,7 @@ namespace Ndk Entity::Entity(Entity&& entity) : HandledObject(std::move(entity)), m_components(std::move(entity.m_components)), + m_containedInLists(std::move(entity.m_containedInLists)), m_componentBits(std::move(entity.m_componentBits)), m_removedComponentBits(std::move(entity.m_removedComponentBits)), m_systemBits(std::move(entity.m_systemBits)), @@ -176,9 +177,15 @@ namespace Ndk m_components.clear(); m_componentBits.Reset(); - // And then free every handle + // Free every handle UnregisterAllHandles(); + // Remove from every list + for (EntityList* list : m_containedInLists) + list->NotifyEntityDestruction(this); + + m_containedInLists.clear(); + m_valid = false; } diff --git a/SDK/src/NDK/Systems/RenderSystem.cpp b/SDK/src/NDK/Systems/RenderSystem.cpp index 44b0d1bba..022621596 100644 --- a/SDK/src/NDK/Systems/RenderSystem.cpp +++ b/SDK/src/NDK/Systems/RenderSystem.cpp @@ -57,12 +57,6 @@ namespace Ndk } } - m_directionalLights.Remove(entity); - m_drawables.Remove(entity); - m_lights.Remove(entity); - m_particleGroups.Remove(entity); - m_pointSpotLights.Remove(entity); - if (entity->HasComponent()) { GraphicsComponent& gfxComponent = entity->GetComponent(); From 7425993d2deb725312543deaa205a761f9c99ed4 Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 15 May 2017 10:11:42 +0200 Subject: [PATCH 47/73] SDK/World: Fix waiting entities not being cleared on time --- SDK/src/NDK/World.cpp | 1 + tests/SDK/NDK/Systems/ListenerSystem.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SDK/src/NDK/World.cpp b/SDK/src/NDK/World.cpp index 8b7b51186..3ed1a25d0 100644 --- a/SDK/src/NDK/World.cpp +++ b/SDK/src/NDK/World.cpp @@ -119,6 +119,7 @@ namespace Ndk // This is made to avoid that handle warn uselessly entities before their destruction m_entities.clear(); m_entityBlocks.clear(); + m_waitingEntities.clear(); m_aliveEntities.Clear(); m_dirtyEntities.Clear(); diff --git a/tests/SDK/NDK/Systems/ListenerSystem.cpp b/tests/SDK/NDK/Systems/ListenerSystem.cpp index 2792dbc25..b83b24cd1 100644 --- a/tests/SDK/NDK/Systems/ListenerSystem.cpp +++ b/tests/SDK/NDK/Systems/ListenerSystem.cpp @@ -11,7 +11,7 @@ SCENARIO("ListenerSystem", "[NDK][LISTENERSYSTEM]") GIVEN("A world and an entity with listener & node components") { Ndk::World world; - const Ndk::EntityHandle& entity = world.CreateEntity(); + Ndk::EntityHandle entity = world.CreateEntity(); Ndk::ListenerComponent& listenerComponent = entity->AddComponent(); Ndk::NodeComponent& nodeComponent = entity->AddComponent(); From 65d3b59e03613233bddbf8cf3ec1c716a5e5e124 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 May 2017 09:07:28 +0200 Subject: [PATCH 48/73] Network/SocketPoller: Makes it possible to watch read and write states --- include/Nazara/Network/Enums.hpp | 19 +++- include/Nazara/Network/SocketPoller.hpp | 7 +- src/Nazara/Network/Linux/SocketPollerImpl.cpp | 45 ++++++--- src/Nazara/Network/Linux/SocketPollerImpl.hpp | 8 +- src/Nazara/Network/Posix/SocketPollerImpl.cpp | 46 ++++++--- src/Nazara/Network/Posix/SocketPollerImpl.hpp | 5 +- src/Nazara/Network/SocketPoller.cpp | 43 +++++++-- src/Nazara/Network/Win32/SocketPollerImpl.cpp | 96 +++++++++++-------- src/Nazara/Network/Win32/SocketPollerImpl.hpp | 16 ++-- 9 files changed, 192 insertions(+), 93 deletions(-) diff --git a/include/Nazara/Network/Enums.hpp b/include/Nazara/Network/Enums.hpp index f80ba6cd9..39bce0dd0 100644 --- a/include/Nazara/Network/Enums.hpp +++ b/include/Nazara/Network/Enums.hpp @@ -7,7 +7,7 @@ #ifndef NAZARA_ENUMS_NETWORK_HPP #define NAZARA_ENUMS_NETWORK_HPP -#include +#include namespace Nz { @@ -91,6 +91,23 @@ namespace Nz SocketError_Max = SocketError_UnreachableHost }; + enum SocketPollEvent + { + SocketPollEvent_Read, //< One or more sockets is ready for a read operation + SocketPollEvent_Write, //< One or more sockets is ready for a write operation + + SocketPollEvent_Max = SocketPollEvent_Write + }; + + template<> + struct EnumAsFlags + { + static constexpr bool value = true; + static constexpr int max = SocketPollEvent_Max; + }; + + using SocketPollEventFlags = Flags; + enum SocketState { SocketState_Bound, //< The socket is currently bound diff --git a/include/Nazara/Network/SocketPoller.hpp b/include/Nazara/Network/SocketPoller.hpp index 74f90c17f..c801ca5e2 100644 --- a/include/Nazara/Network/SocketPoller.hpp +++ b/include/Nazara/Network/SocketPoller.hpp @@ -24,10 +24,11 @@ namespace Nz void Clear(); - bool IsReady(const AbstractSocket& socket) const; + bool IsReadyToRead(const AbstractSocket& socket) const; + bool IsReadyToWrite(const AbstractSocket& socket) const; bool IsRegistered(const AbstractSocket& socket) const; - bool RegisterSocket(AbstractSocket& socket); + bool RegisterSocket(AbstractSocket& socket, SocketPollEventFlags eventFlags); void UnregisterSocket(AbstractSocket& socket); bool Wait(UInt64 msTimeout); @@ -41,4 +42,4 @@ namespace Nz #include -#endif // NAZARA_SOCKETPOLLER_HPP \ No newline at end of file +#endif // NAZARA_SOCKETPOLLER_HPP diff --git a/src/Nazara/Network/Linux/SocketPollerImpl.cpp b/src/Nazara/Network/Linux/SocketPollerImpl.cpp index c839d7352..6617efd37 100644 --- a/src/Nazara/Network/Linux/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Linux/SocketPollerImpl.cpp @@ -23,13 +23,19 @@ namespace Nz void SocketPollerImpl::Clear() { - m_activeSockets.clear(); + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); m_sockets.clear(); } - bool SocketPollerImpl::IsReady(SocketHandle socket) const + bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const { - return m_activeSockets.count(socket) != 0; + return m_readyToReadSockets.count(socket) != 0; + } + + bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const + { + return m_readyToWriteSockets.count(socket) != 0; } bool SocketPollerImpl::IsRegistered(SocketHandle socket) const @@ -37,15 +43,21 @@ namespace Nz return m_sockets.count(socket) != 0; } - bool SocketPollerImpl::RegisterSocket(SocketHandle socket) + bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags) { NazaraAssert(!IsRegistered(socket), "Socket is already registered"); - epoll_event event; - event.events = EPOLLIN; - event.data.fd = socket; + epoll_event entry; + entry.events = 0; + entry.data.fd = socket; - if (epoll_ctl(m_handle, EPOLL_CTL_ADD, socket, &event) != 0) + if (eventFlags & SocketPollEvent_Read) + entry.events |= EPOLLIN; + + if (eventFlags & SocketPollEvent_Write) + entry.events |= EPOLLOUT; + + if (epoll_ctl(m_handle, EPOLL_CTL_ADD, socket, &entry) != 0) { NazaraError("Failed to add socket to epoll structure (errno " + String::Number(errno) + ": " + Error::GetLastSystemError() + ')'); return false; @@ -60,7 +72,8 @@ namespace Nz { NazaraAssert(IsRegistered(socket), "Socket is not registered"); - m_activeSockets.erase(socket); + m_readyToReadSockets.erase(socket); + m_readyToWriteSockets.erase(socket); m_sockets.erase(socket); if (epoll_ctl(m_handle, EPOLL_CTL_DEL, socket, nullptr) != 0) @@ -84,21 +97,27 @@ namespace Nz return 0; } - m_activeSockets.clear(); + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); if (activeSockets > 0) { int socketCount = activeSockets; for (int i = 0; i < socketCount; ++i) { - if (m_events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) + if (m_events[i].events & (EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR)) { - m_activeSockets.insert(m_events[i].data.fd); + if (m_events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) + m_readyToReadSockets.insert(m_events[i].data.fd); + + if (m_events[i].events & (EPOLLOUT | EPOLLERR)) + m_readyToWriteSockets.insert(m_events[i].data.fd); + if (m_events[i].events & EPOLLERR) NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll with EPOLLERR status"); } else { - NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll without EPOLLIN (events: 0x" + String::Number(m_events[i].events, 16) + ')'); + NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll without EPOLLIN nor EPOLLOUT flags (events: 0x" + String::Number(m_events[i].events, 16) + ')'); activeSockets--; } } diff --git a/src/Nazara/Network/Linux/SocketPollerImpl.hpp b/src/Nazara/Network/Linux/SocketPollerImpl.hpp index 1c54471fc..a804102fa 100644 --- a/src/Nazara/Network/Linux/SocketPollerImpl.hpp +++ b/src/Nazara/Network/Linux/SocketPollerImpl.hpp @@ -23,16 +23,18 @@ namespace Nz void Clear(); - bool IsReady(SocketHandle socket) const; + bool IsReadyToRead(SocketHandle socket) const; + bool IsReadyToWrite(SocketHandle socket) const; bool IsRegistered(SocketHandle socket) const; - bool RegisterSocket(SocketHandle socket); + bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags); void UnregisterSocket(SocketHandle socket); int Wait(UInt64 msTimeout, SocketError* error); private: - std::unordered_set m_activeSockets; + std::unordered_set m_readyToReadSockets; + std::unordered_set m_readyToWriteSockets; std::unordered_set m_sockets; std::vector m_events; int m_handle; diff --git a/src/Nazara/Network/Posix/SocketPollerImpl.cpp b/src/Nazara/Network/Posix/SocketPollerImpl.cpp index 5d2a6c317..59b8a8ca7 100644 --- a/src/Nazara/Network/Posix/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Posix/SocketPollerImpl.cpp @@ -10,14 +10,20 @@ namespace Nz { void SocketPollerImpl::Clear() { - m_activeSockets.clear(); + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); m_allSockets.clear(); m_sockets.clear(); } - bool SocketPollerImpl::IsReady(SocketHandle socket) const + bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const { - return m_activeSockets.count(socket) != 0; + return m_readyToReadSockets.count(socket) != 0; + } + + bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const + { + return m_readyToWriteSockets.count(socket) != 0; } bool SocketPollerImpl::IsRegistered(SocketHandle socket) const @@ -25,16 +31,22 @@ namespace Nz return m_allSockets.count(socket) != 0; } - bool SocketPollerImpl::RegisterSocket(SocketHandle socket) + bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags) { NazaraAssert(!IsRegistered(socket), "Socket is already registered"); PollSocket entry = { socket, - POLLRDNORM, + 0, 0 }; + if (eventFlags & SocketPollEvent_Read) + entry.events |= POLLRDNORM; + + if (eventFlags & SocketPollEvent_Write) + entry.events |= POLLWRNORM; + m_allSockets[socket] = m_sockets.size(); m_sockets.emplace_back(entry); @@ -57,10 +69,11 @@ namespace Nz // Now move it properly (lastElement is invalid after the following line) and pop it m_sockets[entry] = std::move(m_sockets.back()); } - m_sockets.pop_back(); - m_activeSockets.erase(socket); + m_allSockets.erase(socket); + m_readyToReadSockets.erase(socket); + m_readyToWriteSockets.erase(socket); } int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error) @@ -68,20 +81,25 @@ namespace Nz int activeSockets; // Reset status of sockets - for (PollSocket& entry : m_sockets) - entry.revents = 0; - activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast(msTimeout), error); - m_activeSockets.clear(); - if (activeSockets > 0) + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); + if (activeSockets > 0U) { int socketRemaining = activeSockets; for (PollSocket& entry : m_sockets) { - if (entry.revents & POLLRDNORM) + if (entry.revents != 0) { - m_activeSockets.insert(entry.fd); + if (entry.revents & POLLRDNORM) + m_readyToReadSockets.insert(entry.fd); + + if (entry.revents & POLLWRNORM) + m_readyToWriteSockets.insert(entry.fd); + + entry.revents = 0; + if (--socketRemaining == 0) break; } diff --git a/src/Nazara/Network/Posix/SocketPollerImpl.hpp b/src/Nazara/Network/Posix/SocketPollerImpl.hpp index 3472c3265..3582121d4 100644 --- a/src/Nazara/Network/Posix/SocketPollerImpl.hpp +++ b/src/Nazara/Network/Posix/SocketPollerImpl.hpp @@ -27,13 +27,14 @@ namespace Nz bool IsReady(SocketHandle socket) const; bool IsRegistered(SocketHandle socket) const; - bool RegisterSocket(SocketHandle socket); + bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags); void UnregisterSocket(SocketHandle socket); int Wait(UInt64 msTimeout, SocketError* error); private: - std::unordered_set m_activeSockets; + std::unordered_set m_readyToReadSockets; + std::unordered_set m_readyToWriteSockets; std::unordered_map m_allSockets; std::vector m_sockets; }; diff --git a/src/Nazara/Network/SocketPoller.cpp b/src/Nazara/Network/SocketPoller.cpp index 43250a84f..7ef261ef9 100644 --- a/src/Nazara/Network/SocketPoller.cpp +++ b/src/Nazara/Network/SocketPoller.cpp @@ -57,12 +57,13 @@ namespace Nz /*! * \brief Checks if a specific socket is ready to read data * - * This function allows you to read the results of the last Wait operation and if a specific socket is ready. + * This function allows you to read the results of the last Wait operation and if a specific socket is ready to read (has incoming data). * - * A socket in the ready state (with the exception of TcpServer) has incoming data and can be read without blocking. + * A socket in the ready to read state (with the exception of TcpServer) has incoming data and can be read without blocking. * - * \remark When used on a TcpServer socket, this function returns true if the server is ready to accept a new client. - * \remark You must call Wait before using this function in order to refresh the state. + * \remark You must call Wait before using this function in order to refresh the read state. + * \remark A socket must be registered with SocketPollerEvent_Read event flag for its read state to be watched + * \remark A TcpServer socket becomes ready to read when it is ready to accept a new client. * * \param socket Reference to the socket to check * @@ -70,11 +71,32 @@ namespace Nz * * \see Wait */ - bool SocketPoller::IsReady(const AbstractSocket& socket) const + bool SocketPoller::IsReadyToRead(const AbstractSocket& socket) const { NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller"); - return m_impl->IsReady(socket.GetNativeHandle()); + return m_impl->IsReadyToRead(socket.GetNativeHandle()); + } + + /*! + * \brief Checks if a specific socket is ready to write data + * + * This function allows you to read the results of the last Wait operation and if a specific socket is ready to write (can be written to without blocking). + * + * \remark You must call Wait before using this function in order to refresh the read state. + * \remark A socket must be registered with SocketPollerEvent_Write event flag for its read state to be watched + * + * \param socket Reference to the socket to check + * + * \return True if the socket is available for writing without blocking, false otherwise + * + * \see Wait + */ + bool SocketPoller::IsReadyToWrite(const AbstractSocket& socket) const + { + NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller"); + + return m_impl->IsReadyToWrite(socket.GetNativeHandle()); } /*! @@ -97,7 +119,7 @@ namespace Nz /*! * \brief Register a socket in the SocketPoller * - * A registered socket is part of the SocketPoller and will be checked by the next Wait operations. + * A registered socket is part of the SocketPoller and will be checked by the next Wait operations according to the event flags passed when registered. * * The SocketPoller keeps a reference to the internal handle of registered socket, which should not be freed while it is registered in the SocketPooler. * @@ -107,17 +129,18 @@ namespace Nz * \remark The socket should not be freed while it is registered in the SocketPooler. * * \param socket Reference to the socket to register + * \param eventFlags Socket events to watch * * \return True if the socket is registered, false otherwise * * \see IsRegistered * \see UnregisterSocket */ - bool SocketPoller::RegisterSocket(AbstractSocket& socket) + bool SocketPoller::RegisterSocket(AbstractSocket& socket, SocketPollEventFlags eventFlags) { NazaraAssert(!IsRegistered(socket), "This socket is already registered in this SocketPoller"); - return m_impl->RegisterSocket(socket.GetNativeHandle()); + return m_impl->RegisterSocket(socket.GetNativeHandle(), eventFlags); } /*! @@ -145,7 +168,7 @@ namespace Nz * \brief Wait until any registered socket switches to a ready state. * * Waits a specific/undetermined amount of time until at least one socket part of the SocketPoller becomes ready. - * To query the ready state of the registered socket, use the IsReady function. + * To query the ready state of the registered socket, use the IsReadyToRead or IsReadyToWrite functions. * * \param msTimeout Maximum time to wait in milliseconds, 0 for infinity * diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.cpp b/src/Nazara/Network/Win32/SocketPollerImpl.cpp index 292e8dfa5..405f80c8f 100644 --- a/src/Nazara/Network/Win32/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Win32/SocketPollerImpl.cpp @@ -10,29 +10,43 @@ namespace Nz SocketPollerImpl::SocketPollerImpl() { #if !NAZARA_NETWORK_POLL_SUPPORT - FD_ZERO(&m_activeSockets); - FD_ZERO(&m_sockets); + FD_ZERO(&m_readSockets); + FD_ZERO(&m_readyToReadSockets); + FD_ZERO(&m_readyToWriteSockets); + FD_ZERO(&m_writeSockets); #endif } void SocketPollerImpl::Clear() { #if NAZARA_NETWORK_POLL_SUPPORT - m_activeSockets.clear(); m_allSockets.clear(); + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); m_sockets.clear(); #else - FD_ZERO(&m_activeSockets); - FD_ZERO(&m_sockets); + FD_ZERO(&m_readSockets); + FD_ZERO(&m_readyToReadSockets); + FD_ZERO(&m_readyToWriteSockets); + FD_ZERO(&m_writeSockets); #endif } - bool SocketPollerImpl::IsReady(SocketHandle socket) const + bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const { #if NAZARA_NETWORK_POLL_SUPPORT - return m_activeSockets.count(socket) != 0; + return m_readyToReadSockets.count(socket) != 0; #else - return FD_ISSET(socket, &m_activeSockets) != 0; + return FD_ISSET(socket, &m_readyToReadSockets) != 0; + #endif + } + + bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const + { + #if NAZARA_NETWORK_POLL_SUPPORT + return m_readyToWriteSockets.count(socket) != 0; + #else + return FD_ISSET(socket, &m_readyToWriteSockets) != 0; #endif } @@ -41,31 +55,45 @@ namespace Nz #if NAZARA_NETWORK_POLL_SUPPORT return m_allSockets.count(socket) != 0; #else - return FD_ISSET(socket, &m_sockets) != 0; + return FD_ISSET(socket, &m_readSockets) != 0 || + FD_ISSET(socket, &m_writeSockets) != 0; #endif } - bool SocketPollerImpl::RegisterSocket(SocketHandle socket) + bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags) { NazaraAssert(!IsRegistered(socket), "Socket is already registered"); #if NAZARA_NETWORK_POLL_SUPPORT PollSocket entry = { socket, - POLLRDNORM, + 0, 0 }; + if (eventFlags & SocketPollEvent_Read) + entry.events |= POLLRDNORM; + + if (eventFlags & SocketPollEvent_Write) + entry.events |= POLLWRNORM; + m_allSockets[socket] = m_sockets.size(); m_sockets.emplace_back(entry); #else - if (m_sockets.fd_count > FD_SETSIZE) + for (std::size_t i = 0; i < 2; ++i) { - NazaraError("Socket count exceeding FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")"); - return false; - } + if (eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write) == 0) + continue; - FD_SET(socket, &m_sockets); + fd_set& targetSet = (i == 0) ? m_readSockets : m_writeSockets; + if (targetSet.fd_count > FD_SETSIZE) + { + NazaraError("Socket count exceeding hard-coded FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")"); + return false; + } + + FD_SET(socket, &targetSet); + } #endif return true; @@ -88,13 +116,16 @@ namespace Nz // Now move it properly (lastElement is invalid after the following line) and pop it m_sockets[entry] = std::move(m_sockets.back()); } - m_sockets.pop_back(); - m_activeSockets.erase(socket); + m_allSockets.erase(socket); + m_readyToReadSockets.erase(socket); + m_readyToWriteSockets.erase(socket); #else - FD_CLR(socket, &m_activeSockets); - FD_CLR(socket, &m_sockets); + FD_CLR(socket, &m_readSockets); + FD_CLR(socket, &m_readyToReadSockets); + FD_CLR(socket, &m_readyToWriteSockets); + FD_CLR(socket, &m_writeSockets); #endif } @@ -103,35 +134,18 @@ namespace Nz int activeSockets; #if NAZARA_NETWORK_POLL_SUPPORT - // Reset status of sockets - for (PollSocket& entry : m_sockets) - entry.revents = 0; - activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast(msTimeout), error); + x - m_activeSockets.clear(); - if (activeSockets > 0U) - { - int socketRemaining = activeSockets; - for (PollSocket& entry : m_sockets) - { - if (entry.revents & POLLRDNORM) - { - m_activeSockets.insert(entry.fd); - if (--socketRemaining == 0) - break; - } - } - } #else - - m_activeSockets = m_sockets; + m_readyToReadSockets = m_readSockets; + m_readyToWriteSockets = m_writeSockets; timeval tv; tv.tv_sec = static_cast(msTimeout / 1000ULL); tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); - activeSockets = ::select(0xDEADBEEF, &m_activeSockets, nullptr, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows + activeSockets = ::select(0xDEADBEEF, &m_readyToReadSockets, &m_readyToWriteSockets, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows if (activeSockets == SOCKET_ERROR) { if (error) diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.hpp b/src/Nazara/Network/Win32/SocketPollerImpl.hpp index 0a745878d..a94af1372 100644 --- a/src/Nazara/Network/Win32/SocketPollerImpl.hpp +++ b/src/Nazara/Network/Win32/SocketPollerImpl.hpp @@ -25,24 +25,28 @@ namespace Nz void Clear(); - bool IsReady(SocketHandle socket) const; + bool IsReadyToRead(SocketHandle socket) const; + bool IsReadyToWrite(SocketHandle socket) const; bool IsRegistered(SocketHandle socket) const; - bool RegisterSocket(SocketHandle socket); + bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags); void UnregisterSocket(SocketHandle socket); int Wait(UInt64 msTimeout, SocketError* error); private: #if NAZARA_NETWORK_POLL_SUPPORT - std::unordered_set m_activeSockets; + std::unordered_set m_readyToReadSockets; + std::unordered_set m_readyToWriteSockets; std::unordered_map m_allSockets; std::vector m_sockets; #else - fd_set m_sockets; - fd_set m_activeSockets; + fd_set m_readSockets; + fd_set m_readyToReadSockets; + fd_set m_readyToWriteSockets; + fd_set m_writeSockets; #endif }; } -#endif // NAZARA_SOCKETPOLLERIMPL_HPP \ No newline at end of file +#endif // NAZARA_SOCKETPOLLERIMPL_HPP From d516b0907b8247c61255b8c6041ad9bb67bb5742 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 May 2017 09:11:02 +0200 Subject: [PATCH 49/73] Network/ENetHost: Fix usage of SocketPoller --- src/Nazara/Network/ENetHost.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index d4d1be9f9..e12f80454 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -280,7 +280,7 @@ namespace Nz m_serviceTime = GetElapsedMilliseconds(); } - while (m_poller.IsReady(m_socket)); + while (m_poller.IsReadyToRead(m_socket)); return 0; } @@ -327,7 +327,7 @@ namespace Nz } } - m_poller.RegisterSocket(m_socket); + m_poller.RegisterSocket(m_socket, SocketPollEvent_Read); return true; } From 999cb13f000918cbefd598dc3b265d28179aa539 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 May 2017 09:19:37 +0200 Subject: [PATCH 50/73] Fix test compilation --- tests/Engine/Network/SocketPoller.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Engine/Network/SocketPoller.cpp b/tests/Engine/Network/SocketPoller.cpp index 7081c1b30..2e880cf5c 100644 --- a/tests/Engine/Network/SocketPoller.cpp +++ b/tests/Engine/Network/SocketPoller.cpp @@ -27,7 +27,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") WHEN("We register the server socket to the poller") { - REQUIRE(serverPoller.RegisterSocket(server)); + REQUIRE(serverPoller.RegisterSocket(server, Nz::SocketPollEvent_Read)); THEN("The poller should have registered our socket") { @@ -48,7 +48,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") WHEN("We register the client socket to the poller") { - REQUIRE(serverPoller.RegisterSocket(serverToClient)); + REQUIRE(serverPoller.RegisterSocket(serverToClient, Nz::SocketPollEvent_Read)); THEN("The poller should have registered our socket") { @@ -65,7 +65,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") REQUIRE(serverPoller.Wait(1000)); - CHECK(serverPoller.IsReady(serverToClient)); + CHECK(serverPoller.IsReadyToRead(serverToClient)); CHECK(serverToClient.Read(buffer.data(), buffer.size()) == sent); @@ -73,7 +73,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") { REQUIRE_FALSE(serverPoller.Wait(100)); - REQUIRE_FALSE(serverPoller.IsReady(serverToClient)); + REQUIRE_FALSE(serverPoller.IsReadyToRead(serverToClient)); } } } From 1cdac50af215da6d033099ded414716fd08f3c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 16 May 2017 10:09:09 +0200 Subject: [PATCH 51/73] Network/SocketPoller: Fix RegisterSocket on Windows --- src/Nazara/Network/Win32/SocketPollerImpl.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.cpp b/src/Nazara/Network/Win32/SocketPollerImpl.cpp index 405f80c8f..e228da789 100644 --- a/src/Nazara/Network/Win32/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Win32/SocketPollerImpl.cpp @@ -82,7 +82,7 @@ namespace Nz #else for (std::size_t i = 0; i < 2; ++i) { - if (eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write) == 0) + if ((eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write)) == 0) continue; fd_set& targetSet = (i == 0) ? m_readSockets : m_writeSockets; @@ -135,8 +135,6 @@ namespace Nz #if NAZARA_NETWORK_POLL_SUPPORT activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast(msTimeout), error); - x - #else m_readyToReadSockets = m_readSockets; m_readyToWriteSockets = m_writeSockets; From ba24181fd69d900881e71277bbecaee2bb7dbf67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 17 May 2017 11:29:55 +0200 Subject: [PATCH 52/73] Network/SocketPollerImpl: Fix possible weird behavior with SocketPoller --- src/Nazara/Network/Win32/SocketPollerImpl.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.cpp b/src/Nazara/Network/Win32/SocketPollerImpl.cpp index e228da789..3513ce722 100644 --- a/src/Nazara/Network/Win32/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Win32/SocketPollerImpl.cpp @@ -136,14 +136,26 @@ namespace Nz #if NAZARA_NETWORK_POLL_SUPPORT activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast(msTimeout), error); #else - m_readyToReadSockets = m_readSockets; - m_readyToWriteSockets = m_writeSockets; + fd_set* readSet = nullptr; + fd_set* writeSet = nullptr; + + if (m_readSockets.fd_count > 0) + { + m_readyToReadSockets = m_readSockets; + readSet = &m_readyToReadSockets; + } + + if (m_writeSockets.fd_count > 0) + { + m_readyToWriteSockets = m_writeSockets; + readSet = &m_readyToWriteSockets; + } timeval tv; tv.tv_sec = static_cast(msTimeout / 1000ULL); tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); - activeSockets = ::select(0xDEADBEEF, &m_readyToReadSockets, &m_readyToWriteSockets, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows + activeSockets = ::select(0xDEADBEEF, readSet, writeSet, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows if (activeSockets == SOCKET_ERROR) { if (error) From 3b7881ebfecb888dae28607a9cb582e2ae14a403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 17 May 2017 11:29:55 +0200 Subject: [PATCH 53/73] Network/SocketPollerImpl: Fix possible weird behavior with SocketPoller --- src/Nazara/Network/Win32/SocketPollerImpl.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.cpp b/src/Nazara/Network/Win32/SocketPollerImpl.cpp index e228da789..3513ce722 100644 --- a/src/Nazara/Network/Win32/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Win32/SocketPollerImpl.cpp @@ -136,14 +136,26 @@ namespace Nz #if NAZARA_NETWORK_POLL_SUPPORT activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast(msTimeout), error); #else - m_readyToReadSockets = m_readSockets; - m_readyToWriteSockets = m_writeSockets; + fd_set* readSet = nullptr; + fd_set* writeSet = nullptr; + + if (m_readSockets.fd_count > 0) + { + m_readyToReadSockets = m_readSockets; + readSet = &m_readyToReadSockets; + } + + if (m_writeSockets.fd_count > 0) + { + m_readyToWriteSockets = m_writeSockets; + readSet = &m_readyToWriteSockets; + } timeval tv; tv.tv_sec = static_cast(msTimeout / 1000ULL); tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); - activeSockets = ::select(0xDEADBEEF, &m_readyToReadSockets, &m_readyToWriteSockets, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows + activeSockets = ::select(0xDEADBEEF, readSet, writeSet, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows if (activeSockets == SOCKET_ERROR) { if (error) From 09bace0f28baf5761889c82318593aa6e8ff1b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 18 May 2017 11:44:28 +0200 Subject: [PATCH 54/73] Sdk/LuaBinding: Bind UdpSocket --- SDK/include/NDK/Lua/LuaBinding_Network.hpp | 2 + SDK/src/NDK/Lua/LuaBinding_Network.cpp | 60 +++++++++++++++++++++- examples/FirstScene/main.cpp | 2 + include/Nazara/Network/UdpSocket.hpp | 1 - include/Nazara/Network/UdpSocket.inl | 10 ---- 5 files changed, 63 insertions(+), 12 deletions(-) diff --git a/SDK/include/NDK/Lua/LuaBinding_Network.hpp b/SDK/include/NDK/Lua/LuaBinding_Network.hpp index a9a5b31e0..3774cb5e8 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Network.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Network.hpp @@ -9,6 +9,7 @@ #include #include +#include #include namespace Ndk @@ -23,6 +24,7 @@ namespace Ndk Nz::LuaClass abstractSocket; Nz::LuaClass ipAddress; + Nz::LuaClass udpSocket; }; } diff --git a/SDK/src/NDK/Lua/LuaBinding_Network.cpp b/SDK/src/NDK/Lua/LuaBinding_Network.cpp index d6f92cb40..a47cdbfb6 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Network.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Network.cpp @@ -32,7 +32,7 @@ namespace Ndk { std::size_t argCount = std::min(argumentCount, 9U); - int argIndex = 2; + int argIndex = 1; switch (argCount) { case 0: @@ -142,6 +142,63 @@ namespace Ndk } }); } + + udpSocket.Reset("UdpSocket"); + { + udpSocket.Inherit(abstractSocket); + + udpSocket.BindDefaultConstructor(); + + udpSocket.BindMethod("Create", &Nz::UdpSocket::Create); + udpSocket.BindMethod("EnableBroadcasting", &Nz::UdpSocket::EnableBroadcasting); + udpSocket.BindMethod("GetBoundAddress", &Nz::UdpSocket::GetBoundAddress); + udpSocket.BindMethod("GetBoundPort", &Nz::UdpSocket::GetBoundPort); + udpSocket.BindMethod("IsBroadcastingEnabled", &Nz::UdpSocket::IsBroadcastingEnabled); + udpSocket.BindMethod("QueryMaxDatagramSize", &Nz::UdpSocket::QueryMaxDatagramSize); + + udpSocket.BindMethod("Bind", [](Nz::LuaInstance& lua, Nz::UdpSocket& instance, std::size_t /*argumentCount*/) -> int + { + int argIndex = 2; + if (lua.IsOfType(argIndex, "IpAddress")) + return lua.Push(instance.Bind(*static_cast(lua.ToUserdata(argIndex)))); + else + return lua.Push(instance.Bind(lua.Check(&argIndex))); + }); + + udpSocket.BindMethod("Receive", [](Nz::LuaInstance& lua, Nz::UdpSocket& instance, std::size_t /*argumentCount*/) -> int + { + Nz::IpAddress from; + + std::array buffer; + std::size_t received; + if (instance.Receive(buffer.data(), buffer.size(), &from, &received)) + { + lua.PushBoolean(true); + lua.PushString(from.ToString()); + lua.PushString(buffer.data(), received); + return 3; + } + + lua.PushBoolean(false); + return 1; + }); + + udpSocket.BindMethod("Send", [](Nz::LuaInstance& lua, Nz::UdpSocket& instance, std::size_t /*argumentCount*/) -> int + { + int argIndex = 2; + Nz::String to = lua.Check(&argIndex); + + std::size_t bufferLength; + const char* buffer = lua.CheckString(argIndex, &bufferLength); + + std::size_t sent; + bool ret; + if ((ret = instance.Send(Nz::IpAddress(to), buffer, bufferLength, &sent)) != true) + sent = 0; + + return lua.Push(std::make_pair(ret, sent)); + }); + } } /*! @@ -154,6 +211,7 @@ namespace Ndk // Classes abstractSocket.Register(instance); ipAddress.Register(instance); + udpSocket.Register(instance); // Enums diff --git a/examples/FirstScene/main.cpp b/examples/FirstScene/main.cpp index b7e7d1198..4acbdf5a1 100644 --- a/examples/FirstScene/main.cpp +++ b/examples/FirstScene/main.cpp @@ -16,6 +16,7 @@ #include // Module de scripting #include // Module graphique #include // Module de rendu +#include // Module utilitaire #include // Module utilitaire #include #include @@ -33,6 +34,7 @@ int main() { // Ndk::Application est une classe s'occupant de l'initialisation du moteur ainsi que de la gestion de beaucoup de choses Ndk::Application application; + Nz::Initializer network; // Nazara étant initialisé, nous pouvons créer le monde pour contenir notre scène. // Dans un ECS, le monde représente bien ce que son nom indique, c'est l'ensemble de ce qui existe au niveau de l'application. diff --git a/include/Nazara/Network/UdpSocket.hpp b/include/Nazara/Network/UdpSocket.hpp index 04ca41db0..0086249e9 100644 --- a/include/Nazara/Network/UdpSocket.hpp +++ b/include/Nazara/Network/UdpSocket.hpp @@ -33,7 +33,6 @@ namespace Nz inline IpAddress GetBoundAddress() const; inline UInt16 GetBoundPort() const; - inline SocketState GetState() const; inline bool IsBroadcastingEnabled() const; diff --git a/include/Nazara/Network/UdpSocket.inl b/include/Nazara/Network/UdpSocket.inl index 3e4dee4df..2925c1935 100644 --- a/include/Nazara/Network/UdpSocket.inl +++ b/include/Nazara/Network/UdpSocket.inl @@ -103,16 +103,6 @@ namespace Nz return m_boundAddress.GetPort(); } - /*! - * \brief Gets the state of the socket - * \return State of the socket - */ - - inline SocketState UdpSocket::GetState() const - { - return m_state; - } - /*! * \brief Checks whether the broadcasting is enabled * \return true If it is the case From 3ca179b954e22b640ef753bd8064727a328d6250 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 19 May 2017 16:31:29 +0200 Subject: [PATCH 55/73] Network/ENet: Separate Connect event into OutgoingConnect and IncomingConnect --- include/Nazara/Network/ENetHost.hpp | 2 +- include/Nazara/Network/ENetProtocol.hpp | 18 +++++++++++------- src/Nazara/Network/ENetHost.cpp | 15 +++++++++++---- src/Nazara/Network/ENetPeer.cpp | 6 +++--- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 4941df353..eb5c7d6de 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -87,7 +87,7 @@ namespace Nz int ReceiveIncomingCommands(ENetEvent* event); - void NotifyConnect(ENetPeer* peer, ENetEvent* event); + void NotifyConnect(ENetPeer* peer, ENetEvent* event, bool incoming); void NotifyDisconnect(ENetPeer*, ENetEvent* event); void SendAcknowledgements(ENetPeer* peer); diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp index 7cd613ab0..dab014aa2 100644 --- a/include/Nazara/Network/ENetProtocol.hpp +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -118,11 +118,6 @@ namespace Nz /** no event occurred within the specified time limit */ None, - /** a connection request initiated by enet_host_connect has completed. - * The peer field contains the peer which successfully connected. - */ - Connect, - /** a peer has disconnected. This event is generated on a successful * completion of a disconnect initiated by enet_peer_disconnect, if * a peer has timed out, or if a connection request initialized by @@ -132,11 +127,20 @@ namespace Nz */ Disconnect, + /** a connection request initiated by enet_host_connect from this host has completed. + * The peer field contains the peer which successfully connected. + */ + OutgoingConnect, + + /** a connection request initiated by enet_host_connect from another host has completed. + * The peer field contains the peer which successfully connected. + */ + IncomingConnect, + /** a packet has been received from a peer. The peer field specifies the * peer which sent the packet. The channelID field specifies the channel * number upon which the packet was received. The packet field contains - * the packet that was received; this packet must be destroyed with - * enet_packet_destroy after use. + * the packet that was received; */ Receive }; diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index d4d1be9f9..ade03bb10 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -352,10 +352,17 @@ namespace Nz switch (peer.GetState()) { case ENetPeerState::ConnectionPending: + peer.ChangeState(ENetPeerState::Connected); + + event->type = ENetEventType::IncomingConnect; + event->peer = &peer; + event->data = peer.m_eventData; + return true; + case ENetPeerState::ConnectionSucceeded: peer.ChangeState(ENetPeerState::Connected); - event->type = ENetEventType::Connect; + event->type = ENetEventType::OutgoingConnect; event->peer = &peer; event->data = peer.m_eventData; return true; @@ -728,7 +735,7 @@ namespace Nz return -1; } - void ENetHost::NotifyConnect(ENetPeer* peer, ENetEvent* event) + void ENetHost::NotifyConnect(ENetPeer* peer, ENetEvent* event, bool incoming) { m_recalculateBandwidthLimits = true; @@ -736,12 +743,12 @@ namespace Nz { peer->ChangeState(ENetPeerState::Connected); - event->type = ENetEventType::Connect; + event->type = (incoming) ? ENetEventType::IncomingConnect : ENetEventType::OutgoingConnect; event->peer = peer; event->data = peer->m_eventData; } else - peer->DispatchState(peer->GetState() == ENetPeerState::Connecting ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); + peer->DispatchState((peer->GetState() == ENetPeerState::Connecting) ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); } void ENetHost::NotifyDisconnect(ENetPeer* peer, ENetEvent* event) diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index 5ce92a1e4..cbae37148 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -501,7 +501,7 @@ namespace Nz if (commandNumber != ENetProtocolCommand_VerifyConnect) return false; - m_host->NotifyConnect(this, event); + m_host->NotifyConnect(this, event, true); break; case ENetPeerState::Disconnecting: @@ -864,7 +864,7 @@ namespace Nz NetToHost(command->verifyConnect.packetThrottleInterval) != m_packetThrottleInterval || NetToHost(command->verifyConnect.packetThrottleAcceleration) != m_packetThrottleAcceleration || NetToHost(command->verifyConnect.packetThrottleDeceleration) != m_packetThrottleDeceleration || - command->verifyConnect.connectID != m_connectID) + command->verifyConnect.connectID != m_connectID) { m_eventData = 0; @@ -891,7 +891,7 @@ namespace Nz m_incomingBandwidth = NetToHost(command->verifyConnect.incomingBandwidth); m_outgoingBandwidth = NetToHost(command->verifyConnect.outgoingBandwidth); - m_host->NotifyConnect(this, event); + m_host->NotifyConnect(this, event, false); return true; } From 3e972401488da555e742fc33fa266fb13cd80af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 29 May 2017 18:01:19 +0200 Subject: [PATCH 56/73] Core/ParameterList: Add ForEach methods --- include/Nazara/Core/ParameterList.hpp | 5 ++++ include/Nazara/Core/ParameterList.inl | 42 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 include/Nazara/Core/ParameterList.inl diff --git a/include/Nazara/Core/ParameterList.hpp b/include/Nazara/Core/ParameterList.hpp index 75972b49c..3e9d3a825 100644 --- a/include/Nazara/Core/ParameterList.hpp +++ b/include/Nazara/Core/ParameterList.hpp @@ -27,6 +27,9 @@ namespace Nz void Clear(); + inline void ForEach(const std::function& callback); + inline void ForEach(const std::function& callback) const; + bool GetBooleanParameter(const String& name, bool* value) const; bool GetColorParameter(const String& name, Color* value) const; bool GetFloatParameter(const String& name, float* value) const; @@ -102,4 +105,6 @@ namespace Nz std::ostream& operator<<(std::ostream& out, const Nz::ParameterList& parameterList); +#include + #endif // NAZARA_PARAMETERLIST_HPP diff --git a/include/Nazara/Core/ParameterList.inl b/include/Nazara/Core/ParameterList.inl new file mode 100644 index 000000000..b1983b49b --- /dev/null +++ b/include/Nazara/Core/ParameterList.inl @@ -0,0 +1,42 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + /*! + * \brief Iterates over every value of the parameter list + * + * \param callback Callback function called with every parameter contained in the list, which can return true to remove the key (or false to keep it) + * + * \remark Changing the ParameterList while iterating on it may cause bugs, but querying data is safe. + */ + inline void ParameterList::ForEach(const std::function& callback) + { + for (auto it = m_parameters.begin(); it != m_parameters.end();) + { + if (callback(*this, it->first)) + it = m_parameters.erase(it); + else + ++it; + } + } + + /*! + * \brief Iterates over every value of the parameter list + * + * \param callback Callback function called with every parameter contained in the list + * + * \remark Changing the ParameterList while iterating on it may cause bugs, but querying data is safe. + */ + inline void ParameterList::ForEach(const std::function& callback) const + { + for (auto& pair : m_parameters) + callback(*this, pair.first); + } +} + +#include From 30a4e20ee535c386f01ba9775e46c78b4e1a5002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 29 May 2017 18:01:31 +0200 Subject: [PATCH 57/73] Lua/LuaInstance: Expose some raw functions --- include/Nazara/Lua/LuaInstance.hpp | 3 +++ src/Nazara/Lua/LuaInstance.cpp | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/Nazara/Lua/LuaInstance.hpp b/include/Nazara/Lua/LuaInstance.hpp index 39b0879a8..2ac752c9e 100644 --- a/include/Nazara/Lua/LuaInstance.hpp +++ b/include/Nazara/Lua/LuaInstance.hpp @@ -101,6 +101,7 @@ namespace Nz bool GetMetatable(int index) const; unsigned int GetStackTop() const; LuaType GetTable(int index = -2) const; + LuaType GetTableRaw(int index = -2) const; inline UInt32 GetTimeLimit() const; LuaType GetType(int index) const; const char* GetTypeName(LuaType type) const; @@ -113,6 +114,7 @@ namespace Nz bool IsValid(int index) const; long long Length(int index) const; + std::size_t LengthRaw(int index) const; void MoveTo(LuaInstance* instance, int n) const; @@ -161,6 +163,7 @@ namespace Nz void SetMetatable(int index) const; void SetMemoryLimit(std::size_t memoryLimit); void SetTable(int index = -3) const; + void SetTableRaw(int index = -3) const; void SetTimeLimit(UInt32 timeLimit); bool ToBoolean(int index) const; diff --git a/src/Nazara/Lua/LuaInstance.cpp b/src/Nazara/Lua/LuaInstance.cpp index 380e7c48f..1c8f25567 100644 --- a/src/Nazara/Lua/LuaInstance.cpp +++ b/src/Nazara/Lua/LuaInstance.cpp @@ -503,6 +503,11 @@ namespace Nz return FromLuaType(lua_gettable(m_state, index)); } + LuaType LuaInstance::GetTableRaw(int index) const + { + return FromLuaType(lua_rawget(m_state, index)); + } + LuaType LuaInstance::GetType(int index) const { return FromLuaType(lua_type(m_state, index)); @@ -586,6 +591,11 @@ namespace Nz return luaL_len(m_state, index); } + std::size_t LuaInstance::LengthRaw(int index) const + { + return lua_rawlen(m_state, index); + } + void LuaInstance::MoveTo(LuaInstance* instance, int n) const { lua_xmove(m_state, instance->m_state, n); @@ -750,6 +760,11 @@ namespace Nz lua_settable(m_state, index); } + void LuaInstance::SetTableRaw(int index) const + { + lua_rawset(m_state, index); + } + void LuaInstance::SetTimeLimit(UInt32 timeLimit) { if (m_timeLimit != timeLimit) From bc4a533b96f9716c89de07230c2fbbc0b46b321d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 29 May 2017 19:55:02 +0200 Subject: [PATCH 58/73] Core/ParameterList: Use double and long long instead of float and int --- include/Nazara/Core/Enums.hpp | 2 +- include/Nazara/Core/ParameterList.hpp | 12 ++-- src/Nazara/Core/ParameterList.cpp | 73 ++++++++++++------------ src/Nazara/Utility/Formats/OBJLoader.cpp | 6 +- src/Nazara/Utility/Formats/OBJSaver.cpp | 8 +-- tests/Engine/Core/ParameterList.cpp | 8 +-- 6 files changed, 53 insertions(+), 56 deletions(-) diff --git a/include/Nazara/Core/Enums.hpp b/include/Nazara/Core/Enums.hpp index 5a6e67565..2bacb1f2d 100644 --- a/include/Nazara/Core/Enums.hpp +++ b/include/Nazara/Core/Enums.hpp @@ -105,7 +105,7 @@ namespace Nz { ParameterType_Boolean, ParameterType_Color, - ParameterType_Float, + ParameterType_Double, ParameterType_Integer, ParameterType_None, ParameterType_Pointer, diff --git a/include/Nazara/Core/ParameterList.hpp b/include/Nazara/Core/ParameterList.hpp index 3e9d3a825..d6b3985b4 100644 --- a/include/Nazara/Core/ParameterList.hpp +++ b/include/Nazara/Core/ParameterList.hpp @@ -32,8 +32,8 @@ namespace Nz bool GetBooleanParameter(const String& name, bool* value) const; bool GetColorParameter(const String& name, Color* value) const; - bool GetFloatParameter(const String& name, float* value) const; - bool GetIntegerParameter(const String& name, int* value) const; + bool GetDoubleParameter(const String& name, double* value) const; + bool GetIntegerParameter(const String& name, long long* value) const; bool GetParameterType(const String& name, ParameterType* type) const; bool GetPointerParameter(const String& name, void** value) const; bool GetStringParameter(const String& name, String* value) const; @@ -48,8 +48,8 @@ namespace Nz void SetParameter(const String& name, const String& value); void SetParameter(const String& name, const char* value); void SetParameter(const String& name, bool value); - void SetParameter(const String& name, float value); - void SetParameter(const String& name, int value); + void SetParameter(const String& name, double value); + void SetParameter(const String& name, long long value); void SetParameter(const String& name, void* value); void SetParameter(const String& name, void* value, Destructor destructor); @@ -84,8 +84,8 @@ namespace Nz ~Value() {} bool boolVal; - float floatVal; - int intVal; + double doubleVal; + long long intVal; void* ptrVal; Color colorVal; String stringVal; diff --git a/src/Nazara/Core/ParameterList.cpp b/src/Nazara/Core/ParameterList.cpp index 5206dd333..89fdb4591 100644 --- a/src/Nazara/Core/ParameterList.cpp +++ b/src/Nazara/Core/ParameterList.cpp @@ -95,7 +95,7 @@ namespace Nz } case ParameterType_Color: - case ParameterType_Float: + case ParameterType_Double: case ParameterType_None: case ParameterType_Pointer: case ParameterType_Userdata: @@ -137,9 +137,9 @@ namespace Nz return true; case ParameterType_Boolean: + case ParameterType_Double: case ParameterType_Integer: case ParameterType_String: - case ParameterType_Float: case ParameterType_None: case ParameterType_Pointer: case ParameterType_Userdata: @@ -151,19 +151,19 @@ namespace Nz } /*! - * \brief Gets a parameter as a float - * \return true if the parameter could be represented as a float + * \brief Gets a parameter as a double + * \return true if the parameter could be represented as a double * * \param name Name of the parameter - * \param value Pointer to a float to hold the retrieved value + * \param value Pointer to a double to hold the retrieved value * * \remark value must be a valid pointer * \remark In case of failure, the variable pointed by value keep its value - * \remark If the parameter is not a float, a conversion will be performed, compatibles types are: - Integer: The integer value is converted to its float representation + * \remark If the parameter is not a double, a conversion will be performed, compatibles types are: + Integer: The integer value is converted to its double representation String: Conversion obeys the rule as described by String::ToDouble */ - bool ParameterList::GetFloatParameter(const String& name, float* value) const + bool ParameterList::GetDoubleParameter(const String& name, double* value) const { NazaraAssert(value, "Invalid pointer"); @@ -178,12 +178,12 @@ namespace Nz switch (it->second.type) { - case ParameterType_Float: - *value = it->second.value.floatVal; + case ParameterType_Double: + *value = it->second.value.doubleVal; return true; case ParameterType_Integer: - *value = static_cast(it->second.value.intVal); + *value = static_cast(it->second.value.intVal); return true; case ParameterType_String: @@ -191,7 +191,7 @@ namespace Nz double converted; if (it->second.value.stringVal.ToDouble(&converted)) { - *value = static_cast(converted); + *value = converted; return true; } @@ -206,7 +206,7 @@ namespace Nz break; } - NazaraError("Parameter value is not representable as a float"); + NazaraError("Parameter value is not representable as a double"); return false; } @@ -219,12 +219,12 @@ namespace Nz * * \remark value must be a valid pointer * \remark In case of failure, the variable pointed by value keep its value - * \remark If the parameter is not a float, a conversion will be performed, compatibles types are: + * \remark If the parameter is not an integer, a conversion will be performed, compatibles types are: Boolean: The boolean is represented as 1 if true and 0 if false - Float: The floating-point value is truncated and converted to a integer - String: Conversion obeys the rule as described by String::ToInteger but fails if the value could not be represented as a int + Double: The floating-point value is truncated and converted to a integer + String: Conversion obeys the rule as described by String::ToInteger */ - bool ParameterList::GetIntegerParameter(const String& name, int* value) const + bool ParameterList::GetIntegerParameter(const String& name, long long* value) const { NazaraAssert(value, "Invalid pointer"); @@ -243,8 +243,8 @@ namespace Nz *value = (it->second.value.boolVal) ? 1 : 0; return true; - case ParameterType_Float: - *value = static_cast(it->second.value.floatVal); + case ParameterType_Double: + *value = static_cast(it->second.value.doubleVal); return true; case ParameterType_Integer: @@ -256,11 +256,8 @@ namespace Nz long long converted; if (it->second.value.stringVal.ToInteger(&converted)) { - if (converted <= std::numeric_limits::max() && converted >= std::numeric_limits::min()) - { - *value = static_cast(converted); - return true; - } + *value = converted; + return true; } break; } @@ -335,7 +332,7 @@ namespace Nz case ParameterType_Boolean: case ParameterType_Color: - case ParameterType_Float: + case ParameterType_Double: case ParameterType_Integer: case ParameterType_None: case ParameterType_String: @@ -358,7 +355,7 @@ namespace Nz * \remark If the parameter is not a string, a conversion will be performed, all types are compatibles: Boolean: Conversion obeys the rules of String::Boolean Color: Conversion obeys the rules of Color::ToString - Float: Conversion obeys the rules of String::Number + Double: Conversion obeys the rules of String::Number Integer: Conversion obeys the rules of String::Number None: An empty string is returned Pointer: Conversion obeys the rules of String::Pointer @@ -387,8 +384,8 @@ namespace Nz *value = it->second.value.colorVal.ToString(); return true; - case ParameterType_Float: - *value = String::Number(it->second.value.floatVal); + case ParameterType_Double: + *value = String::Number(it->second.value.doubleVal); return true; case ParameterType_Integer: @@ -560,18 +557,18 @@ namespace Nz } /*! - * \brief Sets a float parameter named `name` + * \brief Sets a double parameter named `name` * * If a parameter already exists with that name, it is destroyed and replaced by this call * * \param name Name of the parameter - * \param value The float value + * \param value The double value */ - void ParameterList::SetParameter(const String& name, float value) + void ParameterList::SetParameter(const String& name, double value) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_Float; - parameter.value.floatVal = value; + parameter.type = ParameterType_Double; + parameter.value.doubleVal = value; } /*! @@ -582,7 +579,7 @@ namespace Nz * \param name Name of the parameter * \param value The integer value */ - void ParameterList::SetParameter(const String& name, int value) + void ParameterList::SetParameter(const String& name, long long value) { Parameter& parameter = CreateValue(name); parameter.type = ParameterType_Integer; @@ -627,8 +624,8 @@ namespace Nz case ParameterType_Color: ss << "Color(" << it->second.value.colorVal.ToString() << ")"; break; - case ParameterType_Float: - ss << "Float(" << it->second.value.floatVal << ")"; + case ParameterType_Double: + ss << "Double(" << it->second.value.doubleVal << ")"; break; case ParameterType_Integer: ss << "Integer(" << it->second.value.intVal << ")"; @@ -692,7 +689,7 @@ namespace Nz { case ParameterType_Boolean: case ParameterType_Color: - case ParameterType_Float: + case ParameterType_Double: case ParameterType_Integer: case ParameterType_Pointer: std::memcpy(¶meter, &it->second, sizeof(Parameter)); @@ -764,7 +761,7 @@ namespace Nz case ParameterType_Boolean: case ParameterType_Color: - case ParameterType_Float: + case ParameterType_Double: case ParameterType_Integer: case ParameterType_None: case ParameterType_Pointer: diff --git a/src/Nazara/Utility/Formats/OBJLoader.cpp b/src/Nazara/Utility/Formats/OBJLoader.cpp index 563300aaf..d7dd15d14 100644 --- a/src/Nazara/Utility/Formats/OBJLoader.cpp +++ b/src/Nazara/Utility/Formats/OBJLoader.cpp @@ -124,8 +124,8 @@ namespace Nz // Some default settings data.SetParameter(MaterialData::Blending, true); data.SetParameter(MaterialData::DepthWrite, true); - data.SetParameter(MaterialData::DstBlend, static_cast(BlendFunc_InvSrcAlpha)); - data.SetParameter(MaterialData::SrcBlend, static_cast(BlendFunc_SrcAlpha)); + data.SetParameter(MaterialData::DstBlend, static_cast(BlendFunc_InvSrcAlpha)); + data.SetParameter(MaterialData::SrcBlend, static_cast(BlendFunc_SrcAlpha)); } it = materialCache.emplace(matName, std::move(data)).first; @@ -139,7 +139,7 @@ namespace Nz bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) { - int reservedVertexCount; + long long reservedVertexCount; if (!parameters.custom.GetIntegerParameter("NativeOBJLoader_VertexCount", &reservedVertexCount)) reservedVertexCount = 100; diff --git a/src/Nazara/Utility/Formats/OBJSaver.cpp b/src/Nazara/Utility/Formats/OBJSaver.cpp index 513f28ff7..7b3507730 100644 --- a/src/Nazara/Utility/Formats/OBJSaver.cpp +++ b/src/Nazara/Utility/Formats/OBJSaver.cpp @@ -128,7 +128,7 @@ namespace Nz else { Color colorVal; - float fValue; + double dValue; if (matData.GetColorParameter(MaterialData::AmbientColor, &colorVal)) material->ambient = colorVal; @@ -139,8 +139,8 @@ namespace Nz if (matData.GetColorParameter(MaterialData::SpecularColor, &colorVal)) material->specular = colorVal; - if (matData.GetFloatParameter(MaterialData::Shininess, &fValue)) - material->shininess = fValue; + if (matData.GetDoubleParameter(MaterialData::Shininess, &dValue)) + material->shininess = float(dValue); if (matData.GetStringParameter(MaterialData::AlphaTexturePath, &strVal)) material->alphaMap = strVal; @@ -176,7 +176,7 @@ namespace Nz UInt32 faceIndex = 0; TriangleIterator triangle(staticMesh); - do + do { OBJParser::Face& face = meshes[i].faces[faceIndex]; face.firstVertex = faceIndex * 3; diff --git a/tests/Engine/Core/ParameterList.cpp b/tests/Engine/Core/ParameterList.cpp index ef2729833..5d998f5b8 100644 --- a/tests/Engine/Core/ParameterList.cpp +++ b/tests/Engine/Core/ParameterList.cpp @@ -24,13 +24,13 @@ SCENARIO("ParameterList", "[CORE][PARAMETERLIST]") WHEN("We add Float '3.f'") { - float fl = 3.f; - parameterList.SetParameter("float", fl); + double fl = 3.f; + parameterList.SetParameter("double", fl); THEN("We can get it back") { - float newFl; - REQUIRE(parameterList.GetFloatParameter("float", &newFl)); + double newFl; + REQUIRE(parameterList.GetDoubleParameter("double", &newFl)); REQUIRE(newFl == fl); } } From 308f6d744897ef70274a73855198d17fdf5dde28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 29 May 2017 20:00:39 +0200 Subject: [PATCH 59/73] #Oops --- plugins/Assimp/Plugin.cpp | 16 ++++---- src/Nazara/Graphics/Material.cpp | 66 ++++++++++++++++---------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/plugins/Assimp/Plugin.cpp b/plugins/Assimp/Plugin.cpp index 8a4ec0e09..744434137 100644 --- a/plugins/Assimp/Plugin.cpp +++ b/plugins/Assimp/Plugin.cpp @@ -108,21 +108,21 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) if (parameters.optimizeIndexBuffers) postProcess |= aiProcess_ImproveCacheLocality; - float smoothingAngle = 80.f; - parameters.custom.GetFloatParameter("AssimpLoader_SmoothingAngle", &smoothingAngle); + double smoothingAngle = 80.f; + parameters.custom.GetDoubleParameter("AssimpLoader_SmoothingAngle", &smoothingAngle); - int triangleLimit = 1'000'000; + long long triangleLimit = 1'000'000; parameters.custom.GetIntegerParameter("AssimpLoader_TriangleLimit", &triangleLimit); - int vertexLimit = 1'000'000; + long long vertexLimit = 1'000'000; parameters.custom.GetIntegerParameter("AssimpLoader_VertexLimit", &vertexLimit); aiPropertyStore* properties = aiCreatePropertyStore(); - aiSetImportPropertyFloat(properties, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, smoothingAngle); + aiSetImportPropertyFloat(properties, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, float(smoothingAngle)); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SBP_REMOVE, ~aiPrimitiveType_TRIANGLE); //< We only want triangles - aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, triangleLimit); - aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_VERTEX_LIMIT, vertexLimit); + aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, int(triangleLimit)); + aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_VERTEX_LIMIT, int(vertexLimit)); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_RVC_FLAGS, aiComponent_COLORS); const aiScene* scene = aiImportFileExWithProperties(userdata.originalFilePath, postProcess, &fileIO, properties); @@ -276,7 +276,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) break; } - matData.SetParameter(wrapKey, static_cast(wrap)); + matData.SetParameter(wrapKey, static_cast(wrap)); } } }; diff --git a/src/Nazara/Graphics/Material.cpp b/src/Nazara/Graphics/Material.cpp index df871f9f2..0e865038a 100644 --- a/src/Nazara/Graphics/Material.cpp +++ b/src/Nazara/Graphics/Material.cpp @@ -114,14 +114,14 @@ namespace Nz { Color color; bool isEnabled; - float fValue; - int iValue; + double dValue; + long long iValue; String path; ErrorFlags errFlags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled, true); - if (matData.GetFloatParameter(MaterialData::AlphaThreshold, &fValue)) - SetAlphaThreshold(fValue); + if (matData.GetDoubleParameter(MaterialData::AlphaThreshold, &dValue)) + SetAlphaThreshold(float(dValue)); if (matData.GetBooleanParameter(MaterialData::AlphaTest, &isEnabled)) EnableAlphaTest(isEnabled); @@ -147,17 +147,17 @@ namespace Nz if (matData.GetIntegerParameter(MaterialData::FaceFilling, &iValue)) SetFaceFilling(static_cast(iValue)); - if (matData.GetFloatParameter(MaterialData::LineWidth, &fValue)) - SetLineWidth(fValue); + if (matData.GetDoubleParameter(MaterialData::LineWidth, &dValue)) + SetLineWidth(float(dValue)); - if (matData.GetFloatParameter(MaterialData::PointSize, &fValue)) - SetPointSize(fValue); + if (matData.GetDoubleParameter(MaterialData::PointSize, &dValue)) + SetPointSize(float(dValue)); if (matData.GetColorParameter(MaterialData::SpecularColor, &color)) SetSpecularColor(color); - if (matData.GetFloatParameter(MaterialData::Shininess, &fValue)) - SetShininess(fValue); + if (matData.GetDoubleParameter(MaterialData::Shininess, &dValue)) + SetShininess(float(dValue)); if (matData.GetIntegerParameter(MaterialData::SrcBlend, &iValue)) SetSrcBlend(static_cast(iValue)); @@ -277,17 +277,17 @@ namespace Nz matData->SetParameter(MaterialData::AlphaTest, IsAlphaTestEnabled()); matData->SetParameter(MaterialData::AlphaThreshold, GetAlphaThreshold()); matData->SetParameter(MaterialData::AmbientColor, GetAmbientColor()); - matData->SetParameter(MaterialData::CullingSide, int(GetFaceCulling())); - matData->SetParameter(MaterialData::DepthFunc, int(GetDepthFunc())); + matData->SetParameter(MaterialData::CullingSide, static_cast(GetFaceCulling())); + matData->SetParameter(MaterialData::DepthFunc, static_cast(GetDepthFunc())); matData->SetParameter(MaterialData::DepthSorting, IsDepthSortingEnabled()); matData->SetParameter(MaterialData::DiffuseColor, GetDiffuseColor()); - matData->SetParameter(MaterialData::DstBlend, int(GetDstBlend())); - matData->SetParameter(MaterialData::FaceFilling, int(GetFaceFilling())); + matData->SetParameter(MaterialData::DstBlend, static_cast(GetDstBlend())); + matData->SetParameter(MaterialData::FaceFilling, static_cast(GetFaceFilling())); matData->SetParameter(MaterialData::LineWidth, GetLineWidth()); matData->SetParameter(MaterialData::PointSize, GetPointSize()); matData->SetParameter(MaterialData::Shininess, GetShininess()); matData->SetParameter(MaterialData::SpecularColor, GetSpecularColor()); - matData->SetParameter(MaterialData::SrcBlend, int(GetSrcBlend())); + matData->SetParameter(MaterialData::SrcBlend, static_cast(GetSrcBlend())); // RendererParameter matData->SetParameter(MaterialData::Blending, IsBlendingEnabled()); @@ -299,29 +299,29 @@ namespace Nz matData->SetParameter(MaterialData::StencilTest, IsStencilTestEnabled()); // Samplers - matData->SetParameter(MaterialData::DiffuseAnisotropyLevel, int(GetDiffuseSampler().GetAnisotropicLevel())); - matData->SetParameter(MaterialData::DiffuseFilter, int(GetDiffuseSampler().GetFilterMode())); - matData->SetParameter(MaterialData::DiffuseWrap, int(GetDiffuseSampler().GetWrapMode())); + matData->SetParameter(MaterialData::DiffuseAnisotropyLevel, static_cast(GetDiffuseSampler().GetAnisotropicLevel())); + matData->SetParameter(MaterialData::DiffuseFilter, static_cast(GetDiffuseSampler().GetFilterMode())); + matData->SetParameter(MaterialData::DiffuseWrap, static_cast(GetDiffuseSampler().GetWrapMode())); - matData->SetParameter(MaterialData::SpecularAnisotropyLevel, int(GetSpecularSampler().GetAnisotropicLevel())); - matData->SetParameter(MaterialData::SpecularFilter, int(GetSpecularSampler().GetFilterMode())); - matData->SetParameter(MaterialData::SpecularWrap, int(GetSpecularSampler().GetWrapMode())); + matData->SetParameter(MaterialData::SpecularAnisotropyLevel, static_cast(GetSpecularSampler().GetAnisotropicLevel())); + matData->SetParameter(MaterialData::SpecularFilter, static_cast(GetSpecularSampler().GetFilterMode())); + matData->SetParameter(MaterialData::SpecularWrap, static_cast(GetSpecularSampler().GetWrapMode())); // Stencil - matData->SetParameter(MaterialData::StencilCompare, int(GetPipelineInfo().stencilCompare.front)); - matData->SetParameter(MaterialData::StencilFail, int(GetPipelineInfo().stencilFail.front)); - matData->SetParameter(MaterialData::StencilPass, int(GetPipelineInfo().stencilPass.front)); - matData->SetParameter(MaterialData::StencilZFail, int(GetPipelineInfo().stencilDepthFail.front)); - matData->SetParameter(MaterialData::StencilMask, int(GetPipelineInfo().stencilWriteMask.front)); - matData->SetParameter(MaterialData::StencilReference, int(GetPipelineInfo().stencilReference.front)); + matData->SetParameter(MaterialData::StencilCompare, static_cast(GetPipelineInfo().stencilCompare.front)); + matData->SetParameter(MaterialData::StencilFail, static_cast(GetPipelineInfo().stencilFail.front)); + matData->SetParameter(MaterialData::StencilPass, static_cast(GetPipelineInfo().stencilPass.front)); + matData->SetParameter(MaterialData::StencilZFail, static_cast(GetPipelineInfo().stencilDepthFail.front)); + matData->SetParameter(MaterialData::StencilMask, static_cast(GetPipelineInfo().stencilWriteMask.front)); + matData->SetParameter(MaterialData::StencilReference, static_cast(GetPipelineInfo().stencilReference.front)); // Stencil (back) - matData->SetParameter(MaterialData::BackFaceStencilCompare, int(GetPipelineInfo().stencilCompare.back)); - matData->SetParameter(MaterialData::BackFaceStencilFail, int(GetPipelineInfo().stencilFail.back)); - matData->SetParameter(MaterialData::BackFaceStencilPass, int(GetPipelineInfo().stencilPass.back)); - matData->SetParameter(MaterialData::BackFaceStencilZFail, int(GetPipelineInfo().stencilDepthFail.back)); - matData->SetParameter(MaterialData::BackFaceStencilMask, int(GetPipelineInfo().stencilWriteMask.back)); - matData->SetParameter(MaterialData::BackFaceStencilReference, int(GetPipelineInfo().stencilReference.back)); + matData->SetParameter(MaterialData::BackFaceStencilCompare, static_cast(GetPipelineInfo().stencilCompare.back)); + matData->SetParameter(MaterialData::BackFaceStencilFail, static_cast(GetPipelineInfo().stencilFail.back)); + matData->SetParameter(MaterialData::BackFaceStencilPass, static_cast(GetPipelineInfo().stencilPass.back)); + matData->SetParameter(MaterialData::BackFaceStencilZFail, static_cast(GetPipelineInfo().stencilDepthFail.back)); + matData->SetParameter(MaterialData::BackFaceStencilMask, static_cast(GetPipelineInfo().stencilWriteMask.back)); + matData->SetParameter(MaterialData::BackFaceStencilReference, static_cast(GetPipelineInfo().stencilReference.back)); // Textures if (HasAlphaMap()) From 3b914422c825aed2b71d01f201866b8bd2f25ddf Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 30 May 2017 00:50:28 +0200 Subject: [PATCH 60/73] SDK/EntityList: Fix warning on GCC --- SDK/include/NDK/EntityList.hpp | 4 ++-- SDK/include/NDK/EntityList.inl | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SDK/include/NDK/EntityList.hpp b/SDK/include/NDK/EntityList.hpp index b659b15fb..8303f7fa4 100644 --- a/SDK/include/NDK/EntityList.hpp +++ b/SDK/include/NDK/EntityList.hpp @@ -59,11 +59,11 @@ namespace Ndk friend EntityList; public: - inline iterator(const iterator& iterator); + inline iterator(const iterator& it); const EntityHandle& operator*() const; - inline iterator& operator=(const iterator& iterator); + inline iterator& operator=(const iterator& it); inline iterator& operator++(); inline iterator operator++(int); diff --git a/SDK/include/NDK/EntityList.inl b/SDK/include/NDK/EntityList.inl index d178d2b09..8d871e2c6 100644 --- a/SDK/include/NDK/EntityList.inl +++ b/SDK/include/NDK/EntityList.inl @@ -207,16 +207,16 @@ namespace Ndk { } - inline EntityList::iterator::iterator(const iterator& iterator) : - m_nextEntityId(iterator.m_nextEntityId), - m_list(iterator.m_list) + inline EntityList::iterator::iterator(const iterator& it) : + m_nextEntityId(it.m_nextEntityId), + m_list(it.m_list) { } - inline EntityList::iterator& EntityList::iterator::operator=(const iterator& iterator) + inline EntityList::iterator& EntityList::iterator::operator=(const iterator& it) { - m_nextEntityId = iterator.m_nextEntityId; - m_list = iterator.m_list; + m_nextEntityId = it.m_nextEntityId; + m_list = it.m_list; return *this; } From 4f1d52b395566cbbe718274ce1342b4097b1af17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 1 Jun 2017 17:24:28 +0200 Subject: [PATCH 61/73] Fix [Box|Rect]::Contains including outer border points --- include/Nazara/Math/Box.inl | 6 +++--- include/Nazara/Math/Rect.inl | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/Nazara/Math/Box.inl b/include/Nazara/Math/Box.inl index 1b5276ee6..60275b206 100644 --- a/include/Nazara/Math/Box.inl +++ b/include/Nazara/Math/Box.inl @@ -133,9 +133,9 @@ namespace Nz template bool Box::Contains(T X, T Y, T Z) const { - return X >= x && X <= x + width && - Y >= y && Y <= y + height && - Z >= z && Z <= z + depth; + return X >= x && X < x + width && + Y >= y && Y < y + height && + Z >= z && Z < z + depth; } /*! diff --git a/include/Nazara/Math/Rect.inl b/include/Nazara/Math/Rect.inl index 47a837cbd..f5d96c249 100644 --- a/include/Nazara/Math/Rect.inl +++ b/include/Nazara/Math/Rect.inl @@ -117,8 +117,8 @@ namespace Nz template bool Rect::Contains(T X, T Y) const { - return X >= x && X <= (x + width) && - Y >= y && Y <= (y + height); + return X >= x && X < (x + width) && + Y >= y && Y < (y + height); } /*! From 8752d1e0f40e8710b0f406dc5ae4159cc52db6e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 1 Jun 2017 17:25:21 +0200 Subject: [PATCH 62/73] Network: Add ErrorToString for ResolveError/SocketError --- include/Nazara/Network/Algorithm.hpp | 4 + src/Nazara/Network/AlgorithmNetwork.cpp | 110 +++++++++++++++++++++++- 2 files changed, 110 insertions(+), 4 deletions(-) diff --git a/include/Nazara/Network/Algorithm.hpp b/include/Nazara/Network/Algorithm.hpp index 001d98059..1befe974e 100644 --- a/include/Nazara/Network/Algorithm.hpp +++ b/include/Nazara/Network/Algorithm.hpp @@ -9,11 +9,15 @@ #include #include +#include #include #include namespace Nz { + NAZARA_NETWORK_API const char* ErrorToString(Nz::ResolveError resolveError); + NAZARA_NETWORK_API const char* ErrorToString(Nz::SocketError socketError); + NAZARA_NETWORK_API bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port = nullptr, bool* isIPv6 = nullptr, const char** endOfRead = nullptr); } diff --git a/src/Nazara/Network/AlgorithmNetwork.cpp b/src/Nazara/Network/AlgorithmNetwork.cpp index 4538230f3..9a593db39 100644 --- a/src/Nazara/Network/AlgorithmNetwork.cpp +++ b/src/Nazara/Network/AlgorithmNetwork.cpp @@ -19,7 +19,6 @@ namespace Nz * \param number Optional argument to return the number parsed * \param endOfRead Optional argument to determine where parsing stopped */ - bool ParseDecimal(const char* str, unsigned int* number, const char** endOfRead) { const char* ptr = str; @@ -52,7 +51,6 @@ namespace Nz * \param number Optional argument to return the number parsed * \param endOfRead Optional argument to determine where parsing stopped */ - bool ParseHexadecimal(const char* str, unsigned int* number, const char** endOfRead) { const char* ptr = str; @@ -78,8 +76,113 @@ namespace Nz } } + /*! - * \ingroup network + * \ingroup network + * \brief Returns the text representation of an error + * \return Text representation of an error + * + * \param resolveError Error enumeration + */ + const char* ErrorToString(Nz::ResolveError resolveError) + { + switch (resolveError) + { + case Nz::ResolveError_NoError: + return "No error"; + + case Nz::ResolveError_Internal: + return "An internal error occurred"; + + case Nz::ResolveError_ResourceError: + return "The operating system lacks the resources to proceed"; + + case Nz::ResolveError_NonRecoverable: + return "A nonrecoverable error occurred"; + + case Nz::ResolveError_NotFound: + return "No such host is known"; + + case Nz::ResolveError_NotInitialized: + return "Nazara Network has not been initialized"; + + case Nz::ResolveError_ProtocolNotSupported: + return "A specified protocol is not supported by the server"; + + case Nz::ResolveError_TemporaryFailure: + return "A temporary failure occurred, try again"; + + case Nz::ResolveError_Unknown: + return "An unknown error occurred"; + + default: + return "Invalid error value"; + } + } + + /*! + * \ingroup network + * \brief Returns the text representation of an error + * \return Text representation of an error + * + * \param socketError Error enumeration + */ + const char* ErrorToString(Nz::SocketError socketError) + { + switch (socketError) + { + case Nz::SocketError_NoError: + return "No error"; + + case Nz::SocketError_AddressNotAvailable: + return "The address is already in use"; + + case Nz::SocketError_ConnectionClosed: + return "The connection has been closed"; + + case Nz::SocketError_ConnectionRefused: + return "The connection attempt was refused"; + + case Nz::SocketError_DatagramSize: + return "The datagram size is over the system limit"; + + case Nz::SocketError_Internal: + return "An internal error occurred"; + + case Nz::SocketError_Packet: + return "Packet encoding or decoding failed"; + + case Nz::SocketError_NetworkError: + return "Networking subsystem failed"; + + case Nz::SocketError_NotInitialized: + return "Network module has not been initialized"; + + case Nz::SocketError_NotSupported: + return "This operation is not supported"; + + case Nz::SocketError_ResolveError: + return "The hostname couldn't be resolved"; + + case Nz::SocketError_ResourceError: + return "The operating system lacks the resources to proceed"; + + case Nz::SocketError_TimedOut: + return "The operation timed out"; + + case Nz::SocketError_Unknown: + return "An unknown error occurred"; + + case Nz::SocketError_UnreachableHost: + return "The host is not reachable"; + + default: + return "Invalid error value"; + } + } + + /*! + * \ingroup network * \brief Parse a textual IPv4 or IPv6 address * \return true If successful * @@ -97,7 +200,6 @@ namespace Nz * \remark Produces a NazaraAssert if addressPtr is invalid * \remark Produces a NazaraAssert if result is invalid */ - bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port, bool* isIPv6, const char** endOfRead) { NazaraAssert(addressPtr, "Invalid address string"); From e32c1a8b8b34408328a210263ada489f6b8dbbc1 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 4 Jun 2017 17:28:58 +0200 Subject: [PATCH 63/73] Utility/PixelFormat: Move Flip to .cpp Because of std::swap_range usage (Thanks Microsoft) --- include/Nazara/Utility/PixelFormat.hpp | 2 +- include/Nazara/Utility/PixelFormat.inl | 96 -------------------------- src/Nazara/Utility/PixelFormat.cpp | 96 ++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 97 deletions(-) diff --git a/include/Nazara/Utility/PixelFormat.hpp b/include/Nazara/Utility/PixelFormat.hpp index 8731ad29f..f6c3a36a4 100644 --- a/include/Nazara/Utility/PixelFormat.hpp +++ b/include/Nazara/Utility/PixelFormat.hpp @@ -65,7 +65,7 @@ namespace Nz static inline bool Convert(PixelFormatType srcFormat, PixelFormatType dstFormat, const void* src, void* dst); static inline bool Convert(PixelFormatType srcFormat, PixelFormatType dstFormat, const void* start, const void* end, void* dst); - static inline bool Flip(PixelFlipping flipping, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst); + static bool Flip(PixelFlipping flipping, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst); static inline UInt8 GetBitsPerPixel(PixelFormatType format); static inline PixelFormatContent GetContent(PixelFormatType format); diff --git a/include/Nazara/Utility/PixelFormat.inl b/include/Nazara/Utility/PixelFormat.inl index b4dfd95ee..4fe75c8b5 100644 --- a/include/Nazara/Utility/PixelFormat.inl +++ b/include/Nazara/Utility/PixelFormat.inl @@ -227,102 +227,6 @@ namespace Nz return true; } - inline bool PixelFormat::Flip(PixelFlipping flipping, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst) - { - #if NAZARA_UTILITY_SAFE - if (!IsValid(format)) - { - NazaraError("Invalid pixel format"); - return false; - } - #endif - - auto it = s_flipFunctions[flipping].find(format); - if (it != s_flipFunctions[flipping].end()) - it->second(width, height, depth, reinterpret_cast(src), reinterpret_cast(dst)); - else - { - // Flipping générique - - #if NAZARA_UTILITY_SAFE - if (IsCompressed(format)) - { - NazaraError("No function to flip compressed format"); - return false; - } - #endif - - UInt8 bpp = GetBytesPerPixel(format); - unsigned int lineStride = width*bpp; - switch (flipping) - { - case PixelFlipping_Horizontally: - { - if (src == dst) - { - for (unsigned int z = 0; z < depth; ++z) - { - UInt8* ptr = reinterpret_cast(dst) + width*height*z; - for (unsigned int y = 0; y < height/2; ++y) - std::swap_ranges(&ptr[y*lineStride], &ptr[(y+1)*lineStride-1], &ptr[(height-y-1)*lineStride]); - } - } - else - { - for (unsigned int z = 0; z < depth; ++z) - { - const UInt8* srcPtr = reinterpret_cast(src); - UInt8* dstPtr = reinterpret_cast(dst) + (width-1)*height*depth*bpp; - for (unsigned int y = 0; y < height; ++y) - { - std::memcpy(dstPtr, srcPtr, lineStride); - - srcPtr += lineStride; - dstPtr -= lineStride; - } - } - } - break; - } - - case PixelFlipping_Vertically: - { - if (src == dst) - { - for (unsigned int z = 0; z < depth; ++z) - { - UInt8* ptr = reinterpret_cast(dst) + width*height*z; - for (unsigned int y = 0; y < height; ++y) - { - for (unsigned int x = 0; x < width/2; ++x) - std::swap_ranges(&ptr[x*bpp], &ptr[(x+1)*bpp], &ptr[(width-x)*bpp]); - - ptr += lineStride; - } - } - } - else - { - for (unsigned int z = 0; z < depth; ++z) - { - UInt8* ptr = reinterpret_cast(dst) + width*height*z; - for (unsigned int y = 0; y < height; ++y) - { - for (unsigned int x = 0; x < width; ++x) - std::memcpy(&ptr[x*bpp], &ptr[(width-x)*bpp], bpp); - - ptr += lineStride; - } - } - } - break; - } - } - } - - return true; - } - inline UInt8 PixelFormat::GetBitsPerPixel(PixelFormatType format) { return s_pixelFormatInfos[format].bitsPerPixel; diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index 8bfe461e3..f27f6bd00 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -1268,6 +1268,102 @@ namespace Nz } } + bool PixelFormat::Flip(PixelFlipping flipping, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst) + { + #if NAZARA_UTILITY_SAFE + if (!IsValid(format)) + { + NazaraError("Invalid pixel format"); + return false; + } + #endif + + auto it = s_flipFunctions[flipping].find(format); + if (it != s_flipFunctions[flipping].end()) + it->second(width, height, depth, reinterpret_cast(src), reinterpret_cast(dst)); + else + { + // Flipping générique + + #if NAZARA_UTILITY_SAFE + if (IsCompressed(format)) + { + NazaraError("No function to flip compressed format"); + return false; + } + #endif + + UInt8 bpp = GetBytesPerPixel(format); + unsigned int lineStride = width*bpp; + switch (flipping) + { + case PixelFlipping_Horizontally: + { + if (src == dst) + { + for (unsigned int z = 0; z < depth; ++z) + { + UInt8* ptr = reinterpret_cast(dst) + width*height*z; + for (unsigned int y = 0; y < height / 2; ++y) + std::swap_ranges(&ptr[y*lineStride], &ptr[(y + 1)*lineStride - 1], &ptr[(height - y - 1)*lineStride]); + } + } + else + { + for (unsigned int z = 0; z < depth; ++z) + { + const UInt8* srcPtr = reinterpret_cast(src); + UInt8* dstPtr = reinterpret_cast(dst) + (width - 1)*height*depth*bpp; + for (unsigned int y = 0; y < height; ++y) + { + std::memcpy(dstPtr, srcPtr, lineStride); + + srcPtr += lineStride; + dstPtr -= lineStride; + } + } + } + break; + } + + case PixelFlipping_Vertically: + { + if (src == dst) + { + for (unsigned int z = 0; z < depth; ++z) + { + UInt8* ptr = reinterpret_cast(dst) + width*height*z; + for (unsigned int y = 0; y < height; ++y) + { + for (unsigned int x = 0; x < width / 2; ++x) + std::swap_ranges(&ptr[x*bpp], &ptr[(x + 1)*bpp], &ptr[(width - x)*bpp]); + + ptr += lineStride; + } + } + } + else + { + for (unsigned int z = 0; z < depth; ++z) + { + UInt8* ptr = reinterpret_cast(dst) + width*height*z; + for (unsigned int y = 0; y < height; ++y) + { + for (unsigned int x = 0; x < width; ++x) + std::memcpy(&ptr[x*bpp], &ptr[(width - x)*bpp], bpp); + + ptr += lineStride; + } + } + } + break; + } + } + } + + return true; + } + PixelFormatType PixelFormat::IdentifyFormat(const PixelFormatInfo& info) { for (unsigned int i = 0; i <= PixelFormatType_Max; ++i) From c98fb482e7bb54054b6cf40eddd1dffb745824ec Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 5 Jun 2017 15:06:19 +0200 Subject: [PATCH 64/73] Network/ENetPeer: Add GetRoundTripTime method --- include/Nazara/Network/ENetPeer.hpp | 1 + include/Nazara/Network/ENetPeer.inl | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp index e3538e6fb..4e36378a5 100644 --- a/include/Nazara/Network/ENetPeer.hpp +++ b/include/Nazara/Network/ENetPeer.hpp @@ -55,6 +55,7 @@ namespace Nz inline UInt32 GetPacketThrottleDeceleration() const; inline UInt32 GetPacketThrottleInterval() const; inline UInt16 GetPeerId() const; + inline UInt32 GetRoundTripTime() const; inline ENetPeerState GetState() const; inline bool HasPendingCommands(); diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index bcec4a8c1..d831b4d0d 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -48,6 +48,11 @@ namespace Nz return m_incomingPeerID; } + inline UInt32 ENetPeer::GetRoundTripTime() const + { + return m_roundTripTime; + } + inline ENetPeerState ENetPeer::GetState() const { return m_state; From 184a970b722e16477a327a3810ea9ce01ca3891d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 6 Jun 2017 16:50:09 +0200 Subject: [PATCH 65/73] Fix all flags.. --- include/Nazara/Core/Flags.hpp | 5 +++ include/Nazara/Core/Flags.inl | 62 +++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/Nazara/Core/Flags.hpp b/include/Nazara/Core/Flags.hpp index cb336def6..5285ef601 100644 --- a/include/Nazara/Core/Flags.hpp +++ b/include/Nazara/Core/Flags.hpp @@ -54,6 +54,11 @@ namespace Nz private: BitField m_value; }; + + template constexpr std::enable_if_t::value, Flags> operator~(E lhs); + template constexpr std::enable_if_t::value, Flags> operator|(E lhs, E rhs); + template constexpr std::enable_if_t::value, Flags> operator&(E lhs, E rhs); + template constexpr std::enable_if_t::value, Flags> operator^(E lhs, E rhs); } template constexpr std::enable_if_t::value, Nz::Flags> operator~(E lhs); diff --git a/include/Nazara/Core/Flags.inl b/include/Nazara/Core/Flags.inl index 973da958d..3832d3b50 100644 --- a/include/Nazara/Core/Flags.inl +++ b/include/Nazara/Core/Flags.inl @@ -209,6 +209,68 @@ namespace Nz { return 1U << static_cast(enumValue); } + + + /*! + * \brief Override binary NOT operator on enum to turns into a Flags object. + * \return A Flags object with reversed bits. + * + * \param lhs Enumeration value to reverse. + * + * Returns a Flags object with all state enabled except for the enum one. + */ + template + constexpr std::enable_if_t::value, Flags> operator~(E lhs) + { + return ~Flags(lhs); + } + + /*! + * \brief Override binary OR operator on enum to turns into a Flags object. + * \return A Flags object with combined enum states. + * + * \param lhs First enumeration value to combine. + * \param rhs Second enumeration value to combine. + * + * Returns a Flags object with combined states from the two enumeration values. + */ + template + constexpr std::enable_if_t::value, Flags> operator|(E lhs, E rhs) + { + return Flags(lhs) | rhs; + } + + /*! + * \brief Override binary AND operator on enum to turns into a Flags object. + * \return A Flags object with compare enum states. + * + * \param lhs First enumeration value to compare. + * \param rhs Second enumeration value to compare. + * + * Returns a Flags object with compared states from the two enumeration values. + * In this case, only one flag will be enabled if both enumeration values are the same. + */ + template + constexpr std::enable_if_t::value, Flags> operator&(E lhs, E rhs) + { + return Flags(lhs) & rhs; + } + + /*! + * \brief Override binary XOR operator on enum to turns into a Flags object. + * \return A Flags object with XORed enum states. + * + * \param lhs First enumeration value to compare. + * \param rhs Second enumeration value to compare. + * + * Returns a Flags object with XORed states from the two enumeration values. + * In this case, two flags will be enabled if both the enumeration values are different. + */ + template + constexpr std::enable_if_t::value, Flags> operator^(E lhs, E rhs) + { + return Flags(lhs) ^ rhs; + } } /*! From b7df3bd1c4acd7fc0de159159bff992c2a801092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 6 Jun 2017 18:08:36 +0200 Subject: [PATCH 66/73] Core/Flags: Try some hack to fix compilation --- include/Nazara/Core/Flags.hpp | 19 ++-- include/Nazara/Core/Flags.inl | 180 ++++++++++++---------------------- 2 files changed, 72 insertions(+), 127 deletions(-) diff --git a/include/Nazara/Core/Flags.hpp b/include/Nazara/Core/Flags.hpp index 5285ef601..293a8dfa8 100644 --- a/include/Nazara/Core/Flags.hpp +++ b/include/Nazara/Core/Flags.hpp @@ -55,16 +55,19 @@ namespace Nz BitField m_value; }; - template constexpr std::enable_if_t::value, Flags> operator~(E lhs); - template constexpr std::enable_if_t::value, Flags> operator|(E lhs, E rhs); - template constexpr std::enable_if_t::value, Flags> operator&(E lhs, E rhs); - template constexpr std::enable_if_t::value, Flags> operator^(E lhs, E rhs); + // Little hack to have them in both Nz and global scope + namespace DetailFlagOperators + { + template constexpr std::enable_if_t::value, Flags> operator~(E lhs); + template constexpr std::enable_if_t::value, Flags> operator|(E lhs, E rhs); + template constexpr std::enable_if_t::value, Flags> operator&(E lhs, E rhs); + template constexpr std::enable_if_t::value, Flags> operator^(E lhs, E rhs); + } + + using namespace DetailFlagOperators; } -template constexpr std::enable_if_t::value, Nz::Flags> operator~(E lhs); -template constexpr std::enable_if_t::value, Nz::Flags> operator|(E lhs, E rhs); -template constexpr std::enable_if_t::value, Nz::Flags> operator&(E lhs, E rhs); -template constexpr std::enable_if_t::value, Nz::Flags> operator^(E lhs, E rhs); +using namespace Nz::DetailFlagOperators; #include diff --git a/include/Nazara/Core/Flags.inl b/include/Nazara/Core/Flags.inl index 3832d3b50..11cd22109 100644 --- a/include/Nazara/Core/Flags.inl +++ b/include/Nazara/Core/Flags.inl @@ -211,127 +211,69 @@ namespace Nz } - /*! - * \brief Override binary NOT operator on enum to turns into a Flags object. - * \return A Flags object with reversed bits. - * - * \param lhs Enumeration value to reverse. - * - * Returns a Flags object with all state enabled except for the enum one. - */ - template - constexpr std::enable_if_t::value, Flags> operator~(E lhs) + namespace DetailFlagOperators { - return ~Flags(lhs); + /*! + * \brief Override binary NOT operator on enum to turns into a Flags object. + * \return A Flags object with reversed bits. + * + * \param lhs Enumeration value to reverse. + * + * Returns a Flags object with all state enabled except for the enum one. + */ + template + constexpr std::enable_if_t::value, Flags> operator~(E lhs) + { + return ~Flags(lhs); + } + + /*! + * \brief Override binary OR operator on enum to turns into a Flags object. + * \return A Flags object with combined enum states. + * + * \param lhs First enumeration value to combine. + * \param rhs Second enumeration value to combine. + * + * Returns a Flags object with combined states from the two enumeration values. + */ + template + constexpr std::enable_if_t::value, Flags> operator|(E lhs, E rhs) + { + return Flags(lhs) | rhs; + } + + /*! + * \brief Override binary AND operator on enum to turns into a Flags object. + * \return A Flags object with compare enum states. + * + * \param lhs First enumeration value to compare. + * \param rhs Second enumeration value to compare. + * + * Returns a Flags object with compared states from the two enumeration values. + * In this case, only one flag will be enabled if both enumeration values are the same. + */ + template + constexpr std::enable_if_t::value, Flags> operator&(E lhs, E rhs) + { + return Flags(lhs) & rhs; + } + + /*! + * \brief Override binary XOR operator on enum to turns into a Flags object. + * \return A Flags object with XORed enum states. + * + * \param lhs First enumeration value to compare. + * \param rhs Second enumeration value to compare. + * + * Returns a Flags object with XORed states from the two enumeration values. + * In this case, two flags will be enabled if both the enumeration values are different. + */ + template + constexpr std::enable_if_t::value, Flags> operator^(E lhs, E rhs) + { + return Flags(lhs) ^ rhs; + } } - - /*! - * \brief Override binary OR operator on enum to turns into a Flags object. - * \return A Flags object with combined enum states. - * - * \param lhs First enumeration value to combine. - * \param rhs Second enumeration value to combine. - * - * Returns a Flags object with combined states from the two enumeration values. - */ - template - constexpr std::enable_if_t::value, Flags> operator|(E lhs, E rhs) - { - return Flags(lhs) | rhs; - } - - /*! - * \brief Override binary AND operator on enum to turns into a Flags object. - * \return A Flags object with compare enum states. - * - * \param lhs First enumeration value to compare. - * \param rhs Second enumeration value to compare. - * - * Returns a Flags object with compared states from the two enumeration values. - * In this case, only one flag will be enabled if both enumeration values are the same. - */ - template - constexpr std::enable_if_t::value, Flags> operator&(E lhs, E rhs) - { - return Flags(lhs) & rhs; - } - - /*! - * \brief Override binary XOR operator on enum to turns into a Flags object. - * \return A Flags object with XORed enum states. - * - * \param lhs First enumeration value to compare. - * \param rhs Second enumeration value to compare. - * - * Returns a Flags object with XORed states from the two enumeration values. - * In this case, two flags will be enabled if both the enumeration values are different. - */ - template - constexpr std::enable_if_t::value, Flags> operator^(E lhs, E rhs) - { - return Flags(lhs) ^ rhs; - } -} - -/*! -* \brief Override binary NOT operator on enum to turns into a Flags object. -* \return A Flags object with reversed bits. -* -* \param lhs Enumeration value to reverse. -* -* Returns a Flags object with all state enabled except for the enum one. -*/ -template -constexpr std::enable_if_t::value, Nz::Flags> operator~(E lhs) -{ - return ~Nz::Flags(lhs); -} - -/*! -* \brief Override binary OR operator on enum to turns into a Flags object. -* \return A Flags object with combined enum states. -* -* \param lhs First enumeration value to combine. -* \param rhs Second enumeration value to combine. -* -* Returns a Flags object with combined states from the two enumeration values. -*/ -template -constexpr std::enable_if_t::value, Nz::Flags> operator|(E lhs, E rhs) -{ - return Nz::Flags(lhs) | rhs; -} - -/*! -* \brief Override binary AND operator on enum to turns into a Flags object. -* \return A Flags object with compare enum states. -* -* \param lhs First enumeration value to compare. -* \param rhs Second enumeration value to compare. -* -* Returns a Flags object with compared states from the two enumeration values. -* In this case, only one flag will be enabled if both enumeration values are the same. -*/ -template -constexpr std::enable_if_t::value, Nz::Flags> operator&(E lhs, E rhs) -{ - return Nz::Flags(lhs) & rhs; -} - -/*! -* \brief Override binary XOR operator on enum to turns into a Flags object. -* \return A Flags object with XORed enum states. -* -* \param lhs First enumeration value to compare. -* \param rhs Second enumeration value to compare. -* -* Returns a Flags object with XORed states from the two enumeration values. -* In this case, two flags will be enabled if both the enumeration values are different. -*/ -template -constexpr std::enable_if_t::value, Nz::Flags> operator^(E lhs, E rhs) -{ - return Nz::Flags(lhs) ^ rhs; } #include From a8129b218b63474fa6b06a0f42338b32eeaee172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 7 Jun 2017 21:18:07 +0200 Subject: [PATCH 67/73] Refactor LuaInstance to prepare coroutine handling --- SDK/include/NDK/Console.hpp | 6 +- SDK/include/NDK/Lua/LuaBinding.hpp | 12 +- SDK/include/NDK/Lua/LuaBinding.inl | 4 +- SDK/include/NDK/Lua/LuaBinding_Audio.hpp | 2 +- SDK/include/NDK/Lua/LuaBinding_Base.hpp | 2 +- SDK/include/NDK/Lua/LuaBinding_Core.hpp | 2 +- SDK/include/NDK/Lua/LuaBinding_Graphics.hpp | 2 +- SDK/include/NDK/Lua/LuaBinding_Math.hpp | 2 +- SDK/include/NDK/Lua/LuaBinding_Network.hpp | 2 +- SDK/include/NDK/Lua/LuaBinding_Renderer.hpp | 2 +- SDK/include/NDK/Lua/LuaBinding_SDK.hpp | 2 +- SDK/include/NDK/Lua/LuaBinding_Utility.hpp | 2 +- SDK/include/NDK/LuaAPI.hpp | 4 +- SDK/include/NDK/LuaAPI.inl | 402 ++++----- SDK/src/NDK/Application.cpp | 16 +- SDK/src/NDK/Console.cpp | 8 +- SDK/src/NDK/Lua/LuaBinding.cpp | 26 +- SDK/src/NDK/Lua/LuaBinding_Audio.cpp | 22 +- SDK/src/NDK/Lua/LuaBinding_Core.cpp | 108 +-- SDK/src/NDK/Lua/LuaBinding_Graphics.cpp | 40 +- SDK/src/NDK/Lua/LuaBinding_Math.cpp | 84 +- SDK/src/NDK/Lua/LuaBinding_Network.cpp | 184 ++--- SDK/src/NDK/Lua/LuaBinding_Renderer.cpp | 10 +- SDK/src/NDK/Lua/LuaBinding_SDK.cpp | 58 +- SDK/src/NDK/Lua/LuaBinding_Utility.cpp | 202 +++-- SDK/src/NDK/LuaAPI.cpp | 4 +- include/Nazara/Lua/LuaClass.hpp | 60 +- include/Nazara/Lua/LuaClass.inl | 330 ++++---- include/Nazara/Lua/LuaInstance.hpp | 180 +---- include/Nazara/Lua/LuaInstance.inl | 779 ------------------ include/Nazara/Lua/LuaState.hpp | 197 +++++ include/Nazara/Lua/LuaState.inl | 788 ++++++++++++++++++ src/Nazara/Lua/LuaInstance.cpp | 853 +------------------- src/Nazara/Lua/LuaState.cpp | 834 +++++++++++++++++++ 34 files changed, 2635 insertions(+), 2594 deletions(-) create mode 100644 include/Nazara/Lua/LuaState.hpp create mode 100644 include/Nazara/Lua/LuaState.inl create mode 100644 src/Nazara/Lua/LuaState.cpp diff --git a/SDK/include/NDK/Console.hpp b/SDK/include/NDK/Console.hpp index 5c7935a7c..9635373e0 100644 --- a/SDK/include/NDK/Console.hpp +++ b/SDK/include/NDK/Console.hpp @@ -19,7 +19,7 @@ namespace Nz { - class LuaInstance; + class LuaState; } namespace Ndk @@ -32,7 +32,7 @@ namespace Ndk class NDK_API Console : public Nz::Node, public Nz::HandledObject { public: - Console(World& world, const Nz::Vector2f& size, Nz::LuaInstance& instance); + Console(World& world, const Nz::Vector2f& size, Nz::LuaState& state); Console(const Console& console) = delete; Console(Console&& console) = default; ~Console() = default; @@ -83,7 +83,7 @@ namespace Ndk EntityOwner m_input; EntityOwner m_inputBackground; Nz::FontRef m_defaultFont; - Nz::LuaInstance& m_instance; + Nz::LuaState& m_state; Nz::SpriteRef m_historyBackgroundSprite; Nz::SpriteRef m_inputBackgroundSprite; Nz::SimpleTextDrawer m_historyDrawer; diff --git a/SDK/include/NDK/Lua/LuaBinding.hpp b/SDK/include/NDK/Lua/LuaBinding.hpp index 88b6a88ef..c1ea9206d 100644 --- a/SDK/include/NDK/Lua/LuaBinding.hpp +++ b/SDK/include/NDK/Lua/LuaBinding.hpp @@ -24,7 +24,7 @@ namespace Ndk template void BindComponent(const Nz::String& name); - void RegisterClasses(Nz::LuaInstance& instance); + void RegisterClasses(Nz::LuaState& state); std::unique_ptr core; std::unique_ptr math; @@ -40,13 +40,13 @@ namespace Ndk private: template - static int AddComponentOfType(Nz::LuaInstance& lua, EntityHandle& handle); + static int AddComponentOfType(Nz::LuaState& lua, EntityHandle& handle); template - static int PushComponentOfType(Nz::LuaInstance& lua, BaseComponent& component); + static int PushComponentOfType(Nz::LuaState& lua, BaseComponent& component); - using AddComponentFunc = int(*)(Nz::LuaInstance&, EntityHandle&); - using GetComponentFunc = int(*)(Nz::LuaInstance&, BaseComponent&); + using AddComponentFunc = int(*)(Nz::LuaState&, EntityHandle&); + using GetComponentFunc = int(*)(Nz::LuaState&, BaseComponent&); struct ComponentBinding { @@ -56,7 +56,7 @@ namespace Ndk Nz::String name; }; - ComponentBinding* QueryComponentIndex(Nz::LuaInstance& lua, int argIndex = 2); + ComponentBinding* QueryComponentIndex(Nz::LuaState& lua, int argIndex = 2); std::vector m_componentBinding; std::unordered_map m_componentBindingByName; diff --git a/SDK/include/NDK/Lua/LuaBinding.inl b/SDK/include/NDK/Lua/LuaBinding.inl index c9f3f86bb..502f179ae 100644 --- a/SDK/include/NDK/Lua/LuaBinding.inl +++ b/SDK/include/NDK/Lua/LuaBinding.inl @@ -33,7 +33,7 @@ namespace Ndk } template - int LuaBinding::AddComponentOfType(Nz::LuaInstance& lua, EntityHandle& handle) + int LuaBinding::AddComponentOfType(Nz::LuaState& lua, EntityHandle& handle) { static_assert(std::is_base_of::value, "ComponentType must inherit BaseComponent"); @@ -43,7 +43,7 @@ namespace Ndk } template - int LuaBinding::PushComponentOfType(Nz::LuaInstance& lua, BaseComponent& component) + int LuaBinding::PushComponentOfType(Nz::LuaState& lua, BaseComponent& component) { static_assert(std::is_base_of::value, "ComponentType must inherit BaseComponent"); diff --git a/SDK/include/NDK/Lua/LuaBinding_Audio.hpp b/SDK/include/NDK/Lua/LuaBinding_Audio.hpp index 1764fb729..d842ecc9b 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Audio.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Audio.hpp @@ -21,7 +21,7 @@ namespace Ndk LuaBinding_Audio(LuaBinding& binding); ~LuaBinding_Audio() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass music; Nz::LuaClass sound; diff --git a/SDK/include/NDK/Lua/LuaBinding_Base.hpp b/SDK/include/NDK/Lua/LuaBinding_Base.hpp index 36c41af8c..8e596e999 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Base.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Base.hpp @@ -30,7 +30,7 @@ namespace Ndk LuaBinding_Base(LuaBinding& binding); virtual ~LuaBinding_Base(); - virtual void Register(Nz::LuaInstance& instance) = 0; + virtual void Register(Nz::LuaState& state) = 0; // Implementation lies in the respective .cpp files (still searching for a cleaner way..) static std::unique_ptr BindCore(LuaBinding& binding); diff --git a/SDK/include/NDK/Lua/LuaBinding_Core.hpp b/SDK/include/NDK/Lua/LuaBinding_Core.hpp index 97d31cde4..decca39fc 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Core.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Core.hpp @@ -21,7 +21,7 @@ namespace Ndk LuaBinding_Core(LuaBinding& binding); ~LuaBinding_Core() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass clock; Nz::LuaClass directory; diff --git a/SDK/include/NDK/Lua/LuaBinding_Graphics.hpp b/SDK/include/NDK/Lua/LuaBinding_Graphics.hpp index 0bfece994..cd71f0fc5 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Graphics.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Graphics.hpp @@ -22,7 +22,7 @@ namespace Ndk LuaBinding_Graphics(LuaBinding& binding); ~LuaBinding_Graphics() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass abstractViewer; Nz::LuaClass instancedRenderable; diff --git a/SDK/include/NDK/Lua/LuaBinding_Math.hpp b/SDK/include/NDK/Lua/LuaBinding_Math.hpp index d94f357c3..386912bab 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Math.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Math.hpp @@ -23,7 +23,7 @@ namespace Ndk LuaBinding_Math(LuaBinding& binding); ~LuaBinding_Math() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass eulerAngles; Nz::LuaClass matrix4d; diff --git a/SDK/include/NDK/Lua/LuaBinding_Network.hpp b/SDK/include/NDK/Lua/LuaBinding_Network.hpp index 3774cb5e8..daee2b224 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Network.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Network.hpp @@ -20,7 +20,7 @@ namespace Ndk LuaBinding_Network(LuaBinding& binding); ~LuaBinding_Network() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass abstractSocket; Nz::LuaClass ipAddress; diff --git a/SDK/include/NDK/Lua/LuaBinding_Renderer.hpp b/SDK/include/NDK/Lua/LuaBinding_Renderer.hpp index a2db03f8d..af1ffeaa5 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Renderer.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Renderer.hpp @@ -18,7 +18,7 @@ namespace Ndk LuaBinding_Renderer(LuaBinding& binding); ~LuaBinding_Renderer() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass texture; Nz::LuaClass textureLibrary; diff --git a/SDK/include/NDK/Lua/LuaBinding_SDK.hpp b/SDK/include/NDK/Lua/LuaBinding_SDK.hpp index b6b7079eb..8a6a0915e 100644 --- a/SDK/include/NDK/Lua/LuaBinding_SDK.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_SDK.hpp @@ -22,7 +22,7 @@ namespace Ndk LuaBinding_SDK(LuaBinding& binding); ~LuaBinding_SDK() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass application; Nz::LuaClass entity; diff --git a/SDK/include/NDK/Lua/LuaBinding_Utility.hpp b/SDK/include/NDK/Lua/LuaBinding_Utility.hpp index b10492efc..8aefd20c6 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Utility.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Utility.hpp @@ -21,7 +21,7 @@ namespace Ndk LuaBinding_Utility(LuaBinding& binding); ~LuaBinding_Utility() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; // Utility Nz::LuaClass abstractImage; diff --git a/SDK/include/NDK/LuaAPI.hpp b/SDK/include/NDK/LuaAPI.hpp index 3ed73d9d2..d3e755fc6 100644 --- a/SDK/include/NDK/LuaAPI.hpp +++ b/SDK/include/NDK/LuaAPI.hpp @@ -11,7 +11,7 @@ namespace Nz { - class LuaInstance; + class LuaState; } namespace Ndk @@ -28,7 +28,7 @@ namespace Ndk static bool Initialize(); - static void RegisterClasses(Nz::LuaInstance& instance); + static void RegisterClasses(Nz::LuaState& state); static void Uninitialize(); diff --git a/SDK/include/NDK/LuaAPI.inl b/SDK/include/NDK/LuaAPI.inl index 4cc0e4342..84e3fb34e 100644 --- a/SDK/include/NDK/LuaAPI.inl +++ b/SDK/include/NDK/LuaAPI.inl @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include @@ -28,103 +28,103 @@ namespace Nz { - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Color* color, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Color* color, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - color->r = instance.CheckField("r", index); - color->g = instance.CheckField("g", index); - color->b = instance.CheckField("b", index); - color->a = instance.CheckField("a", 255, index); + color->r = state.CheckField("r", index); + color->g = state.CheckField("g", index); + color->b = state.CheckField("b", index); + color->a = state.CheckField("a", 255, index); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, EulerAnglesd* angles, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, EulerAnglesd* angles, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_Table: - angles->Set(instance.CheckField("pitch", index), instance.CheckField("yaw", index), instance.CheckField("roll", index)); + angles->Set(state.CheckField("pitch", index), state.CheckField("yaw", index), state.CheckField("roll", index)); return 1; default: { - if (instance.IsOfType(index, "EulerAngles")) - angles->Set(*static_cast(instance.ToUserdata(index))); + if (state.IsOfType(index, "EulerAngles")) + angles->Set(*static_cast(state.ToUserdata(index))); else - angles->Set(*static_cast(instance.CheckUserdata(index, "Quaternion"))); + angles->Set(*static_cast(state.CheckUserdata(index, "Quaternion"))); return 1; } } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, EulerAnglesf* angles, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, EulerAnglesf* angles, TypeTag) { EulerAnglesd anglesDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &anglesDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &anglesDouble, TypeTag()); angles->Set(anglesDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, FontRef* fontRef, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, FontRef* fontRef, TypeTag) { - *fontRef = *static_cast(instance.CheckUserdata(index, "Font")); + *fontRef = *static_cast(state.CheckUserdata(index, "Font")); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, FontParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, FontParams* params, TypeTag) { NazaraUnused(params); - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); // Structure is empty for now return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, ImageParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, ImageParams* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->levelCount = instance.CheckField("LevelCount"); - params->loadFormat = instance.CheckField("LoadFormat"); + params->levelCount = state.CheckField("LevelCount"); + params->loadFormat = state.CheckField("LoadFormat"); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, IpAddress* address, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, IpAddress* address, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_String: - address->BuildFromAddress(instance.CheckString(index)); + address->BuildFromAddress(state.CheckString(index)); return 1; default: - *address = *static_cast(instance.CheckUserdata(index, "IpAddress")); + *address = *static_cast(state.CheckUserdata(index, "IpAddress")); return 1; } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Matrix4d* mat, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Matrix4d* mat, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_Table: { double values[16]; for (std::size_t i = 0; i < 16; ++i) { - instance.PushInteger(i + 1); - instance.GetTable(); + state.PushInteger(i + 1); + state.GetTable(); - values[i] = instance.CheckNumber(-1); - instance.Pop(); + values[i] = state.CheckNumber(-1); + state.Pop(); } mat->Set(values); @@ -133,500 +133,500 @@ namespace Nz default: { - if (instance.IsOfType(index, "Matrix4")) - mat->Set(*static_cast(instance.ToUserdata(index))); + if (state.IsOfType(index, "Matrix4")) + mat->Set(*static_cast(state.ToUserdata(index))); return 1; } } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Matrix4f* mat, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Matrix4f* mat, TypeTag) { Matrix4d matDouble = Matrix4d::Identity(); - unsigned int ret = LuaImplQueryArg(instance, index, &matDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &matDouble, TypeTag()); mat->Set(matDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, MeshParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, MeshParams* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->animated = instance.CheckField("Animated", params->animated); - params->center = instance.CheckField("Center", params->center); - params->matrix = instance.CheckField("Matrix", params->matrix); - params->optimizeIndexBuffers = instance.CheckField("OptimizeIndexBuffers", params->optimizeIndexBuffers); - params->texCoordOffset = instance.CheckField("TexCoordOffset", params->texCoordOffset); - params->texCoordScale = instance.CheckField("TexCoordScale", params->texCoordScale); + params->animated = state.CheckField("Animated", params->animated); + params->center = state.CheckField("Center", params->center); + params->matrix = state.CheckField("Matrix", params->matrix); + params->optimizeIndexBuffers = state.CheckField("OptimizeIndexBuffers", params->optimizeIndexBuffers); + params->texCoordOffset = state.CheckField("TexCoordOffset", params->texCoordOffset); + params->texCoordScale = state.CheckField("TexCoordScale", params->texCoordScale); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Quaterniond* quat, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Quaterniond* quat, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_Table: - quat->Set(instance.CheckField("w", index), instance.CheckField("x", index), instance.CheckField("y", index), instance.CheckField("z", index)); + quat->Set(state.CheckField("w", index), state.CheckField("x", index), state.CheckField("y", index), state.CheckField("z", index)); return 1; default: { - if (instance.IsOfType(index, "EulerAngles")) - quat->Set(*static_cast(instance.ToUserdata(index))); + if (state.IsOfType(index, "EulerAngles")) + quat->Set(*static_cast(state.ToUserdata(index))); else - quat->Set(*static_cast(instance.CheckUserdata(index, "Quaternion"))); + quat->Set(*static_cast(state.CheckUserdata(index, "Quaternion"))); return 1; } } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Quaternionf* quat, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Quaternionf* quat, TypeTag) { Quaterniond quatDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &quatDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &quatDouble, TypeTag()); quat->Set(quatDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Rectd* rect, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Rectd* rect, TypeTag) { - instance.CheckType(index, LuaType_Table); + state.CheckType(index, LuaType_Table); - rect->x = instance.CheckField("x", index); - rect->y = instance.CheckField("y", index); - rect->width = instance.CheckField("width", index); - rect->height = instance.CheckField("height", index); + rect->x = state.CheckField("x", index); + rect->y = state.CheckField("y", index); + rect->width = state.CheckField("width", index); + rect->height = state.CheckField("height", index); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Rectf* rect, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Rectf* rect, TypeTag) { Rectd rectDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &rectDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &rectDouble, TypeTag()); rect->Set(rectDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Recti* rect, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Recti* rect, TypeTag) { Rectd rectDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &rectDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &rectDouble, TypeTag()); rect->Set(rectDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Rectui* rect, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Rectui* rect, TypeTag) { Rectd rectDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &rectDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &rectDouble, TypeTag()); rect->Set(rectDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector2d* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector2d* vec, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_Number: if (index < 0 && index > -2) - instance.Error("Vector2 expected, two numbers are required to convert it"); + state.Error("Vector2 expected, two numbers are required to convert it"); - vec->Set(instance.CheckNumber(index), instance.CheckNumber(index + 1)); + vec->Set(state.CheckNumber(index), state.CheckNumber(index + 1)); return 2; case Nz::LuaType_Table: - vec->Set(instance.CheckField("x", index), instance.CheckField("y", index)); + vec->Set(state.CheckField("x", index), state.CheckField("y", index)); return 1; default: - vec->Set(*static_cast(instance.CheckUserdata(index, "Vector2"))); + vec->Set(*static_cast(state.CheckUserdata(index, "Vector2"))); return 1; } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector2f* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector2f* vec, TypeTag) { Vector2d vecDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &vecDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &vecDouble, TypeTag()); vec->Set(vecDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector2ui* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector2ui* vec, TypeTag) { Vector2d vecDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &vecDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &vecDouble, TypeTag()); vec->Set(vecDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector3d* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector3d* vec, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_Number: if (index < 0 && index > -3) - instance.Error("Vector3 expected, three numbers are required to convert it"); + state.Error("Vector3 expected, three numbers are required to convert it"); - vec->Set(instance.CheckNumber(index), instance.CheckNumber(index + 1), instance.CheckNumber(index + 2, 0.0)); + vec->Set(state.CheckNumber(index), state.CheckNumber(index + 1), state.CheckNumber(index + 2, 0.0)); return 3; case Nz::LuaType_Table: - vec->Set(instance.CheckField("x", index), instance.CheckField("y", index), instance.CheckField("z", 0.0, index)); + vec->Set(state.CheckField("x", index), state.CheckField("y", index), state.CheckField("z", 0.0, index)); return 1; default: - vec->Set(*static_cast(instance.CheckUserdata(index, "Vector3"))); + vec->Set(*static_cast(state.CheckUserdata(index, "Vector3"))); return 1; } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector3f* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector3f* vec, TypeTag) { Vector3d vecDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &vecDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &vecDouble, TypeTag()); vec->Set(vecDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector3ui* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector3ui* vec, TypeTag) { Vector3d vecDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &vecDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &vecDouble, TypeTag()); vec->Set(vecDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Ndk::EntityHandle* handle, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Ndk::EntityHandle* handle, TypeTag) { - *handle = *static_cast(instance.CheckUserdata(index, "Entity")); + *handle = *static_cast(state.CheckUserdata(index, "Entity")); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Ndk::WorldHandle* handle, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Ndk::WorldHandle* handle, TypeTag) { - *handle = *static_cast(instance.CheckUserdata(index, "World")); + *handle = *static_cast(state.CheckUserdata(index, "World")); return 1; } #ifndef NDK_SERVER - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, InstancedRenderableRef* renderable, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, InstancedRenderableRef* renderable, TypeTag) { - if (instance.IsOfType(index, "InstancedRenderable") || - instance.IsOfType(index, "Model") || - instance.IsOfType(index, "Sprite")) + if (state.IsOfType(index, "InstancedRenderable") || + state.IsOfType(index, "Model") || + state.IsOfType(index, "Sprite")) { - *renderable = *static_cast(instance.ToUserdata(index)); + *renderable = *static_cast(state.ToUserdata(index)); } else - instance.ArgError(index, "is not a InstancedRenderable instance"); + state.ArgError(index, "is not a InstancedRenderable instance"); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, MaterialRef* materialRef, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, MaterialRef* materialRef, TypeTag) { - *materialRef = *static_cast(instance.CheckUserdata(index, "Material")); + *materialRef = *static_cast(state.CheckUserdata(index, "Material")); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, MaterialParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, MaterialParams* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->loadAlphaMap = instance.CheckField("LoadAlphaMap", params->loadAlphaMap); - params->loadDiffuseMap = instance.CheckField("LoadDiffuseMap", params->loadDiffuseMap); - params->loadEmissiveMap = instance.CheckField("LoadEmissiveMap", params->loadEmissiveMap); - params->loadHeightMap = instance.CheckField("LoadHeightMap", params->loadHeightMap); - params->loadNormalMap = instance.CheckField("LoadNormalMap", params->loadNormalMap); - params->loadSpecularMap = instance.CheckField("LoadSpecularMap", params->loadSpecularMap); - params->shaderName = instance.CheckField("ShaderName", params->shaderName); + params->loadAlphaMap = state.CheckField("LoadAlphaMap", params->loadAlphaMap); + params->loadDiffuseMap = state.CheckField("LoadDiffuseMap", params->loadDiffuseMap); + params->loadEmissiveMap = state.CheckField("LoadEmissiveMap", params->loadEmissiveMap); + params->loadHeightMap = state.CheckField("LoadHeightMap", params->loadHeightMap); + params->loadNormalMap = state.CheckField("LoadNormalMap", params->loadNormalMap); + params->loadSpecularMap = state.CheckField("LoadSpecularMap", params->loadSpecularMap); + params->shaderName = state.CheckField("ShaderName", params->shaderName); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, ModelParameters* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, ModelParameters* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->loadMaterials = instance.CheckField("LoadMaterials", params->loadMaterials); + params->loadMaterials = state.CheckField("LoadMaterials", params->loadMaterials); - LuaImplQueryArg(instance, -1, ¶ms->material, TypeTag()); - LuaImplQueryArg(instance, -1, ¶ms->mesh, TypeTag()); + LuaImplQueryArg(state, -1, ¶ms->material, TypeTag()); + LuaImplQueryArg(state, -1, ¶ms->mesh, TypeTag()); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, MusicParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, MusicParams* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->forceMono = instance.CheckField("ForceMono", params->forceMono); + params->forceMono = state.CheckField("ForceMono", params->forceMono); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, SoundBufferParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, SoundBufferParams* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->forceMono = instance.CheckField("ForceMono", params->forceMono); + params->forceMono = state.CheckField("ForceMono", params->forceMono); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, SpriteRef* spriteRef, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, SpriteRef* spriteRef, TypeTag) { - *spriteRef = *static_cast(instance.CheckUserdata(index, "Sprite")); + *spriteRef = *static_cast(state.CheckUserdata(index, "Sprite")); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, TextureRef* textureRef, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, TextureRef* textureRef, TypeTag) { - *textureRef = *static_cast(instance.CheckUserdata(index, "Texture")); + *textureRef = *static_cast(state.CheckUserdata(index, "Texture")); return 1; } #endif - inline int LuaImplReplyVal(const LuaInstance& instance, Color&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Color&& val, TypeTag) { - instance.PushTable(); - instance.PushField("r", val.r); - instance.PushField("g", val.g); - instance.PushField("b", val.b); - instance.PushField("a", val.a); + state.PushTable(); + state.PushField("r", val.r); + state.PushField("g", val.g); + state.PushField("b", val.b); + state.PushField("a", val.a); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, EulerAnglesd&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, EulerAnglesd&& val, TypeTag) { - instance.PushInstance("EulerAngles", val); + state.PushInstance("EulerAngles", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, EulerAnglesf&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, EulerAnglesf&& val, TypeTag) { - instance.PushInstance("EulerAngles", val); + state.PushInstance("EulerAngles", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, FontRef&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, FontRef&& val, TypeTag) { - instance.PushInstance("Font", val); + state.PushInstance("Font", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Font::SizeInfo&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Font::SizeInfo&& val, TypeTag) { - instance.PushTable(); - instance.PushField("LineHeight", val.lineHeight); - instance.PushField("SpaceAdvance", val.spaceAdvance); - instance.PushField("UnderlinePosition", val.underlinePosition); - instance.PushField("UnderlineThickness", val.underlineThickness); + state.PushTable(); + state.PushField("LineHeight", val.lineHeight); + state.PushField("SpaceAdvance", val.spaceAdvance); + state.PushField("UnderlinePosition", val.underlinePosition); + state.PushField("UnderlineThickness", val.underlineThickness); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, ImageParams&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, ImageParams&& val, TypeTag) { - instance.PushTable(0, 2); - instance.PushField("LevelCount", val.levelCount); - instance.PushField("LoadFormat", val.loadFormat); + state.PushTable(0, 2); + state.PushField("LevelCount", val.levelCount); + state.PushField("LoadFormat", val.loadFormat); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, IpAddress&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, IpAddress&& val, TypeTag) { - instance.PushInstance("IpAddress", val); + state.PushInstance("IpAddress", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Matrix4d&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Matrix4d&& val, TypeTag) { - instance.PushInstance("Matrix4", val); + state.PushInstance("Matrix4", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Matrix4f&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Matrix4f&& val, TypeTag) { - instance.PushInstance("Matrix4", val); + state.PushInstance("Matrix4", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Quaterniond&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Quaterniond&& val, TypeTag) { - instance.PushInstance("Quaternion", val); + state.PushInstance("Quaternion", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Quaternionf&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Quaternionf&& val, TypeTag) { - instance.PushInstance("Quaternion", val); + state.PushInstance("Quaternion", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Rectd&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Rectd&& val, TypeTag) { - instance.PushInstance("Rect", val); + state.PushInstance("Rect", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Rectf&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Rectf&& val, TypeTag) { - instance.PushInstance("Rect", val); + state.PushInstance("Rect", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Recti&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Recti&& val, TypeTag) { - instance.PushInstance("Rect", val); + state.PushInstance("Rect", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Rectui&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Rectui&& val, TypeTag) { - instance.PushInstance("Rect", val); + state.PushInstance("Rect", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector2d&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector2d&& val, TypeTag) { - instance.PushInstance("Vector2", val); + state.PushInstance("Vector2", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector2f&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector2f&& val, TypeTag) { - instance.PushInstance("Vector2", val); + state.PushInstance("Vector2", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector2ui&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector2ui&& val, TypeTag) { - instance.PushInstance("Vector2", val); + state.PushInstance("Vector2", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector3d&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector3d&& val, TypeTag) { - instance.PushInstance("Vector3", val); + state.PushInstance("Vector3", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector3f&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector3f&& val, TypeTag) { - instance.PushInstance("Vector3", val); + state.PushInstance("Vector3", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector3ui&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector3ui&& val, TypeTag) { - instance.PushInstance("Vector3", val); + state.PushInstance("Vector3", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::Entity* ptr, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::Entity* ptr, TypeTag) { - instance.PushInstance("Entity", ptr); + state.PushInstance("Entity", ptr); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::Application* ptr, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::Application* ptr, TypeTag) { - instance.PushInstance("Application", ptr); + state.PushInstance("Application", ptr); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::EntityHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::EntityHandle&& handle, TypeTag) { - instance.PushInstance("Entity", handle); + state.PushInstance("Entity", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::NodeComponentHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::NodeComponentHandle&& handle, TypeTag) { - instance.PushInstance("NodeComponent", handle); + state.PushInstance("NodeComponent", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::VelocityComponentHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::VelocityComponentHandle&& handle, TypeTag) { - instance.PushInstance("VelocityComponent", handle); + state.PushInstance("VelocityComponent", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::World* ptr, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::World* ptr, TypeTag) { - instance.PushInstance("World", ptr); + state.PushInstance("World", ptr); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::WorldHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::WorldHandle&& handle, TypeTag) { - instance.PushInstance("World", handle); + state.PushInstance("World", handle); return 1; } #ifndef NDK_SERVER - inline int LuaImplReplyVal(const LuaInstance& instance, MaterialRef&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, MaterialRef&& handle, TypeTag) { - instance.PushInstance("Material", handle); + state.PushInstance("Material", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, const SoundBuffer* val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, const SoundBuffer* val, TypeTag) { - instance.PushInstance("SoundBuffer", val); + state.PushInstance("SoundBuffer", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, SpriteRef&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, SpriteRef&& handle, TypeTag) { - instance.PushInstance("Sprite", handle); + state.PushInstance("Sprite", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, TextureRef&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, TextureRef&& handle, TypeTag) { - instance.PushInstance("Texture", handle); + state.PushInstance("Texture", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::CameraComponentHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::CameraComponentHandle&& handle, TypeTag) { - instance.PushInstance("CameraComponent", handle); + state.PushInstance("CameraComponent", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::ConsoleHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::ConsoleHandle&& handle, TypeTag) { - instance.PushInstance("Console", handle); + state.PushInstance("Console", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::GraphicsComponentHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::GraphicsComponentHandle&& handle, TypeTag) { - instance.PushInstance("GraphicsComponent", handle); + state.PushInstance("GraphicsComponent", handle); return 1; } #endif diff --git a/SDK/src/NDK/Application.cpp b/SDK/src/NDK/Application.cpp index e159c0101..c70ec181b 100644 --- a/SDK/src/NDK/Application.cpp +++ b/SDK/src/NDK/Application.cpp @@ -164,25 +164,25 @@ namespace Ndk LuaAPI::RegisterClasses(overlay->lua); // Override "print" function to add a line in the console - overlay->lua.PushFunction([&consoleRef] (Nz::LuaInstance& instance) + overlay->lua.PushFunction([&consoleRef] (Nz::LuaState& state) { Nz::StringStream stream; - unsigned int argCount = instance.GetStackTop(); - instance.GetGlobal("tostring"); + unsigned int argCount = state.GetStackTop(); + state.GetGlobal("tostring"); for (unsigned int i = 1; i <= argCount; ++i) { - instance.PushValue(-1); // tostring function - instance.PushValue(i); // argument - instance.Call(1, 1); + state.PushValue(-1); // tostring function + state.PushValue(i); // argument + state.Call(1, 1); std::size_t length; - const char* str = instance.CheckString(-1, &length); + const char* str = state.CheckString(-1, &length); if (i > 1) stream << '\t'; stream << Nz::String(str, length); - instance.Pop(1); + state.Pop(1); } consoleRef.AddLine(stream); diff --git a/SDK/src/NDK/Console.cpp b/SDK/src/NDK/Console.cpp index 3843978ad..a59bfdf81 100644 --- a/SDK/src/NDK/Console.cpp +++ b/SDK/src/NDK/Console.cpp @@ -33,10 +33,10 @@ namespace Ndk * \param instance Lua instance that will interact with the world */ - Console::Console(World& world, const Nz::Vector2f& size, Nz::LuaInstance& instance) : + Console::Console(World& world, const Nz::Vector2f& size, Nz::LuaState& state) : m_historyPosition(0), m_defaultFont(Nz::Font::GetDefault()), - m_instance(instance), + m_state(state), m_size(size), m_opened(false), m_characterSize(24) @@ -310,8 +310,8 @@ namespace Ndk AddLineInternal(input); //< With the input prefix - if (!m_instance.Execute(inputCmd)) - AddLineInternal(m_instance.GetLastError(), Nz::Color::Red); + if (!m_state.Execute(inputCmd)) + AddLineInternal(m_state.GetLastError(), Nz::Color::Red); RefreshHistory(); } diff --git a/SDK/src/NDK/Lua/LuaBinding.cpp b/SDK/src/NDK/Lua/LuaBinding.cpp index cb763b3b4..715351e52 100644 --- a/SDK/src/NDK/Lua/LuaBinding.cpp +++ b/SDK/src/NDK/Lua/LuaBinding.cpp @@ -22,7 +22,7 @@ namespace Ndk utility = LuaBinding_Base::BindUtility(*this); #ifndef NDK_SERVER - audio = LuaBinding_Base::BindAudio(*this); + audio = LuaBinding_Base::BindAudio(*this); renderer = LuaBinding_Base::BindRenderer(*this); graphics = LuaBinding_Base::BindGraphics(*this); #endif @@ -36,31 +36,31 @@ namespace Ndk * \param instance Lua instance that will interact with the engine & SDK */ - void LuaBinding::RegisterClasses(Nz::LuaInstance& instance) + void LuaBinding::RegisterClasses(Nz::LuaState& state) { - core->Register(instance); - math->Register(instance); - network->Register(instance); - sdk->Register(instance); - utility->Register(instance); + core->Register(state); + math->Register(state); + network->Register(state); + sdk->Register(state); + utility->Register(state); #ifndef NDK_SERVER - audio->Register(instance); - graphics->Register(instance); - renderer->Register(instance); + audio->Register(state); + graphics->Register(state); + renderer->Register(state); #endif // ComponentType (fake enumeration to expose component indexes) - instance.PushTable(0, m_componentBinding.size()); + state.PushTable(0, m_componentBinding.size()); { for (const ComponentBinding& entry : m_componentBinding) { if (entry.name.IsEmpty()) continue; - instance.PushField(entry.name, entry.index); + state.PushField(entry.name, entry.index); } } - instance.SetGlobal("ComponentType"); + state.SetGlobal("ComponentType"); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Audio.cpp b/SDK/src/NDK/Lua/LuaBinding_Audio.cpp index 619fe2850..1611c1b8c 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Audio.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Audio.cpp @@ -77,7 +77,7 @@ namespace Ndk music.BindMethod("Stop", &Nz::Music::Stop); // Manual - music.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::Music& instance, std::size_t /*argumentCount*/) -> int + music.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::Music& instance, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("Music("); ss << instance.GetFilePath() << ')'; @@ -104,7 +104,7 @@ namespace Ndk sound.BindMethod("SetPlayingOffset", &Nz::Sound::SetPlayingOffset); // Manual - sound.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::Sound& instance, std::size_t /*argumentCount*/) -> int + sound.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::Sound& instance, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("Sound("); if (const Nz::SoundBuffer* buffer = instance.GetBuffer()) @@ -120,7 +120,7 @@ namespace Ndk /*********************************** Nz::SoundBuffer **********************************/ soundBuffer.Reset("SoundBuffer"); { - soundBuffer.SetConstructor([] (Nz::LuaInstance& lua, Nz::SoundBufferRef* instance, std::size_t argumentCount) + soundBuffer.SetConstructor([] (Nz::LuaState& lua, Nz::SoundBufferRef* instance, std::size_t argumentCount) { NazaraUnused(lua); NazaraUnused(argumentCount); @@ -143,7 +143,7 @@ namespace Ndk soundBuffer.BindStaticMethod("IsFormatSupported", &Nz::SoundBuffer::IsFormatSupported); // Manual - soundBuffer.BindMethod("Create", [] (Nz::LuaInstance& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int + soundBuffer.BindMethod("Create", [] (Nz::LuaState& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int { int index = 2; Nz::AudioFormat format = lua.Check(&index); @@ -158,13 +158,13 @@ namespace Ndk return 1; }); - soundBuffer.BindMethod("GetSamples", [] (Nz::LuaInstance& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int + soundBuffer.BindMethod("GetSamples", [] (Nz::LuaState& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int { lua.PushString(reinterpret_cast(instance->GetSamples()), instance->GetSampleCount() * sizeof(Nz::Int16)); return 1; }); - soundBuffer.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int + soundBuffer.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("SoundBuffer("); if (instance->IsValid()) @@ -188,11 +188,11 @@ namespace Ndk * * \param instance Lua instance that will interact with the Audio classes */ - void LuaBinding_Audio::Register(Nz::LuaInstance& instance) + void LuaBinding_Audio::Register(Nz::LuaState& state) { - music.Register(instance); - sound.Register(instance); - soundBuffer.Register(instance); - soundEmitter.Register(instance); + music.Register(state); + sound.Register(state); + soundBuffer.Register(state); + soundEmitter.Register(state); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Core.cpp b/SDK/src/NDK/Lua/LuaBinding_Core.cpp index fc53f72c3..f86aafa98 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Core.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Core.cpp @@ -32,28 +32,28 @@ namespace Ndk stream.BindMethod("IsWritable", &Nz::Stream::IsWritable); stream.BindMethod("SetCursorPos", &Nz::Stream::SetCursorPos); - stream.BindMethod("Read", [] (Nz::LuaInstance& lua, Nz::Stream& instance, std::size_t /*argumentCount*/) -> int { + stream.BindMethod("Read", [] (Nz::LuaState& lua, Nz::Stream& stream, std::size_t /*argumentCount*/) -> int { int argIndex = 2; std::size_t length = lua.Check(&argIndex); std::unique_ptr buffer(new char[length]); - std::size_t readLength = instance.Read(buffer.get(), length); + std::size_t readLength = stream.Read(buffer.get(), length); lua.PushString(Nz::String(buffer.get(), readLength)); return 1; }); - stream.BindMethod("Write", [] (Nz::LuaInstance& lua, Nz::Stream& instance, std::size_t /*argumentCount*/) -> int { + stream.BindMethod("Write", [] (Nz::LuaState& lua, Nz::Stream& stream, std::size_t /*argumentCount*/) -> int { int argIndex = 2; std::size_t bufferSize = 0; const char* buffer = lua.CheckString(argIndex, &bufferSize); - if (instance.IsTextModeEnabled()) - lua.Push(instance.Write(Nz::String(buffer, bufferSize))); + if (stream.IsTextModeEnabled()) + lua.Push(stream.Write(Nz::String(buffer, bufferSize))); else - lua.Push(instance.Write(buffer, bufferSize)); + lua.Push(stream.Write(buffer, bufferSize)); return 1; }); } @@ -61,7 +61,7 @@ namespace Ndk /*********************************** Nz::Clock **********************************/ clock.Reset("Clock"); { - clock.SetConstructor([] (Nz::LuaInstance& lua, Nz::Clock* instance, std::size_t argumentCount) + clock.SetConstructor([] (Nz::LuaState& lua, Nz::Clock* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 2U); @@ -103,11 +103,11 @@ namespace Ndk clock.BindMethod("Unpause", &Nz::Clock::Unpause); // Manual - clock.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::Clock& instance, std::size_t /*argumentCount*/) -> int { + clock.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::Clock& clock, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("Clock(Elapsed: "); - ss << instance.GetSeconds(); + ss << clock.GetSeconds(); ss << "s, Paused: "; - ss << instance.IsPaused(); + ss << clock.IsPaused(); ss << ')'; lua.PushString(ss); @@ -118,7 +118,7 @@ namespace Ndk /********************************* Nz::Directory ********************************/ directory.Reset("Directory"); { - directory.SetConstructor([] (Nz::LuaInstance& lua, Nz::Directory* instance, std::size_t argumentCount) + directory.SetConstructor([] (Nz::LuaState& lua, Nz::Directory* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 1U); @@ -159,9 +159,9 @@ namespace Ndk directory.BindStaticMethod("SetCurrent", Nz::Directory::SetCurrent); // Manual - directory.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::Directory& instance, std::size_t /*argumentCount*/) -> int { + directory.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::Directory& dir, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("Directory("); - ss << instance.GetPath(); + ss << dir.GetPath(); ss << ')'; lua.PushString(ss); @@ -174,7 +174,7 @@ namespace Ndk { file.Inherit(stream); - file.SetConstructor([] (Nz::LuaInstance& lua, Nz::File* instance, std::size_t argumentCount) + file.SetConstructor([] (Nz::LuaState& lua, Nz::File* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 1U); @@ -237,7 +237,7 @@ namespace Ndk file.BindStaticMethod("Rename", &Nz::File::Rename); // Manual - file.BindMethod("Open", [] (Nz::LuaInstance& lua, Nz::File& instance, std::size_t argumentCount) -> int + file.BindMethod("Open", [] (Nz::LuaState& lua, Nz::File& file, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 2U); @@ -246,13 +246,13 @@ namespace Ndk { case 0: case 1: - return lua.Push(instance.Open(lua.Check(&argIndex, Nz::OpenMode_NotOpen))); + return lua.Push(file.Open(lua.Check(&argIndex, Nz::OpenMode_NotOpen))); case 2: { Nz::String filePath = lua.Check(&argIndex); Nz::UInt32 openMode = lua.Check(&argIndex, Nz::OpenMode_NotOpen); - return lua.Push(instance.Open(filePath, openMode)); + return lua.Push(file.Open(filePath, openMode)); } } @@ -260,7 +260,7 @@ namespace Ndk return 0; }); - file.BindMethod("SetCursorPos", [] (Nz::LuaInstance& lua, Nz::File& instance, std::size_t argumentCount) -> int + file.BindMethod("SetCursorPos", [] (Nz::LuaState& lua, Nz::File& file, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 2U); @@ -268,13 +268,13 @@ namespace Ndk switch (argCount) { case 1: - return lua.Push(instance.SetCursorPos(lua.Check(&argIndex))); + return lua.Push(file.SetCursorPos(lua.Check(&argIndex))); case 2: { Nz::CursorPosition curPos = lua.Check(&argIndex); Nz::Int64 offset = lua.Check(&argIndex); - return lua.Push(instance.SetCursorPos(curPos, offset)); + return lua.Push(file.SetCursorPos(curPos, offset)); } } @@ -282,10 +282,10 @@ namespace Ndk return 0; }); - file.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::File& instance, std::size_t /*argumentCount*/) -> int { + file.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::File& file, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("File("); - if (instance.IsOpen()) - ss << "Path: " << instance.GetPath(); + if (file.IsOpen()) + ss << "Path: " << file.GetPath(); ss << ')'; @@ -300,55 +300,55 @@ namespace Ndk * * \param instance Lua instance that will interact with the Core classes */ - void LuaBinding_Core::Register(Nz::LuaInstance& instance) + void LuaBinding_Core::Register(Nz::LuaState& state) { // Classes - clock.Register(instance); - directory.Register(instance); - file.Register(instance); - stream.Register(instance); + clock.Register(state); + directory.Register(state); + file.Register(state); + stream.Register(state); // Enums // Nz::CursorPosition static_assert(Nz::CursorPosition_Max + 1 == 3, "Nz::CursorPosition has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 3); + state.PushTable(0, 3); { - instance.PushField("AtBegin", Nz::CursorPosition_AtBegin); - instance.PushField("AtCurrent", Nz::CursorPosition_AtCurrent); - instance.PushField("AtEnd", Nz::CursorPosition_AtEnd); + state.PushField("AtBegin", Nz::CursorPosition_AtBegin); + state.PushField("AtCurrent", Nz::CursorPosition_AtCurrent); + state.PushField("AtEnd", Nz::CursorPosition_AtEnd); } - instance.SetGlobal("CursorPosition"); + state.SetGlobal("CursorPosition"); // Nz::HashType static_assert(Nz::HashType_Max + 1 == 9, "Nz::HashType has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 9); + state.PushTable(0, 9); { - instance.PushField("CRC32", Nz::HashType_CRC32); - instance.PushField("Fletcher16", Nz::HashType_Fletcher16); - instance.PushField("MD5", Nz::HashType_MD5); - instance.PushField("SHA1", Nz::HashType_SHA1); - instance.PushField("SHA224", Nz::HashType_SHA224); - instance.PushField("SHA256", Nz::HashType_SHA256); - instance.PushField("SHA384", Nz::HashType_SHA384); - instance.PushField("SHA512", Nz::HashType_SHA512); - instance.PushField("Whirlpool", Nz::HashType_Whirlpool); + state.PushField("CRC32", Nz::HashType_CRC32); + state.PushField("Fletcher16", Nz::HashType_Fletcher16); + state.PushField("MD5", Nz::HashType_MD5); + state.PushField("SHA1", Nz::HashType_SHA1); + state.PushField("SHA224", Nz::HashType_SHA224); + state.PushField("SHA256", Nz::HashType_SHA256); + state.PushField("SHA384", Nz::HashType_SHA384); + state.PushField("SHA512", Nz::HashType_SHA512); + state.PushField("Whirlpool", Nz::HashType_Whirlpool); } - instance.SetGlobal("HashType"); + state.SetGlobal("HashType"); // Nz::OpenMode static_assert(Nz::OpenMode_Max + 1 == 8, "Nz::OpenModeFlags has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, Nz::OpenMode_Max + 1); + state.PushTable(0, Nz::OpenMode_Max + 1); { - instance.PushField("Append", Nz::OpenMode_Append); - instance.PushField("NotOpen", Nz::OpenMode_NotOpen); - instance.PushField("Lock", Nz::OpenMode_Lock); - instance.PushField("ReadOnly", Nz::OpenMode_ReadOnly); - instance.PushField("ReadWrite", Nz::OpenMode_ReadWrite); - instance.PushField("Text", Nz::OpenMode_Text); - instance.PushField("Truncate", Nz::OpenMode_Truncate); - instance.PushField("WriteOnly", Nz::OpenMode_WriteOnly); + state.PushField("Append", Nz::OpenMode_Append); + state.PushField("NotOpen", Nz::OpenMode_NotOpen); + state.PushField("Lock", Nz::OpenMode_Lock); + state.PushField("ReadOnly", Nz::OpenMode_ReadOnly); + state.PushField("ReadWrite", Nz::OpenMode_ReadWrite); + state.PushField("Text", Nz::OpenMode_Text); + state.PushField("Truncate", Nz::OpenMode_Truncate); + state.PushField("WriteOnly", Nz::OpenMode_WriteOnly); } - instance.SetGlobal("OpenMode"); + state.SetGlobal("OpenMode"); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp b/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp index f87ac6556..d33811f49 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp @@ -37,7 +37,7 @@ namespace Ndk /*********************************** Nz::Material ***********************************/ material.Reset("Material"); { - material.SetConstructor([] (Nz::LuaInstance& lua, Nz::MaterialRef* instance, std::size_t argumentCount) + material.SetConstructor([] (Nz::LuaState& lua, Nz::MaterialRef* instance, std::size_t argumentCount) { switch (argumentCount) { @@ -70,7 +70,7 @@ namespace Ndk return false; }); - material.BindMethod("Configure", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("Configure", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "MaterialPipeline")) @@ -168,7 +168,7 @@ namespace Ndk material.BindStaticMethod("GetDefault", &Nz::Material::GetDefault); - material.BindMethod("SetAlphaMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetAlphaMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -180,7 +180,7 @@ namespace Ndk return lua.Push(instance->SetAlphaMap(lua.Check(&argIndex))); }); - material.BindMethod("SetDiffuseMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetDiffuseMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -192,7 +192,7 @@ namespace Ndk return lua.Push(instance->SetDiffuseMap(lua.Check(&argIndex))); }); - material.BindMethod("SetEmissiveMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetEmissiveMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -204,7 +204,7 @@ namespace Ndk return lua.Push(instance->SetEmissiveMap(lua.Check(&argIndex))); }); - material.BindMethod("SetHeightMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetHeightMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -216,7 +216,7 @@ namespace Ndk return lua.Push(instance->SetHeightMap(lua.Check(&argIndex))); }); - material.BindMethod("SetNormalMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetNormalMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -228,7 +228,7 @@ namespace Ndk return lua.Push(instance->SetNormalMap(lua.Check(&argIndex))); }); - material.BindMethod("SetShader", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetShader", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "UberShader")) @@ -240,7 +240,7 @@ namespace Ndk return lua.Push(instance->SetShader(lua.Check(&argIndex))); }); - material.BindMethod("SetSpecularMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetSpecularMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -261,7 +261,7 @@ namespace Ndk return reinterpret_cast(modelRef); //TODO: Make a ObjectRefCast }); - model.SetConstructor([] (Nz::LuaInstance& /*lua*/, Nz::ModelRef* instance, std::size_t /*argumentCount*/) + model.SetConstructor([] (Nz::LuaState& /*lua*/, Nz::ModelRef* instance, std::size_t /*argumentCount*/) { Nz::PlacementNew(instance, Nz::Model::New()); return true; @@ -293,7 +293,7 @@ namespace Ndk return reinterpret_cast(spriteRef); //TODO: Make a ObjectRefCast }); - sprite.SetConstructor([] (Nz::LuaInstance& /*lua*/, Nz::SpriteRef* instance, std::size_t /*argumentCount*/) + sprite.SetConstructor([] (Nz::LuaState& /*lua*/, Nz::SpriteRef* instance, std::size_t /*argumentCount*/) { Nz::PlacementNew(instance, Nz::Sprite::New()); return true; @@ -314,7 +314,7 @@ namespace Ndk sprite.BindMethod("SetTextureCoords", &Nz::Sprite::SetTextureCoords); sprite.BindMethod("SetTextureRect", &Nz::Sprite::SetTextureRect); - sprite.BindMethod("SetMaterial", [] (Nz::LuaInstance& lua, Nz::SpriteRef& instance, std::size_t /*argumentCount*/) -> int + sprite.BindMethod("SetMaterial", [] (Nz::LuaState& lua, Nz::SpriteRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; bool resizeSprite = lua.CheckBoolean(argIndex + 1, true); @@ -327,7 +327,7 @@ namespace Ndk return 0; }); - sprite.BindMethod("SetTexture", [] (Nz::LuaInstance& lua, Nz::SpriteRef& instance, std::size_t /*argumentCount*/) -> int + sprite.BindMethod("SetTexture", [] (Nz::LuaState& lua, Nz::SpriteRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; bool resizeSprite = lua.CheckBoolean(argIndex + 1, true); @@ -358,13 +358,13 @@ namespace Ndk * \param instance Lua instance that will interact with the Graphics classes */ - void LuaBinding_Graphics::Register(Nz::LuaInstance& instance) + void LuaBinding_Graphics::Register(Nz::LuaState& state) { - abstractViewer.Register(instance); - instancedRenderable.Register(instance); - material.Register(instance); - model.Register(instance); - sprite.Register(instance); - spriteLibrary.Register(instance); + abstractViewer.Register(state); + instancedRenderable.Register(state); + material.Register(state); + model.Register(state); + sprite.Register(state); + spriteLibrary.Register(state); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Math.cpp b/SDK/src/NDK/Lua/LuaBinding_Math.cpp index 42403a443..c218c2a66 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Math.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Math.cpp @@ -18,7 +18,7 @@ namespace Ndk /*********************************** Nz::EulerAngles **********************************/ eulerAngles.Reset("EulerAngles"); { - eulerAngles.SetConstructor([] (Nz::LuaInstance& lua, Nz::EulerAnglesd* instance, std::size_t argumentCount) + eulerAngles.SetConstructor([] (Nz::LuaState& lua, Nz::EulerAnglesd* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 3U); @@ -46,7 +46,7 @@ namespace Ndk eulerAngles.BindMethod("__tostring", &Nz::EulerAnglesd::ToString); - eulerAngles.SetGetter([] (Nz::LuaInstance& lua, Nz::EulerAnglesd& instance) + eulerAngles.SetGetter([] (Nz::LuaState& lua, Nz::EulerAnglesd& instance) { std::size_t length; const char* ypr = lua.CheckString(2, &length); @@ -103,7 +103,7 @@ namespace Ndk return false; }); - eulerAngles.SetSetter([] (Nz::LuaInstance& lua, Nz::EulerAnglesd& instance) + eulerAngles.SetSetter([] (Nz::LuaState& lua, Nz::EulerAnglesd& instance) { std::size_t length; const char* ypr = lua.CheckString(2, &length); @@ -165,7 +165,7 @@ namespace Ndk /*********************************** Nz::Matrix4 **********************************/ matrix4d.Reset("Matrix4"); { - matrix4d.SetConstructor([] (Nz::LuaInstance& lua, Nz::Matrix4d* matrix, std::size_t argumentCount) + matrix4d.SetConstructor([] (Nz::LuaState& lua, Nz::Matrix4d* matrix, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 3U); @@ -207,7 +207,7 @@ namespace Ndk matrix4d.BindMethod("GetDeterminant", &Nz::Matrix4d::GetDeterminant); matrix4d.BindMethod("GetDeterminantAffine", &Nz::Matrix4d::GetDeterminantAffine); - matrix4d.BindMethod("GetInverse", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("GetInverse", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { Nz::Matrix4d result; if (instance.GetInverse(&result)) @@ -216,7 +216,7 @@ namespace Ndk return lua.Push(false); }); - matrix4d.BindMethod("GetInverseAffine", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("GetInverseAffine", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { Nz::Matrix4d result; if (instance.GetInverseAffine(&result)) @@ -232,7 +232,7 @@ namespace Ndk matrix4d.BindMethod("GetSquaredScale", &Nz::Matrix4d::GetSquaredScale); matrix4d.BindMethod("GetTranslation", &Nz::Matrix4d::GetTranslation); - matrix4d.BindMethod("GetTransposed", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("GetTransposed", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { Nz::Matrix4d result; instance.GetTransposed(&result); @@ -243,7 +243,7 @@ namespace Ndk matrix4d.BindMethod("HasNegativeScale", &Nz::Matrix4d::HasNegativeScale); matrix4d.BindMethod("HasScale", &Nz::Matrix4d::HasScale); - matrix4d.BindMethod("Inverse", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("Inverse", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { bool succeeded; instance.Inverse(&succeeded); @@ -251,7 +251,7 @@ namespace Ndk return lua.Push(succeeded); }); - matrix4d.BindMethod("InverseAffine", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("InverseAffine", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { bool succeeded; instance.InverseAffine(&succeeded); @@ -273,7 +273,7 @@ namespace Ndk matrix4d.BindMethod("MakeViewMatrix", &Nz::Matrix4d::MakeViewMatrix); matrix4d.BindMethod("MakeZero", &Nz::Matrix4d::MakeZero); - matrix4d.BindMethod("Set", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t argumentCount) -> int + matrix4d.BindMethod("Set", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 3U); @@ -305,7 +305,7 @@ namespace Ndk matrix4d.BindMethod("SetScale", &Nz::Matrix4d::SetScale); matrix4d.BindMethod("SetTranslation", &Nz::Matrix4d::SetTranslation); - matrix4d.BindMethod("Transform", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("Transform", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Vector2")) @@ -345,7 +345,7 @@ namespace Ndk matrix4d.BindStaticMethod("ViewMatrix", &Nz::Matrix4d::ViewMatrix); matrix4d.BindStaticMethod("Zero", &Nz::Matrix4d::Zero); - matrix4d.SetGetter([] (Nz::LuaInstance& lua, Nz::Matrix4d& instance) + matrix4d.SetGetter([] (Nz::LuaState& lua, Nz::Matrix4d& instance) { bool succeeded = false; std::size_t index = static_cast(lua.ToInteger(2, &succeeded)); @@ -356,7 +356,7 @@ namespace Ndk return true; }); - matrix4d.SetSetter([] (Nz::LuaInstance& lua, Nz::Matrix4d& instance) + matrix4d.SetSetter([] (Nz::LuaState& lua, Nz::Matrix4d& instance) { bool succeeded = false; std::size_t index = static_cast(lua.ToInteger(2, &succeeded)); @@ -372,7 +372,7 @@ namespace Ndk /*********************************** Nz::Rect **********************************/ rect.Reset("Rect"); { - rect.SetConstructor([] (Nz::LuaInstance& lua, Nz::Rectd* instance, std::size_t argumentCount) + rect.SetConstructor([] (Nz::LuaState& lua, Nz::Rectd* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 4U); @@ -422,7 +422,7 @@ namespace Ndk rect.BindMethod("__tostring", &Nz::Rectd::ToString); - rect.SetGetter([] (Nz::LuaInstance& lua, Nz::Rectd& instance) + rect.SetGetter([] (Nz::LuaState& lua, Nz::Rectd& instance) { switch (lua.GetType(2)) { @@ -475,7 +475,7 @@ namespace Ndk return false; }); - rect.SetSetter([] (Nz::LuaInstance& lua, Nz::Rectd& instance) + rect.SetSetter([] (Nz::LuaState& lua, Nz::Rectd& instance) { switch (lua.GetType(2)) { @@ -531,7 +531,7 @@ namespace Ndk /*********************************** Nz::Quaternion **********************************/ quaternion.Reset("Quaternion"); { - quaternion.SetConstructor([] (Nz::LuaInstance& lua, Nz::Quaterniond* instance, std::size_t argumentCount) + quaternion.SetConstructor([] (Nz::LuaState& lua, Nz::Quaterniond* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 4U); @@ -587,7 +587,7 @@ namespace Ndk quaternion.BindStaticMethod("RotationBetween", &Nz::Quaterniond::RotationBetween); quaternion.BindStaticMethod("Slerp", &Nz::Quaterniond::Slerp); - quaternion.BindMethod("GetNormal", [] (Nz::LuaInstance& lua, Nz::Quaterniond& instance, std::size_t /*argumentCount*/) -> int + quaternion.BindMethod("GetNormal", [] (Nz::LuaState& lua, Nz::Quaterniond& instance, std::size_t /*argumentCount*/) -> int { double length; @@ -597,7 +597,7 @@ namespace Ndk return 2; }); - quaternion.BindMethod("Normalize", [] (Nz::LuaInstance& lua, Nz::Quaterniond& instance, std::size_t /*argumentCount*/) -> int + quaternion.BindMethod("Normalize", [] (Nz::LuaState& lua, Nz::Quaterniond& instance, std::size_t /*argumentCount*/) -> int { double length; @@ -608,20 +608,20 @@ namespace Ndk return 2; }); - quaternion.BindStaticMethod("Normalize", [] (Nz::LuaInstance& instance) -> int + quaternion.BindStaticMethod("Normalize", [] (Nz::LuaState& state) -> int { int argIndex = 1; - Nz::Quaterniond quat = instance.Check(&argIndex); + Nz::Quaterniond quat = state.Check(&argIndex); double length; - instance.Push(Nz::Quaterniond::Normalize(quat, &length)); - instance.Push(length); + state.Push(Nz::Quaterniond::Normalize(quat, &length)); + state.Push(length); return 2; }); - quaternion.SetGetter([] (Nz::LuaInstance& lua, Nz::Quaterniond& instance) + quaternion.SetGetter([] (Nz::LuaState& lua, Nz::Quaterniond& instance) { std::size_t length; const char* wxyz = lua.CheckString(2, &length); @@ -651,7 +651,7 @@ namespace Ndk return false; }); - quaternion.SetSetter([] (Nz::LuaInstance& lua, Nz::Quaterniond& instance) + quaternion.SetSetter([] (Nz::LuaState& lua, Nz::Quaterniond& instance) { std::size_t length; const char* wxyz = lua.CheckString(2, &length); @@ -690,7 +690,7 @@ namespace Ndk /*********************************** Nz::Vector2 **********************************/ vector2d.Reset("Vector2"); { - vector2d.SetConstructor([] (Nz::LuaInstance& lua, Nz::Vector2d* vector, std::size_t argumentCount) + vector2d.SetConstructor([] (Nz::LuaState& lua, Nz::Vector2d* vector, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 2U); @@ -720,7 +720,7 @@ namespace Ndk vector2d.BindMethod("__tostring", &Nz::Vector2d::ToString); - vector2d.SetGetter([] (Nz::LuaInstance& lua, Nz::Vector2d& instance) + vector2d.SetGetter([] (Nz::LuaState& lua, Nz::Vector2d& instance) { switch (lua.GetType(2)) { @@ -765,7 +765,7 @@ namespace Ndk return false; }); - vector2d.SetSetter([] (Nz::LuaInstance& lua, Nz::Vector2d& instance) + vector2d.SetSetter([] (Nz::LuaState& lua, Nz::Vector2d& instance) { switch (lua.GetType(2)) { @@ -816,7 +816,7 @@ namespace Ndk /*********************************** Nz::Vector3 **********************************/ vector3d.Reset("Vector3"); { - vector3d.SetConstructor([] (Nz::LuaInstance& lua, Nz::Vector3d* vector, std::size_t argumentCount) + vector3d.SetConstructor([] (Nz::LuaState& lua, Nz::Vector3d* vector, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 3U); @@ -860,7 +860,7 @@ namespace Ndk vector3d.BindMethod("__tostring", &Nz::Vector3d::ToString); - vector3d.SetGetter([] (Nz::LuaInstance& lua, Nz::Vector3d& instance) + vector3d.SetGetter([] (Nz::LuaState& lua, Nz::Vector3d& instance) { switch (lua.GetType(2)) { @@ -909,7 +909,7 @@ namespace Ndk return false; }); - vector3d.SetSetter([] (Nz::LuaInstance& lua, Nz::Vector3d& instance) + vector3d.SetSetter([] (Nz::LuaState& lua, Nz::Vector3d& instance) { switch (lua.GetType(2)) { @@ -967,20 +967,20 @@ namespace Ndk * * \param instance Lua instance that will interact with the Math classes */ - void LuaBinding_Math::Register(Nz::LuaInstance& instance) + void LuaBinding_Math::Register(Nz::LuaState& state) { - eulerAngles.Register(instance); - matrix4d.Register(instance); - quaternion.Register(instance); - rect.Register(instance); - vector2d.Register(instance); - vector3d.Register(instance); + eulerAngles.Register(state); + matrix4d.Register(state); + quaternion.Register(state); + rect.Register(state); + vector2d.Register(state); + vector3d.Register(state); - quaternion.PushGlobalTable(instance); + quaternion.PushGlobalTable(state); { - instance.PushField("Identity", Nz::Quaterniond::Identity()); - instance.PushField("Zero", Nz::Quaterniond::Zero()); + state.PushField("Identity", Nz::Quaterniond::Identity()); + state.PushField("Zero", Nz::Quaterniond::Zero()); } - instance.Pop(); + state.Pop(); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Network.cpp b/SDK/src/NDK/Lua/LuaBinding_Network.cpp index a47cdbfb6..c54ef89a0 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Network.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Network.cpp @@ -28,7 +28,7 @@ namespace Ndk /*********************************** Nz::IpAddress **********************************/ ipAddress.Reset("IpAddress"); { - ipAddress.SetConstructor([] (Nz::LuaInstance& lua, Nz::IpAddress* instance, std::size_t argumentCount) + ipAddress.SetConstructor([] (Nz::LuaState& lua, Nz::IpAddress* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 9U); @@ -85,59 +85,59 @@ namespace Ndk ipAddress.BindMethod("ToUInt32", &Nz::IpAddress::ToUInt32); ipAddress.BindMethod("__tostring", &Nz::IpAddress::ToString); - ipAddress.BindStaticMethod("ResolveAddress", [] (Nz::LuaInstance& instance) -> int + ipAddress.BindStaticMethod("ResolveAddress", [] (Nz::LuaState& state) -> int { Nz::String service; Nz::ResolveError error = Nz::ResolveError_Unknown; int argIndex = 2; - Nz::String hostName = Nz::IpAddress::ResolveAddress(instance.Check(&argIndex), &service, &error); + Nz::String hostName = Nz::IpAddress::ResolveAddress(state.Check(&argIndex), &service, &error); if (error == Nz::ResolveError_NoError) { - instance.Push(hostName); - instance.Push(service); + state.Push(hostName); + state.Push(service); return 2; } else { - instance.PushBoolean(false); - instance.Push(error); + state.PushBoolean(false); + state.Push(error); return 2; } }); - ipAddress.BindStaticMethod("ResolveHostname", [] (Nz::LuaInstance& instance) -> int + ipAddress.BindStaticMethod("ResolveHostname", [] (Nz::LuaState& state) -> int { Nz::ResolveError error = Nz::ResolveError_Unknown; int argIndex = 2; - Nz::NetProtocol protocol = instance.Check(&argIndex); - Nz::String hostname = instance.Check(&argIndex); - Nz::String service = instance.Check(&argIndex, "http"); + Nz::NetProtocol protocol = state.Check(&argIndex); + Nz::String hostname = state.Check(&argIndex); + Nz::String service = state.Check(&argIndex, "http"); std::vector addresses = Nz::IpAddress::ResolveHostname(protocol, hostname, service, &error); if (error == Nz::ResolveError_NoError) { int index = 1; - instance.PushTable(addresses.size()); + state.PushTable(addresses.size()); for (Nz::HostnameInfo& info : addresses) { - instance.PushInteger(index++); - instance.PushTable(0, 4); - instance.PushField("Address", std::move(info.address)); - instance.PushField("CanonicalName", std::move(info.canonicalName)); - instance.PushField("Protocol", std::move(info.protocol)); - instance.PushField("SocketType", std::move(info.socketType)); - instance.SetTable(); + state.PushInteger(index++); + state.PushTable(0, 4); + state.PushField("Address", std::move(info.address)); + state.PushField("CanonicalName", std::move(info.canonicalName)); + state.PushField("Protocol", std::move(info.protocol)); + state.PushField("SocketType", std::move(info.socketType)); + state.SetTable(); } return 1; } else { - instance.PushBoolean(false); - instance.Push(error); + state.PushBoolean(false); + state.Push(error); return 2; } }); @@ -156,22 +156,22 @@ namespace Ndk udpSocket.BindMethod("IsBroadcastingEnabled", &Nz::UdpSocket::IsBroadcastingEnabled); udpSocket.BindMethod("QueryMaxDatagramSize", &Nz::UdpSocket::QueryMaxDatagramSize); - udpSocket.BindMethod("Bind", [](Nz::LuaInstance& lua, Nz::UdpSocket& instance, std::size_t /*argumentCount*/) -> int + udpSocket.BindMethod("Bind", [](Nz::LuaState& lua, Nz::UdpSocket& socket, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "IpAddress")) - return lua.Push(instance.Bind(*static_cast(lua.ToUserdata(argIndex)))); + return lua.Push(socket.Bind(*static_cast(lua.ToUserdata(argIndex)))); else - return lua.Push(instance.Bind(lua.Check(&argIndex))); + return lua.Push(socket.Bind(lua.Check(&argIndex))); }); - udpSocket.BindMethod("Receive", [](Nz::LuaInstance& lua, Nz::UdpSocket& instance, std::size_t /*argumentCount*/) -> int + udpSocket.BindMethod("Receive", [](Nz::LuaState& lua, Nz::UdpSocket& socket, std::size_t /*argumentCount*/) -> int { Nz::IpAddress from; std::array buffer; std::size_t received; - if (instance.Receive(buffer.data(), buffer.size(), &from, &received)) + if (socket.Receive(buffer.data(), buffer.size(), &from, &received)) { lua.PushBoolean(true); lua.PushString(from.ToString()); @@ -183,7 +183,7 @@ namespace Ndk return 1; }); - udpSocket.BindMethod("Send", [](Nz::LuaInstance& lua, Nz::UdpSocket& instance, std::size_t /*argumentCount*/) -> int + udpSocket.BindMethod("Send", [](Nz::LuaState& lua, Nz::UdpSocket& socket, std::size_t /*argumentCount*/) -> int { int argIndex = 2; Nz::String to = lua.Check(&argIndex); @@ -193,7 +193,7 @@ namespace Ndk std::size_t sent; bool ret; - if ((ret = instance.Send(Nz::IpAddress(to), buffer, bufferLength, &sent)) != true) + if ((ret = socket.Send(Nz::IpAddress(to), buffer, bufferLength, &sent)) != true) sent = 0; return lua.Push(std::make_pair(ret, sent)); @@ -206,108 +206,108 @@ namespace Ndk * * \param instance Lua instance that will interact with the Network classes */ - void LuaBinding_Network::Register(Nz::LuaInstance& instance) + void LuaBinding_Network::Register(Nz::LuaState& state) { // Classes - abstractSocket.Register(instance); - ipAddress.Register(instance); - udpSocket.Register(instance); + abstractSocket.Register(state); + ipAddress.Register(state); + udpSocket.Register(state); // Enums // Nz::NetProtocol static_assert(Nz::NetProtocol_Max + 1 == 4, "Nz::NetProtocol has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 4); + state.PushTable(0, 4); { - instance.PushField("Any", Nz::NetProtocol_Any); - instance.PushField("IPv4", Nz::NetProtocol_IPv4); - instance.PushField("IPv6", Nz::NetProtocol_IPv6); - instance.PushField("Unknown", Nz::NetProtocol_Unknown); + state.PushField("Any", Nz::NetProtocol_Any); + state.PushField("IPv4", Nz::NetProtocol_IPv4); + state.PushField("IPv6", Nz::NetProtocol_IPv6); + state.PushField("Unknown", Nz::NetProtocol_Unknown); } - instance.SetGlobal("NetProtocol"); + state.SetGlobal("NetProtocol"); // Nz::PacketPriority static_assert(Nz::PacketPriority_Max + 1 == 4, "Nz::PacketPriority has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 6); + state.PushTable(0, 6); { - instance.PushField("High", Nz::PacketPriority_High); - instance.PushField("Highest", Nz::PacketPriority_Highest); - instance.PushField("Immediate", Nz::PacketPriority_Immediate); - instance.PushField("Medium", Nz::PacketPriority_Medium); - instance.PushField("Low", Nz::PacketPriority_Low); - instance.PushField("Lowest", Nz::PacketPriority_Lowest); + state.PushField("High", Nz::PacketPriority_High); + state.PushField("Highest", Nz::PacketPriority_Highest); + state.PushField("Immediate", Nz::PacketPriority_Immediate); + state.PushField("Medium", Nz::PacketPriority_Medium); + state.PushField("Low", Nz::PacketPriority_Low); + state.PushField("Lowest", Nz::PacketPriority_Lowest); } - instance.SetGlobal("PacketPriority"); + state.SetGlobal("PacketPriority"); // Nz::PacketReliability static_assert(Nz::PacketReliability_Max + 1 == 3, "Nz::PacketReliability has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 3); + state.PushTable(0, 3); { - instance.PushField("Reliable", Nz::PacketReliability_Reliable); - instance.PushField("ReliableOrdered", Nz::PacketReliability_ReliableOrdered); - instance.PushField("Unreliable", Nz::PacketReliability_Unreliable); + state.PushField("Reliable", Nz::PacketReliability_Reliable); + state.PushField("ReliableOrdered", Nz::PacketReliability_ReliableOrdered); + state.PushField("Unreliable", Nz::PacketReliability_Unreliable); } - instance.SetGlobal("PacketReliability"); + state.SetGlobal("PacketReliability"); // Nz::ResolveError static_assert(Nz::ResolveError_Max + 1 == 9, "Nz::ResolveError has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 9); + state.PushTable(0, 9); { - instance.PushField("Internal", Nz::ResolveError_Internal); - instance.PushField("ResourceError", Nz::ResolveError_ResourceError); - instance.PushField("NoError", Nz::ResolveError_NoError); - instance.PushField("NonRecoverable", Nz::ResolveError_NonRecoverable); - instance.PushField("NotFound", Nz::ResolveError_NotFound); - instance.PushField("NotInitialized", Nz::ResolveError_NotInitialized); - instance.PushField("ProtocolNotSupported", Nz::ResolveError_ProtocolNotSupported); - instance.PushField("TemporaryFailure", Nz::ResolveError_TemporaryFailure); - instance.PushField("Unknown", Nz::ResolveError_Unknown); + state.PushField("Internal", Nz::ResolveError_Internal); + state.PushField("ResourceError", Nz::ResolveError_ResourceError); + state.PushField("NoError", Nz::ResolveError_NoError); + state.PushField("NonRecoverable", Nz::ResolveError_NonRecoverable); + state.PushField("NotFound", Nz::ResolveError_NotFound); + state.PushField("NotInitialized", Nz::ResolveError_NotInitialized); + state.PushField("ProtocolNotSupported", Nz::ResolveError_ProtocolNotSupported); + state.PushField("TemporaryFailure", Nz::ResolveError_TemporaryFailure); + state.PushField("Unknown", Nz::ResolveError_Unknown); } - instance.SetGlobal("ResolveError"); + state.SetGlobal("ResolveError"); // Nz::SocketError static_assert(Nz::SocketError_Max + 1 == 15, "Nz::ResolveError has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 15); + state.PushTable(0, 15); { - instance.PushField("AddressNotAvailable", Nz::SocketError_AddressNotAvailable); - instance.PushField("ConnectionClosed", Nz::SocketError_ConnectionClosed); - instance.PushField("ConnectionRefused", Nz::SocketError_ConnectionRefused); - instance.PushField("DatagramSize", Nz::SocketError_DatagramSize); - instance.PushField("Internal", Nz::SocketError_Internal); - instance.PushField("Packet", Nz::SocketError_Packet); - instance.PushField("NetworkError", Nz::SocketError_NetworkError); - instance.PushField("NoError", Nz::SocketError_NoError); - instance.PushField("NotInitialized", Nz::SocketError_NotInitialized); - instance.PushField("NotSupported", Nz::SocketError_NotSupported); - instance.PushField("ResolveError", Nz::SocketError_ResolveError); - instance.PushField("ResourceError", Nz::SocketError_ResourceError); - instance.PushField("TimedOut", Nz::SocketError_TimedOut); - instance.PushField("Unknown", Nz::SocketError_Unknown); - instance.PushField("UnreachableHost", Nz::SocketError_UnreachableHost); + state.PushField("AddressNotAvailable", Nz::SocketError_AddressNotAvailable); + state.PushField("ConnectionClosed", Nz::SocketError_ConnectionClosed); + state.PushField("ConnectionRefused", Nz::SocketError_ConnectionRefused); + state.PushField("DatagramSize", Nz::SocketError_DatagramSize); + state.PushField("Internal", Nz::SocketError_Internal); + state.PushField("Packet", Nz::SocketError_Packet); + state.PushField("NetworkError", Nz::SocketError_NetworkError); + state.PushField("NoError", Nz::SocketError_NoError); + state.PushField("NotInitialized", Nz::SocketError_NotInitialized); + state.PushField("NotSupported", Nz::SocketError_NotSupported); + state.PushField("ResolveError", Nz::SocketError_ResolveError); + state.PushField("ResourceError", Nz::SocketError_ResourceError); + state.PushField("TimedOut", Nz::SocketError_TimedOut); + state.PushField("Unknown", Nz::SocketError_Unknown); + state.PushField("UnreachableHost", Nz::SocketError_UnreachableHost); } - instance.SetGlobal("SocketError"); + state.SetGlobal("SocketError"); // Nz::SocketState static_assert(Nz::SocketState_Max + 1 == 5, "Nz::SocketState has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 5); + state.PushTable(0, 5); { - instance.PushField("Bound", Nz::SocketState_Bound); - instance.PushField("Connecting", Nz::SocketState_Connecting); - instance.PushField("Connected", Nz::SocketState_Connected); - instance.PushField("NotConnected", Nz::SocketState_NotConnected); - instance.PushField("Resolving", Nz::SocketState_Resolving); + state.PushField("Bound", Nz::SocketState_Bound); + state.PushField("Connecting", Nz::SocketState_Connecting); + state.PushField("Connected", Nz::SocketState_Connected); + state.PushField("NotConnected", Nz::SocketState_NotConnected); + state.PushField("Resolving", Nz::SocketState_Resolving); } - instance.SetGlobal("SocketState"); + state.SetGlobal("SocketState"); // Nz::SocketType static_assert(Nz::SocketType_Max + 1 == 4, "Nz::SocketState has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 4); + state.PushTable(0, 4); { - instance.PushField("Raw", Nz::SocketType_Raw); - instance.PushField("TCP", Nz::SocketType_TCP); - instance.PushField("UDP", Nz::SocketType_UDP); - instance.PushField("Unknown", Nz::SocketType_Unknown); + state.PushField("Raw", Nz::SocketType_Raw); + state.PushField("TCP", Nz::SocketType_TCP); + state.PushField("UDP", Nz::SocketType_UDP); + state.PushField("Unknown", Nz::SocketType_Unknown); } - instance.SetGlobal("SocketType"); + state.SetGlobal("SocketType"); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Renderer.cpp b/SDK/src/NDK/Lua/LuaBinding_Renderer.cpp index 00088ecb9..064d21cfe 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Renderer.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Renderer.cpp @@ -27,7 +27,7 @@ namespace Ndk return reinterpret_cast(textureRef); //TODO: Make a ObjectRefCast }); - texture.SetConstructor([] (Nz::LuaInstance& /*lua*/, Nz::TextureRef* instance, std::size_t /*argumentCount*/) + texture.SetConstructor([] (Nz::LuaState& /*lua*/, Nz::TextureRef* instance, std::size_t /*argumentCount*/) { Nz::PlacementNew(instance, Nz::Texture::New()); return true; @@ -101,10 +101,10 @@ namespace Ndk * * \param instance Lua instance that will interact with the Renderer classes */ - void LuaBinding_Renderer::Register(Nz::LuaInstance& instance) + void LuaBinding_Renderer::Register(Nz::LuaState& state) { - texture.Register(instance); - textureLibrary.Register(instance); - textureManager.Register(instance); + texture.Register(state); + textureLibrary.Register(state); + textureManager.Register(state); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_SDK.cpp b/SDK/src/NDK/Lua/LuaBinding_SDK.cpp index 4d8408282..a4ae0b792 100644 --- a/SDK/src/NDK/Lua/LuaBinding_SDK.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_SDK.cpp @@ -40,7 +40,7 @@ namespace Ndk application.BindMethod("IsFPSCounterEnabled", &Application::IsFPSCounterEnabled); #endif - application.BindMethod("AddWorld", [] (Nz::LuaInstance& lua, Application* instance, std::size_t /*argumentCount*/) -> int + application.BindMethod("AddWorld", [] (Nz::LuaState& lua, Application* instance, std::size_t /*argumentCount*/) -> int { lua.Push(instance->AddWorld().CreateHandle()); return 1; @@ -94,23 +94,23 @@ namespace Ndk entity.BindMethod("RemoveAllComponents", &Entity::RemoveAllComponents); entity.BindMethod("__tostring", &EntityHandle::ToString); - entity.BindMethod("AddComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle, std::size_t /*argumentCount*/) -> int + entity.BindMethod("AddComponent", [this] (Nz::LuaState& state, EntityHandle& handle, std::size_t /*argumentCount*/) -> int { - LuaBinding::ComponentBinding* bindingComponent = m_binding.QueryComponentIndex(instance); + LuaBinding::ComponentBinding* bindingComponent = m_binding.QueryComponentIndex(state); - return bindingComponent->adder(instance, handle); + return bindingComponent->adder(state, handle); }); - entity.BindMethod("GetComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle, std::size_t /*argumentCount*/) -> int + entity.BindMethod("GetComponent", [this] (Nz::LuaState& state, EntityHandle& handle, std::size_t /*argumentCount*/) -> int { - LuaBinding::ComponentBinding* bindingComponent = m_binding.QueryComponentIndex(instance); + LuaBinding::ComponentBinding* bindingComponent = m_binding.QueryComponentIndex(state); - return bindingComponent->getter(instance, handle->GetComponent(bindingComponent->index)); + return bindingComponent->getter(state, handle->GetComponent(bindingComponent->index)); }); - entity.BindMethod("RemoveComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle, std::size_t /*argumentCount*/) -> int + entity.BindMethod("RemoveComponent", [this] (Nz::LuaState& state, EntityHandle& handle, std::size_t /*argumentCount*/) -> int { - LuaBinding::ComponentBinding* bindingComponent = m_binding.QueryComponentIndex(instance); + LuaBinding::ComponentBinding* bindingComponent = m_binding.QueryComponentIndex(state); handle->RemoveComponent(bindingComponent->index); return 0; @@ -129,7 +129,7 @@ namespace Ndk /*********************************** Ndk::VelocityComponent **********************************/ velocityComponent.Reset("VelocityComponent"); { - velocityComponent.SetGetter([] (Nz::LuaInstance& lua, VelocityComponentHandle& instance) + velocityComponent.SetGetter([] (Nz::LuaState& lua, VelocityComponentHandle& instance) { std::size_t length; const char* member = lua.CheckString(2, &length); @@ -143,7 +143,7 @@ namespace Ndk return false; }); - velocityComponent.SetSetter([] (Nz::LuaInstance& lua, VelocityComponentHandle& instance) + velocityComponent.SetSetter([] (Nz::LuaState& lua, VelocityComponentHandle& instance) { std::size_t length; const char* member = lua.CheckString(2, &length); @@ -193,7 +193,7 @@ namespace Ndk /*********************************** Ndk::GraphicsComponent **********************************/ graphicsComponent.Reset("GraphicsComponent"); { - graphicsComponent.BindMethod("Attach", [] (Nz::LuaInstance& lua, Ndk::GraphicsComponent* instance, std::size_t argumentCount) -> int + graphicsComponent.BindMethod("Attach", [] (Nz::LuaState& lua, Ndk::GraphicsComponent* instance, std::size_t argumentCount) -> int { /* void Attach(Nz::InstancedRenderableRef renderable, int renderOrder = 0); @@ -267,19 +267,19 @@ namespace Ndk * * \param instance Lua instance that will interact with the SDK classes */ - void LuaBinding_SDK::Register(Nz::LuaInstance& instance) + void LuaBinding_SDK::Register(Nz::LuaState& state) { // Classes - application.Register(instance); - entity.Register(instance); - nodeComponent.Register(instance); - velocityComponent.Register(instance); - world.Register(instance); + application.Register(state); + entity.Register(state); + nodeComponent.Register(state); + velocityComponent.Register(state); + world.Register(state); #ifndef NDK_SERVER - cameraComponent.Register(instance); - console.Register(instance); - graphicsComponent.Register(instance); + cameraComponent.Register(state); + console.Register(state); + graphicsComponent.Register(state); #endif // Enums @@ -292,23 +292,23 @@ namespace Ndk * \param instance Lua instance that will interact with the component * \param argIndex Index of the component */ - LuaBinding::ComponentBinding* LuaBinding::QueryComponentIndex(Nz::LuaInstance& instance, int argIndex) + LuaBinding::ComponentBinding* LuaBinding::QueryComponentIndex(Nz::LuaState& state, int argIndex) { - switch (instance.GetType(argIndex)) + switch (state.GetType(argIndex)) { case Nz::LuaType_Number: { - ComponentIndex componentIndex = instance.Check(&argIndex); + ComponentIndex componentIndex = state.Check(&argIndex); if (componentIndex > m_componentBinding.size()) { - instance.Error("Invalid component index"); + state.Error("Invalid component index"); return nullptr; } ComponentBinding& binding = m_componentBinding[componentIndex]; if (binding.name.IsEmpty()) { - instance.Error("Invalid component index"); + state.Error("Invalid component index"); return nullptr; } @@ -317,11 +317,11 @@ namespace Ndk case Nz::LuaType_String: { - const char* key = instance.CheckString(argIndex); + const char* key = state.CheckString(argIndex); auto it = m_componentBindingByName.find(key); if (it == m_componentBindingByName.end()) { - instance.Error("Invalid component name"); + state.Error("Invalid component name"); return nullptr; } @@ -332,7 +332,7 @@ namespace Ndk break; } - instance.Error("Invalid component index at #" + Nz::String::Number(argIndex)); + state.Error("Invalid component index at #" + Nz::String::Number(argIndex)); return nullptr; } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Utility.cpp b/SDK/src/NDK/Lua/LuaBinding_Utility.cpp index 173d6c3c5..6d7baf588 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Utility.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Utility.cpp @@ -29,7 +29,7 @@ namespace Ndk abstractImage.BindMethod("IsCompressed", &Nz::AbstractImage::IsCompressed); abstractImage.BindMethod("IsCubemap", &Nz::AbstractImage::IsCubemap); - abstractImage.BindMethod("GetMemoryUsage", [] (Nz::LuaInstance& lua, Nz::AbstractImage* instance, std::size_t argumentCount) -> int + abstractImage.BindMethod("GetMemoryUsage", [] (Nz::LuaState& lua, Nz::AbstractImage* instance, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 1U); switch (argCount) @@ -50,7 +50,7 @@ namespace Ndk return 0; }); - abstractImage.BindMethod("Update", [] (Nz::LuaInstance& lua, Nz::AbstractImage* instance, std::size_t argumentCount) -> int + abstractImage.BindMethod("Update", [] (Nz::LuaState& lua, Nz::AbstractImage* instance, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 6U); int argIndex = 2; @@ -100,7 +100,7 @@ namespace Ndk /*********************************** Nz::Font **********************************/ font.Reset("Font"); { - font.SetConstructor([] (Nz::LuaInstance& /*lua*/, Nz::FontRef* instance, std::size_t /*argumentCount*/) + font.SetConstructor([] (Nz::LuaState& /*lua*/, Nz::FontRef* instance, std::size_t /*argumentCount*/) { Nz::PlacementNew(instance, Nz::Font::New()); return true; @@ -112,7 +112,7 @@ namespace Ndk font.BindMethod("Destroy", &Nz::Font::Destroy); - font.BindMethod("GetCachedGlyphCount", [] (Nz::LuaInstance& lua, Nz::FontRef& instance, std::size_t argumentCount) -> int + font.BindMethod("GetCachedGlyphCount", [] (Nz::LuaState& lua, Nz::FontRef& instance, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 2U); @@ -216,29 +216,29 @@ namespace Ndk node.BindMethod("SetPosition", (void(Nz::Node::*)(const Nz::Vector3f&, Nz::CoordSys)) &Nz::Node::SetPosition, Nz::CoordSys_Local); node.BindMethod("SetRotation", (void(Nz::Node::*)(const Nz::Quaternionf&, Nz::CoordSys)) &Nz::Node::SetRotation, Nz::CoordSys_Local); - node.BindMethod("Move", [] (Nz::LuaInstance& lua, Nz::Node& instance, std::size_t /*argumentCount*/) -> int + node.BindMethod("Move", [] (Nz::LuaState& lua, Nz::Node& node, std::size_t /*argumentCount*/) -> int { int argIndex = 2; Nz::Vector3f offset = lua.Check(&argIndex); Nz::CoordSys coordSys = lua.Check(&argIndex, Nz::CoordSys_Local); - instance.Move(offset, coordSys); + node.Move(offset, coordSys); return 0; }); - node.BindMethod("Rotate", [] (Nz::LuaInstance& lua, Nz::Node& instance, std::size_t /*argumentCount*/) -> int + node.BindMethod("Rotate", [] (Nz::LuaState& lua, Nz::Node& node, std::size_t /*argumentCount*/) -> int { int argIndex = 2; Nz::Quaternionf rotation = lua.Check(&argIndex); Nz::CoordSys coordSys = lua.Check(&argIndex, Nz::CoordSys_Local); - instance.Rotate(rotation, coordSys); + node.Rotate(rotation, coordSys); return 0; }); - node.BindMethod("Scale", [] (Nz::LuaInstance& lua, Nz::Node& instance, std::size_t argumentCount) -> int + node.BindMethod("Scale", [] (Nz::LuaState& lua, Nz::Node& node, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 4U); @@ -248,15 +248,15 @@ namespace Ndk case 1: { if (lua.IsOfType(argIndex, Nz::LuaType_Number)) - instance.Scale(lua.Check(&argIndex)); + node.Scale(lua.Check(&argIndex)); else - instance.Scale(lua.Check(&argIndex)); + node.Scale(lua.Check(&argIndex)); return 0; } case 3: - instance.Scale(lua.Check(&argIndex)); + node.Scale(lua.Check(&argIndex)); return 0; } @@ -264,7 +264,7 @@ namespace Ndk return 0; }); - node.BindMethod("SetScale", [] (Nz::LuaInstance& lua, Nz::Node& instance, std::size_t argumentCount) -> int + node.BindMethod("SetScale", [] (Nz::LuaState& lua, Nz::Node& node, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 4U); @@ -278,10 +278,10 @@ namespace Ndk { float scale = lua.Check(&argIndex); Nz::CoordSys coordSys = lua.Check(&argIndex, Nz::CoordSys_Local); - instance.SetScale(scale, coordSys); + node.SetScale(scale, coordSys); } else - instance.SetScale(lua.Check(&argIndex)); + node.SetScale(lua.Check(&argIndex)); return 0; } @@ -292,7 +292,7 @@ namespace Ndk Nz::Vector3f scale = lua.Check(&argIndex); Nz::CoordSys coordSys = lua.Check(&argIndex, Nz::CoordSys_Local); - instance.SetScale(scale, coordSys); + node.SetScale(scale, coordSys); return 0; } } @@ -301,7 +301,7 @@ namespace Ndk return 0; }); - node.BindMethod("SetInitialScale", [] (Nz::LuaInstance& lua, Nz::Node& instance, std::size_t argumentCount) -> int + node.BindMethod("SetInitialScale", [] (Nz::LuaState& lua, Nz::Node& node, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 4U); @@ -311,16 +311,16 @@ namespace Ndk case 1: { if (lua.IsOfType(argIndex, Nz::LuaType_Number)) - instance.SetInitialScale(lua.Check(&argIndex)); + node.SetInitialScale(lua.Check(&argIndex)); else - instance.SetInitialScale(lua.Check(&argIndex)); + node.SetInitialScale(lua.Check(&argIndex)); return 0; } case 2: case 3: - instance.SetInitialScale(lua.Check(&argIndex)); + node.SetInitialScale(lua.Check(&argIndex)); return 0; } @@ -335,112 +335,110 @@ namespace Ndk * * \param instance Lua instance that will interact with the Utility classes */ - void LuaBinding_Utility::Register(Nz::LuaInstance& instance) + void LuaBinding_Utility::Register(Nz::LuaState& state) { - abstractImage.Register(instance); - font.Register(instance); - keyboard.Register(instance); - node.Register(instance); + abstractImage.Register(state); + font.Register(state); + keyboard.Register(state); + node.Register(state); - keyboard.PushGlobalTable(instance); + keyboard.PushGlobalTable(state); { static_assert(Nz::Keyboard::Count == 121, "Nz::Keyboard::Key has been updated but change was not reflected to Lua binding"); - instance.PushField("Undefined", Nz::Keyboard::Undefined); + state.PushField("Undefined", Nz::Keyboard::Undefined); // A-Z for (std::size_t i = 0; i < 26; ++i) - instance.PushField(Nz::String('A' + char(i)), Nz::Keyboard::A + i); + state.PushField(Nz::String('A' + char(i)), Nz::Keyboard::A + i); // Numerical for (std::size_t i = 0; i < 10; ++i) { - instance.PushField("Num" + Nz::String::Number(i), Nz::Keyboard::Num0 + i); - instance.PushField("Numpad" + Nz::String::Number(i), Nz::Keyboard::Numpad0 + i); + state.PushField("Num" + Nz::String::Number(i), Nz::Keyboard::Num0 + i); + state.PushField("Numpad" + Nz::String::Number(i), Nz::Keyboard::Numpad0 + i); } // F1-F15 for (std::size_t i = 0; i < 15; ++i) - instance.PushField('F' + Nz::String::Number(i+1), Nz::Keyboard::F1 + i); + state.PushField('F' + Nz::String::Number(i+1), Nz::Keyboard::F1 + i); // And all the others... - instance.PushField("Down", Nz::Keyboard::Down); - instance.PushField("Left", Nz::Keyboard::Left); - instance.PushField("Right", Nz::Keyboard::Right); - instance.PushField("Up", Nz::Keyboard::Up); + state.PushField("Down", Nz::Keyboard::Down); + state.PushField("Left", Nz::Keyboard::Left); + state.PushField("Right", Nz::Keyboard::Right); + state.PushField("Up", Nz::Keyboard::Up); - instance.PushField("Add", Nz::Keyboard::Add); - instance.PushField("Decimal", Nz::Keyboard::Decimal); - instance.PushField("Divide", Nz::Keyboard::Divide); - instance.PushField("Multiply", Nz::Keyboard::Multiply); - instance.PushField("Subtract", Nz::Keyboard::Subtract); + state.PushField("Add", Nz::Keyboard::Add); + state.PushField("Decimal", Nz::Keyboard::Decimal); + state.PushField("Divide", Nz::Keyboard::Divide); + state.PushField("Multiply", Nz::Keyboard::Multiply); + state.PushField("Subtract", Nz::Keyboard::Subtract); - instance.PushField("Backslash", Nz::Keyboard::Backslash); - instance.PushField("Backspace", Nz::Keyboard::Backspace); - instance.PushField("Clear", Nz::Keyboard::Clear); - instance.PushField("Comma", Nz::Keyboard::Comma); - instance.PushField("Dash", Nz::Keyboard::Dash); - instance.PushField("Delete", Nz::Keyboard::Delete); - instance.PushField("End", Nz::Keyboard::End); - instance.PushField("Equal", Nz::Keyboard::Equal); - instance.PushField("Escape", Nz::Keyboard::Escape); - instance.PushField("Home", Nz::Keyboard::Home); - instance.PushField("Insert", Nz::Keyboard::Insert); - instance.PushField("LAlt", Nz::Keyboard::LAlt); - instance.PushField("LBracket", Nz::Keyboard::LBracket); - instance.PushField("LControl", Nz::Keyboard::LControl); - instance.PushField("LShift", Nz::Keyboard::LShift); - instance.PushField("LSystem", Nz::Keyboard::LSystem); - instance.PushField("PageDown", Nz::Keyboard::PageDown); - instance.PushField("PageUp", Nz::Keyboard::PageUp); - instance.PushField("Pause", Nz::Keyboard::Pause); - instance.PushField("Period", Nz::Keyboard::Period); - instance.PushField("Print", Nz::Keyboard::Print); - instance.PushField("PrintScreen", Nz::Keyboard::PrintScreen); - instance.PushField("Quote", Nz::Keyboard::Quote); - instance.PushField("RAlt", Nz::Keyboard::RAlt); - instance.PushField("RBracket", Nz::Keyboard::RBracket); - instance.PushField("RControl", Nz::Keyboard::RControl); - instance.PushField("Return", Nz::Keyboard::Return); - instance.PushField("RShift", Nz::Keyboard::RShift); - instance.PushField("RSystem", Nz::Keyboard::RSystem); - instance.PushField("Semicolon", Nz::Keyboard::Semicolon); - instance.PushField("Slash", Nz::Keyboard::Slash); - instance.PushField("Space", Nz::Keyboard::Space); - instance.PushField("Tab", Nz::Keyboard::Tab); - instance.PushField("Tilde", Nz::Keyboard::Tilde); - instance.PushField("Browser_Back", Nz::Keyboard::Browser_Back); - instance.PushField("Browser_Favorites", Nz::Keyboard::Browser_Favorites); - instance.PushField("Browser_Forward", Nz::Keyboard::Browser_Forward); - instance.PushField("Browser_Home", Nz::Keyboard::Browser_Home); - instance.PushField("Browser_Refresh", Nz::Keyboard::Browser_Refresh); - instance.PushField("Browser_Search", Nz::Keyboard::Browser_Search); - instance.PushField("Browser_Stop", Nz::Keyboard::Browser_Stop); - instance.PushField("Media_Next", Nz::Keyboard::Media_Next); - instance.PushField("Media_Play", Nz::Keyboard::Media_Play); - instance.PushField("Media_Previous", Nz::Keyboard::Media_Previous); - instance.PushField("Media_Stop", Nz::Keyboard::Media_Stop); - instance.PushField("Volume_Down", Nz::Keyboard::Volume_Down); - instance.PushField("Volume_Mute", Nz::Keyboard::Volume_Mute); - instance.PushField("Volume_Up", Nz::Keyboard::Volume_Up); - instance.PushField("CapsLock", Nz::Keyboard::CapsLock); - instance.PushField("NumLock", Nz::Keyboard::NumLock); - instance.PushField("ScrollLock", Nz::Keyboard::ScrollLock); + state.PushField("Backslash", Nz::Keyboard::Backslash); + state.PushField("Backspace", Nz::Keyboard::Backspace); + state.PushField("Clear", Nz::Keyboard::Clear); + state.PushField("Comma", Nz::Keyboard::Comma); + state.PushField("Dash", Nz::Keyboard::Dash); + state.PushField("Delete", Nz::Keyboard::Delete); + state.PushField("End", Nz::Keyboard::End); + state.PushField("Equal", Nz::Keyboard::Equal); + state.PushField("Escape", Nz::Keyboard::Escape); + state.PushField("Home", Nz::Keyboard::Home); + state.PushField("Insert", Nz::Keyboard::Insert); + state.PushField("LAlt", Nz::Keyboard::LAlt); + state.PushField("LBracket", Nz::Keyboard::LBracket); + state.PushField("LControl", Nz::Keyboard::LControl); + state.PushField("LShift", Nz::Keyboard::LShift); + state.PushField("LSystem", Nz::Keyboard::LSystem); + state.PushField("PageDown", Nz::Keyboard::PageDown); + state.PushField("PageUp", Nz::Keyboard::PageUp); + state.PushField("Pause", Nz::Keyboard::Pause); + state.PushField("Period", Nz::Keyboard::Period); + state.PushField("Print", Nz::Keyboard::Print); + state.PushField("PrintScreen", Nz::Keyboard::PrintScreen); + state.PushField("Quote", Nz::Keyboard::Quote); + state.PushField("RAlt", Nz::Keyboard::RAlt); + state.PushField("RBracket", Nz::Keyboard::RBracket); + state.PushField("RControl", Nz::Keyboard::RControl); + state.PushField("Return", Nz::Keyboard::Return); + state.PushField("RShift", Nz::Keyboard::RShift); + state.PushField("RSystem", Nz::Keyboard::RSystem); + state.PushField("Semicolon", Nz::Keyboard::Semicolon); + state.PushField("Slash", Nz::Keyboard::Slash); + state.PushField("Space", Nz::Keyboard::Space); + state.PushField("Tab", Nz::Keyboard::Tab); + state.PushField("Tilde", Nz::Keyboard::Tilde); + state.PushField("Browser_Back", Nz::Keyboard::Browser_Back); + state.PushField("Browser_Favorites", Nz::Keyboard::Browser_Favorites); + state.PushField("Browser_Forward", Nz::Keyboard::Browser_Forward); + state.PushField("Browser_Home", Nz::Keyboard::Browser_Home); + state.PushField("Browser_Refresh", Nz::Keyboard::Browser_Refresh); + state.PushField("Browser_Search", Nz::Keyboard::Browser_Search); + state.PushField("Browser_Stop", Nz::Keyboard::Browser_Stop); + state.PushField("Media_Next", Nz::Keyboard::Media_Next); + state.PushField("Media_Play", Nz::Keyboard::Media_Play); + state.PushField("Media_Previous", Nz::Keyboard::Media_Previous); + state.PushField("Media_Stop", Nz::Keyboard::Media_Stop); + state.PushField("Volume_Down", Nz::Keyboard::Volume_Down); + state.PushField("Volume_Mute", Nz::Keyboard::Volume_Mute); + state.PushField("Volume_Up", Nz::Keyboard::Volume_Up); + state.PushField("CapsLock", Nz::Keyboard::CapsLock); + state.PushField("NumLock", Nz::Keyboard::NumLock); + state.PushField("ScrollLock", Nz::Keyboard::ScrollLock); } - instance.Pop(); + state.Pop(); static_assert(Nz::WindowStyle_Max + 1 == 6, "Nz::WindowStyle has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, Nz::WindowStyle_Max + 1); + state.PushTable(0, Nz::WindowStyle_Max + 1); { - instance.PushField("None", Nz::WindowStyle_None); - instance.PushField("Fullscreen", Nz::WindowStyle_Fullscreen); - instance.PushField("Closable", Nz::WindowStyle_Closable); - instance.PushField("Resizable", Nz::WindowStyle_Resizable); - instance.PushField("Titlebar", Nz::WindowStyle_Titlebar); - instance.PushField("Threaded", Nz::WindowStyle_Threaded); + state.PushField("None", Nz::WindowStyle_None); + state.PushField("Fullscreen", Nz::WindowStyle_Fullscreen); + state.PushField("Closable", Nz::WindowStyle_Closable); + state.PushField("Resizable", Nz::WindowStyle_Resizable); + state.PushField("Titlebar", Nz::WindowStyle_Titlebar); + state.PushField("Threaded", Nz::WindowStyle_Threaded); } - instance.SetGlobal("WindowStyle"); - - + state.SetGlobal("WindowStyle"); } } diff --git a/SDK/src/NDK/LuaAPI.cpp b/SDK/src/NDK/LuaAPI.cpp index a28fbb05f..3a82d2130 100644 --- a/SDK/src/NDK/LuaAPI.cpp +++ b/SDK/src/NDK/LuaAPI.cpp @@ -44,10 +44,10 @@ namespace Ndk * \param instance Lua instance that will interact with the engine & SDK */ - void LuaAPI::RegisterClasses(Nz::LuaInstance& instance) + void LuaAPI::RegisterClasses(Nz::LuaState& state) { Nz::ErrorFlags errFlags(Nz::ErrorFlag_ThrowException, true); - GetBinding()->RegisterClasses(instance); + GetBinding()->RegisterClasses(state); } /*! diff --git a/include/Nazara/Lua/LuaClass.hpp b/include/Nazara/Lua/LuaClass.hpp index 13dcbb828..451f91c08 100644 --- a/include/Nazara/Lua/LuaClass.hpp +++ b/include/Nazara/Lua/LuaClass.hpp @@ -26,13 +26,13 @@ namespace Nz friend class LuaClass; public: - using ClassFunc = std::function; - using ClassIndexFunc = std::function; - using ConstructorFunc = std::function; + using ClassFunc = std::function; + using ClassIndexFunc = std::function; + using ConstructorFunc = std::function; template using ConvertToParent = std::function; - using FinalizerFunc = std::function; - using StaticIndexFunc = std::function; - using StaticFunc = std::function; + using FinalizerFunc = std::function; + using StaticIndexFunc = std::function; + using StaticFunc = std::function; LuaClass() = default; LuaClass(const String& name); @@ -54,9 +54,9 @@ namespace Nz void Reset(); void Reset(const String& name); - void Register(LuaInstance& lua); + void Register(LuaState& state); - void PushGlobalTable(LuaInstance& lua); + void PushGlobalTable(LuaState& state); void SetConstructor(ConstructorFunc constructor); void SetFinalizer(FinalizerFunc finalizer); @@ -69,18 +69,18 @@ namespace Nz template friend struct LuaClassImplFinalizerSetupProxy; - void PushClassInfo(LuaInstance& lua); - void SetupConstructor(LuaInstance& lua); - void SetupDefaultToString(LuaInstance& lua); - void SetupFinalizer(LuaInstance& lua); - void SetupGetter(LuaInstance& lua, LuaCFunction proxy); - void SetupGlobalTable(LuaInstance& lua); - void SetupMetatable(LuaInstance& lua); - void SetupMethod(LuaInstance& lua, LuaCFunction proxy, const String& name, std::size_t methodIndex); - void SetupSetter(LuaInstance& lua, LuaCFunction proxy); + void PushClassInfo(LuaState& state); + void SetupConstructor(LuaState& state); + void SetupDefaultToString(LuaState& state); + void SetupFinalizer(LuaState& state); + void SetupGetter(LuaState& state, LuaCFunction proxy); + void SetupGlobalTable(LuaState& state); + void SetupMetatable(LuaState& state); + void SetupMethod(LuaState& state, LuaCFunction proxy, const String& name, std::size_t methodIndex); + void SetupSetter(LuaState& state, LuaCFunction proxy); - using ParentFunc = std::function; - using InstanceGetter = std::function; + using ParentFunc = std::function; + using InstanceGetter = std::function; struct ClassInfo { @@ -98,17 +98,17 @@ namespace Nz int globalTableRef = -1; }; - static int ConstructorProxy(lua_State* state); - static int FinalizerProxy(lua_State* state); - static int InfoDestructor(lua_State* state); - static void Get(const std::shared_ptr& info, LuaInstance& lua, T* instance); - static int GetterProxy(lua_State* state); - static int MethodProxy(lua_State* state); - static int SetterProxy(lua_State* state); - static int StaticGetterProxy(lua_State* state); - static int StaticMethodProxy(lua_State* state); - static int StaticSetterProxy(lua_State* state); - static int ToStringProxy(lua_State* state); + static int ConstructorProxy(lua_State* internalState); + static int FinalizerProxy(lua_State* internalState); + static int InfoDestructor(lua_State* internalState); + static void Get(const std::shared_ptr& info, LuaState& state, T* instance); + static int GetterProxy(lua_State* internalState); + static int MethodProxy(lua_State* internalState); + static int SetterProxy(lua_State* internalState); + static int StaticGetterProxy(lua_State* internalState); + static int StaticMethodProxy(lua_State* internalState); + static int StaticSetterProxy(lua_State* internalState); + static int ToStringProxy(lua_State* internalState); std::map m_methods; std::map m_staticMethods; diff --git a/include/Nazara/Lua/LuaClass.inl b/include/Nazara/Lua/LuaClass.inl index 94c1f8125..40b7374bc 100644 --- a/include/Nazara/Lua/LuaClass.inl +++ b/include/Nazara/Lua/LuaClass.inl @@ -19,9 +19,9 @@ namespace Nz template inline void LuaClass::BindDefaultConstructor() { - SetConstructor([] (Nz::LuaInstance& lua, T* instance, std::size_t argumentCount) + SetConstructor([] (Nz::LuaState& state, T* instance, std::size_t argumentCount) { - NazaraUnused(lua); + NazaraUnused(state); NazaraUnused(argumentCount); PlacementNew(instance); @@ -47,14 +47,14 @@ namespace Nz std::shared_ptr::ClassInfo>& parentInfo = parent.m_info; - parentInfo->instanceGetters[m_info->name] = [info = m_info, convertFunc] (LuaInstance& lua) -> P* + parentInfo->instanceGetters[m_info->name] = [info = m_info, convertFunc] (LuaState& state) -> P* { - return convertFunc(static_cast(lua.CheckUserdata(1, info->name))); + return convertFunc(static_cast(state.CheckUserdata(1, info->name))); }; - m_info->parentGetters.emplace_back([parentInfo, convertFunc] (LuaInstance& lua, T* instance) + m_info->parentGetters.emplace_back([parentInfo, convertFunc] (LuaState& state, T* instance) { - LuaClass

::Get(parentInfo, lua, convertFunc(instance)); + LuaClass

::Get(parentInfo, state, convertFunc(instance)); }); } @@ -71,30 +71,30 @@ namespace Nz m_info = std::make_shared(); m_info->name = name; - m_info->instanceGetters[m_info->name] = [info = m_info] (LuaInstance& instance) + m_info->instanceGetters[m_info->name] = [info = m_info] (LuaState& state) { - return static_cast(instance.CheckUserdata(1, info->name)); + return static_cast(state.CheckUserdata(1, info->name)); }; } template - void LuaClass::Register(LuaInstance& lua) + void LuaClass::Register(LuaState& state) { - PushClassInfo(lua); + PushClassInfo(state); - // Let's create the metatable which will be associated with every instance. - SetupMetatable(lua); + // Let's create the metatable which will be associated with every state. + SetupMetatable(state); if (m_info->constructor || m_info->staticGetter || m_info->staticSetter || !m_staticMethods.empty()) - SetupGlobalTable(lua); + SetupGlobalTable(state); - lua.Pop(); // Pop our ClassInfo, which is now referenced by all our functions + state.Pop(); // Pop our ClassInfo, which is now referenced by all our functions } template - void LuaClass::PushGlobalTable(LuaInstance& lua) + void LuaClass::PushGlobalTable(LuaState& state) { - lua.PushReference(m_info->globalTableRef); + state.PushReference(m_info->globalTableRef); } template @@ -127,11 +127,11 @@ namespace Nz { typename LuaImplMethodProxy::template Impl handler(std::forward(defArgs)...); - BindMethod(name, [func, handler] (LuaInstance& lua, T& object, std::size_t /*argumentCount*/) -> int + BindMethod(name, [func, handler] (LuaState& state, T& object, std::size_t /*argumentCount*/) -> int { - handler.ProcessArguments(lua); + handler.ProcessArguments(state); - return handler.Invoke(lua, object, func); + return handler.Invoke(state, object, func); }); } @@ -141,11 +141,11 @@ namespace Nz { typename LuaImplMethodProxy::template Impl handler(std::forward(defArgs)...); - BindMethod(name, [func, handler] (LuaInstance& lua, T& object, std::size_t /*argumentCount*/) -> int + BindMethod(name, [func, handler] (LuaState& state, T& object, std::size_t /*argumentCount*/) -> int { - handler.ProcessArguments(lua); + handler.ProcessArguments(state); - return handler.Invoke(lua, object, func); + return handler.Invoke(state, object, func); }); } @@ -155,11 +155,11 @@ namespace Nz { typename LuaImplMethodProxy::template Impl handler(std::forward(defArgs)...); - BindMethod(name, [func, handler] (LuaInstance& lua, T& object, std::size_t /*argumentCount*/) -> int + BindMethod(name, [func, handler] (LuaState& state, T& object, std::size_t /*argumentCount*/) -> int { - handler.ProcessArguments(lua); + handler.ProcessArguments(state); - return handler.Invoke(lua, object, func); + return handler.Invoke(state, object, func); }); } @@ -169,11 +169,11 @@ namespace Nz { typename LuaImplMethodProxy::template Impl handler(std::forward(defArgs)...); - BindMethod(name, [func, handler] (LuaInstance& lua, T& object, std::size_t /*argumentCount*/) -> int + BindMethod(name, [func, handler] (LuaState& state, T& object, std::size_t /*argumentCount*/) -> int { - handler.ProcessArguments(lua); + handler.ProcessArguments(state); - return handler.Invoke(lua, object, func); + return handler.Invoke(state, object, func); }); } @@ -201,11 +201,11 @@ namespace Nz { typename LuaImplFunctionProxy::template Impl handler(std::forward(defArgs)...); - BindStaticMethod(name, [func, handler] (LuaInstance& lua) -> int + BindStaticMethod(name, [func, handler] (LuaState& state) -> int { - handler.ProcessArguments(lua); + handler.ProcessArguments(state); - return handler.Invoke(lua, func); + return handler.Invoke(state, func); }); } @@ -216,37 +216,37 @@ namespace Nz } template - void LuaClass::PushClassInfo(LuaInstance& lua) + void LuaClass::PushClassInfo(LuaState& state) { // Our ClassInfo has to outlive the LuaClass, because we don't want to force the user to keep the LuaClass alive // To do that, each Registration creates a tiny shared_ptr wrapper whose life is directly managed by Lua. // This shared_ptr object gets pushed as a up-value for every proxy function set in the metatable. // This way, there is no way our ClassInfo gets freed before any instance and the global class gets destroyed. - std::shared_ptr* info = static_cast*>(lua.PushUserdata(sizeof(std::shared_ptr))); + std::shared_ptr* info = static_cast*>(state.PushUserdata(sizeof(std::shared_ptr))); PlacementNew(info, m_info); // Setup a tiny metatable to let Lua know how to destroy our ClassInfo - lua.PushTable(0, 1); - lua.PushLightUserdata(info); - lua.PushCFunction(InfoDestructor, 1); - lua.SetField("__gc"); - lua.SetMetatable(-2); + state.PushTable(0, 1); + state.PushLightUserdata(info); + state.PushCFunction(InfoDestructor, 1); + state.SetField("__gc"); + state.SetMetatable(-2); } template - void LuaClass::SetupConstructor(LuaInstance& lua) + void LuaClass::SetupConstructor(LuaState& state) { - lua.PushValue(1); // ClassInfo - lua.PushCFunction(ConstructorProxy, 1); - lua.SetField("__call"); // ClassMeta.__call = ConstructorProxy + state.PushValue(1); // ClassInfo + state.PushCFunction(ConstructorProxy, 1); + state.SetField("__call"); // ClassMeta.__call = ConstructorProxy } template - void LuaClass::SetupDefaultToString(LuaInstance& lua) + void LuaClass::SetupDefaultToString(LuaState& state) { - lua.PushValue(1); // shared_ptr on UserData - lua.PushCFunction(ToStringProxy, 1); - lua.SetField("__tostring"); + state.PushValue(1); // shared_ptr on UserData + state.PushCFunction(ToStringProxy, 1); + state.SetField("__tostring"); } template @@ -255,61 +255,61 @@ namespace Nz template struct LuaClassImplFinalizerSetupProxy { - static void Setup(LuaInstance& lua) + static void Setup(LuaState& state) { - lua.PushValue(1); // ClassInfo - lua.PushCFunction(LuaClass::FinalizerProxy, 1); - lua.SetField("__gc"); + state.PushValue(1); // ClassInfo + state.PushCFunction(LuaClass::FinalizerProxy, 1); + state.SetField("__gc"); } }; template struct LuaClassImplFinalizerSetupProxy { - static void Setup(LuaInstance&) + static void Setup(LuaState&) { } }; template - void LuaClass::SetupFinalizer(LuaInstance& lua) + void LuaClass::SetupFinalizer(LuaState& state) { - LuaClassImplFinalizerSetupProxy::value>::Setup(lua); + LuaClassImplFinalizerSetupProxy::value>::Setup(state); } template - void LuaClass::SetupGetter(LuaInstance& lua, LuaCFunction proxy) + void LuaClass::SetupGetter(LuaState& state, LuaCFunction proxy) { - lua.PushValue(1); // ClassInfo - lua.PushValue(-2); // Metatable - lua.PushCFunction(proxy, 2); + state.PushValue(1); // ClassInfo + state.PushValue(-2); // Metatable + state.PushCFunction(proxy, 2); - lua.SetField("__index"); // Getter + state.SetField("__index"); // Getter } template - void LuaClass::SetupGlobalTable(LuaInstance& lua) + void LuaClass::SetupGlobalTable(LuaState& state) { // Create the global table - lua.PushTable(); // Class = {} + state.PushTable(); // Class = {} // Create a metatable which will be used for our global table - lua.PushTable(); // ClassMeta = {} + state.PushTable(); // ClassMeta = {} if (m_info->constructor) - SetupConstructor(lua); + SetupConstructor(state); if (m_info->staticGetter) - SetupGetter(lua, StaticGetterProxy); + SetupGetter(state, StaticGetterProxy); else { // Optimize by assigning the metatable instead of a search function - lua.PushValue(-1); // Metatable - lua.SetField("__index"); + state.PushValue(-1); // Metatable + state.SetField("__index"); } if (m_info->staticSetter) - SetupSetter(lua, StaticSetterProxy); + SetupSetter(state, StaticSetterProxy); m_info->staticMethods.reserve(m_staticMethods.size()); for (auto& pair : m_staticMethods) @@ -317,41 +317,41 @@ namespace Nz std::size_t methodIndex = m_info->staticMethods.size(); m_info->staticMethods.push_back(pair.second); - SetupMethod(lua, StaticMethodProxy, pair.first, methodIndex); + SetupMethod(state, StaticMethodProxy, pair.first, methodIndex); } - lua.SetMetatable(-2); // setmetatable(Class, ClassMeta), pops ClassMeta + state.SetMetatable(-2); // setmetatable(Class, ClassMeta), pops ClassMeta - lua.PushValue(-1); // As CreateReference() pops the table, push a copy - m_info->globalTableRef = lua.CreateReference(); + state.PushValue(-1); // As CreateReference() pops the table, push a copy + m_info->globalTableRef = state.CreateReference(); - lua.SetGlobal(m_info->name); // _G["Class"] = Class + state.SetGlobal(m_info->name); // _G["Class"] = Class } template - void LuaClass::SetupMetatable(LuaInstance& lua) + void LuaClass::SetupMetatable(LuaState& state) { - if (!lua.NewMetatable(m_info->name)) + if (!state.NewMetatable(m_info->name)) NazaraWarning("Class \"" + m_info->name + "\" already registred in this instance"); { - SetupFinalizer(lua); + SetupFinalizer(state); if (m_info->getter || !m_info->parentGetters.empty()) - SetupGetter(lua, GetterProxy); + SetupGetter(state, GetterProxy); else { // Optimize by assigning the metatable instead of a search function // This is only possible if we have no custom getter nor parent - lua.PushValue(-1); // Metatable - lua.SetField("__index"); + state.PushValue(-1); // Metatable + state.SetField("__index"); } if (m_info->setter) - SetupSetter(lua, SetterProxy); + SetupSetter(state, SetterProxy); // In case a __tostring method is missing, add a default implementation returning the class name if (m_methods.find("__tostring") == m_methods.end()) - SetupDefaultToString(lua); + SetupDefaultToString(state); m_info->methods.reserve(m_methods.size()); for (auto& pair : m_methods) @@ -359,80 +359,80 @@ namespace Nz std::size_t methodIndex = m_info->methods.size(); m_info->methods.push_back(pair.second); - SetupMethod(lua, MethodProxy, pair.first, methodIndex); + SetupMethod(state, MethodProxy, pair.first, methodIndex); } } - lua.Pop(); //< Pops the metatable, it won't be collected before it's referenced by the Lua registry. + state.Pop(); //< Pops the metatable, it won't be collected before it's referenced by the Lua registry. } template - void LuaClass::SetupMethod(LuaInstance& lua, LuaCFunction proxy, const String& name, std::size_t methodIndex) + void LuaClass::SetupMethod(LuaState& state, LuaCFunction proxy, const String& name, std::size_t methodIndex) { - lua.PushValue(1); // ClassInfo - lua.PushInteger(methodIndex); - lua.PushCFunction(proxy, 2); + state.PushValue(1); // ClassInfo + state.PushInteger(methodIndex); + state.PushCFunction(proxy, 2); - lua.SetField(name); // Method name + state.SetField(name); // Method name } template - void LuaClass::SetupSetter(LuaInstance& lua, LuaCFunction proxy) + void LuaClass::SetupSetter(LuaState& state, LuaCFunction proxy) { - lua.PushValue(1); // ClassInfo - lua.PushCFunction(proxy, 1); + state.PushValue(1); // ClassInfo + state.PushCFunction(proxy, 1); - lua.SetField("__newindex"); // Setter + state.SetField("__newindex"); // Setter } template - int LuaClass::ConstructorProxy(lua_State* state) + int LuaClass::ConstructorProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); const ConstructorFunc& constructor = info->constructor; - lua.Remove(1); // On enlève l'argument "table" du stack + state.Remove(1); // On enlève l'argument "table" du stack - std::size_t argCount = lua.GetStackTop(); + std::size_t argCount = state.GetStackTop(); - T* instance = static_cast(lua.PushUserdata(sizeof(T))); + T* instance = static_cast(state.PushUserdata(sizeof(T))); - if (!constructor(lua, instance, argCount)) + if (!constructor(state, instance, argCount)) { - lua.Error("Constructor failed"); + state.Error("Constructor failed"); return 0; // Normalement jamais exécuté (l'erreur provoquant une exception) } - lua.SetMetatable(info->name); + state.SetMetatable(info->name); return 1; } template - int LuaClass::FinalizerProxy(lua_State* state) + int LuaClass::FinalizerProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); const FinalizerFunc& finalizer = info->finalizer; - T* instance = static_cast(lua.CheckUserdata(1, info->name)); - lua.Remove(1); //< Remove the instance from the Lua stack + T* instance = static_cast(state.CheckUserdata(1, info->name)); + state.Remove(1); //< Remove the instance from the Lua stack - if (!finalizer || finalizer(lua, *instance)) + if (!finalizer || finalizer(state, *instance)) instance->~T(); return 0; } template - int LuaClass::InfoDestructor(lua_State* state) + int LuaClass::InfoDestructor(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); - lua.DestroyReference(info->globalTableRef); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); + state.DestroyReference(info->globalTableRef); using namespace std; // Obligatoire pour le destructeur info.~shared_ptr(); // Si vous voyez une autre façon de faire, je suis preneur @@ -441,27 +441,27 @@ namespace Nz } template - void LuaClass::Get(const std::shared_ptr& info, LuaInstance& lua, T* instance) + void LuaClass::Get(const std::shared_ptr& info, LuaState& state, T* instance) { const ClassIndexFunc& getter = info->getter; - if (!getter || !getter(lua, *instance)) + if (!getter || !getter(state, *instance)) { // Query from the metatable - lua.GetMetatable(info->name); //< Metatable - lua.PushValue(2); //< Field - lua.GetTable(); // Metatable[Field] + state.GetMetatable(info->name); //< Metatable + state.PushValue(2); //< Field + state.GetTable(); // Metatable[Field] - lua.Remove(-2); // Remove Metatable + state.Remove(-2); // Remove Metatable - if (!lua.IsValid(-1)) + if (!state.IsValid(-1)) { for (const ParentFunc& parentGetter : info->parentGetters) { - lua.Pop(); //< Pop the last nil value + state.Pop(); //< Pop the last nil value - parentGetter(lua, instance); - if (lua.IsValid(-1)) + parentGetter(state, instance); + if (state.IsValid(-1)) return; } } @@ -469,131 +469,131 @@ namespace Nz } template - int LuaClass::GetterProxy(lua_State* state) + int LuaClass::GetterProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); - T* instance = static_cast(lua.CheckUserdata(1, info->name)); + T* instance = static_cast(state.CheckUserdata(1, info->name)); - Get(info, lua, instance); + Get(info, state, instance); return 1; } template - int LuaClass::MethodProxy(lua_State* state) + int LuaClass::MethodProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); T* instance = nullptr; - if (lua.GetMetatable(1)) + if (state.GetMetatable(1)) { - LuaType type = lua.GetField("__name"); + LuaType type = state.GetField("__name"); if (type == LuaType_String) { - String name = lua.ToString(-1); + String name = state.ToString(-1); auto it = info->instanceGetters.find(name); if (it != info->instanceGetters.end()) - instance = it->second(lua); + instance = it->second(state); } - lua.Pop(2); + state.Pop(2); } if (!instance) { - lua.Error("Method cannot be called without an object"); + state.Error("Method cannot be called without an object"); return 0; } - std::size_t argCount = lua.GetStackTop() - 1U; + std::size_t argCount = state.GetStackTop() - 1U; - unsigned int index = static_cast(lua.ToInteger(lua.GetIndexOfUpValue(2))); + unsigned int index = static_cast(state.ToInteger(state.GetIndexOfUpValue(2))); const ClassFunc& method = info->methods[index]; - return method(lua, *instance, argCount); + return method(state, *instance, argCount); } template - int LuaClass::SetterProxy(lua_State* state) + int LuaClass::SetterProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); const ClassIndexFunc& setter = info->setter; - T& instance = *static_cast(lua.CheckUserdata(1, info->name)); + T& instance = *static_cast(state.CheckUserdata(1, info->name)); - if (!setter(lua, instance)) + if (!setter(state, instance)) { std::size_t length; - const char* str = lua.ToString(2, &length); + const char* str = state.ToString(2, &length); - lua.Error("Class \"" + info->name + "\" has no field \"" + String(str, length) + "\")"); + state.Error("Class \"" + info->name + "\" has no field \"" + String(str, length) + "\")"); } return 1; } template - int LuaClass::StaticGetterProxy(lua_State* state) + int LuaClass::StaticGetterProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); const StaticIndexFunc& getter = info->staticGetter; - if (!getter(lua)) + if (!getter(state)) { // On accède alors à la table - lua.PushValue(lua.GetIndexOfUpValue(2)); - lua.PushValue(-2); - lua.GetTable(); + state.PushValue(state.GetIndexOfUpValue(2)); + state.PushValue(-2); + state.GetTable(); } return 1; } template - int LuaClass::StaticMethodProxy(lua_State* state) + int LuaClass::StaticMethodProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); - unsigned int index = static_cast(lua.ToInteger(lua.GetIndexOfUpValue(2))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); + unsigned int index = static_cast(state.ToInteger(state.GetIndexOfUpValue(2))); const StaticFunc& method = info->staticMethods[index]; - return method(lua); + return method(state); } template - int LuaClass::StaticSetterProxy(lua_State* state) + int LuaClass::StaticSetterProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); const StaticIndexFunc& setter = info->staticSetter; - if (!setter(lua)) + if (!setter(state)) { std::size_t length; - const char* str = lua.ToString(2, &length); + const char* str = state.ToString(2, &length); - lua.Error("Class \"" + info->name + "\" has no static field \"" + String(str, length) + ')'); + state.Error("Class \"" + info->name + "\" has no static field \"" + String(str, length) + ')'); } return 1; } template - int LuaClass::ToStringProxy(lua_State* state) + int LuaClass::ToStringProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); - lua.PushString(info->name); + state.PushString(info->name); return 1; } } diff --git a/include/Nazara/Lua/LuaInstance.hpp b/include/Nazara/Lua/LuaInstance.hpp index 2ac752c9e..45d19ddba 100644 --- a/include/Nazara/Lua/LuaInstance.hpp +++ b/include/Nazara/Lua/LuaInstance.hpp @@ -4,201 +4,41 @@ #pragma once -#ifndef NAZARA_LUASTATE_HPP -#define NAZARA_LUASTATE_HPP +#ifndef NAZARA_LUAINSTANCE_HPP +#define NAZARA_LUAINSTANCE_HPP #include -#include -#include -#include -#include -#include +#include #include #include -struct lua_Debug; -struct lua_State; - namespace Nz { - class LuaInstance; - - using LuaCFunction = int (*)(lua_State* state); - using LuaFunction = std::function; - - class NAZARA_LUA_API LuaInstance + class NAZARA_LUA_API LuaInstance : public LuaState { + friend class LuaState; + public: LuaInstance(); LuaInstance(const LuaInstance&) = delete; - LuaInstance(LuaInstance&& instance) noexcept; + LuaInstance(LuaInstance&& instance) = default; ~LuaInstance(); - void ArgCheck(bool condition, unsigned int argNum, const char* error) const; - void ArgCheck(bool condition, unsigned int argNum, const String& error) const; - int ArgError(unsigned int argNum, const char* error) const; - int ArgError(unsigned int argNum, const String& error) const; - - bool Call(unsigned int argCount); - bool Call(unsigned int argCount, unsigned int resultCount); - - template T Check(int* index) const; - template T Check(int* index, T defValue) const; - void CheckAny(int index) const; - bool CheckBoolean(int index) const; - bool CheckBoolean(int index, bool defValue) const; - template T CheckBoundInteger(int index) const; - template T CheckBoundInteger(int index, T defValue) const; - template T CheckField(const char* fieldName, int tableIndex = -1) const; - template T CheckField(const String& fieldName, int tableIndex = -1) const; - template T CheckField(const char* fieldName, T defValue, int tableIndex = -1) const; - template T CheckField(const String& fieldName, T defValue, int tableIndex = -1) const; - long long CheckInteger(int index) const; - long long CheckInteger(int index, long long defValue) const; - template T CheckGlobal(const char* fieldName) const; - template T CheckGlobal(const String& fieldName) const; - template T CheckGlobal(const char* fieldName, T defValue) const; - template T CheckGlobal(const String& fieldName, T defValue) const; - double CheckNumber(int index) const; - double CheckNumber(int index, double defValue) const; - void CheckStack(int space, const char* error = nullptr) const; - void CheckStack(int space, const String& error) const; - const char* CheckString(int index, std::size_t* length = nullptr) const; - const char* CheckString(int index, const char* defValue, std::size_t* length = nullptr) const; - void CheckType(int index, LuaType type) const; - void* CheckUserdata(int index, const char* tname) const; - void* CheckUserdata(int index, const String& tname) const; - - bool Compare(int index1, int index2, LuaComparison comparison) const; - void Compute(LuaOperation operation) const; - - void Concatenate(int count) const; - - int CreateReference(); - void DestroyReference(int ref); - - String DumpStack() const; - - void Error(const char* message) const; - void Error(const String& message) const; - - bool Execute(const String& code); - bool ExecuteFromFile(const String& filePath); - bool ExecuteFromMemory(const void* data, std::size_t size); - bool ExecuteFromStream(Stream& stream); - - int GetAbsIndex(int index) const; - LuaType GetField(const char* fieldName, int tableIndex = -1) const; - LuaType GetField(const String& fieldName, int tableIndex = -1) const; - LuaType GetGlobal(const char* name) const; - LuaType GetGlobal(const String& name) const; - inline lua_State* GetInternalState() const; - inline String GetLastError() const; - inline std::size_t GetMemoryLimit() const; - inline std::size_t GetMemoryUsage() const; - LuaType GetMetatable(const char* tname) const; - LuaType GetMetatable(const String& tname) const; - bool GetMetatable(int index) const; - unsigned int GetStackTop() const; - LuaType GetTable(int index = -2) const; - LuaType GetTableRaw(int index = -2) const; - inline UInt32 GetTimeLimit() const; - LuaType GetType(int index) const; - const char* GetTypeName(LuaType type) const; - - void Insert(int index) const; - - bool IsOfType(int index, LuaType type) const; - bool IsOfType(int index, const char* tname) const; - bool IsOfType(int index, const String& tname) const; - bool IsValid(int index) const; - - long long Length(int index) const; - std::size_t LengthRaw(int index) const; - - void MoveTo(LuaInstance* instance, int n) const; - - bool NewMetatable(const char* str); - bool NewMetatable(const String& str); - bool Next(int index = -2) const; - - void Pop(unsigned int n = 1U) const; - - template int Push(T arg) const; - template int Push(T firstArg, T2 secondArg, Args... args) const; - void PushBoolean(bool value) const; - void PushCFunction(LuaCFunction func, unsigned int upvalueCount = 0) const; - template void PushField(const char* name, T&& arg, int tableIndex = -2) const; - template void PushField(const String& name, T&& arg, int tableIndex = -2) const; - void PushFunction(LuaFunction func) const; - template void PushFunction(R(*func)(Args...), DefArgs&&... defArgs) const; - template void PushGlobal(const char* name, T&& arg); - template void PushGlobal(const String& name, T&& arg); - template void PushInstance(const char* tname, const T& instance) const; - template void PushInstance(const char* tname, T&& instance) const; - template void PushInstance(const char* tname, Args&&... args) const; - void PushInteger(long long value) const; - void PushLightUserdata(void* value) const; - void PushMetatable(const char* str) const; - void PushMetatable(const String& str) const; - void PushNil() const; - void PushNumber(double value) const; - void PushReference(int ref) const; - void PushString(const char* str) const; - void PushString(const char* str, std::size_t size) const; - void PushString(const String& str) const; - void PushTable(std::size_t sequenceElementCount = 0, std::size_t arrayElementCount = 0) const; - void* PushUserdata(std::size_t size) const; - void PushValue(int index) const; - - void Remove(int index) const; - void Replace(int index) const; - - void SetField(const char* name, int tableIndex = -2) const; - void SetField(const String& name, int tableIndex = -2) const; - void SetGlobal(const char* name); - void SetGlobal(const String& name); - void SetMetatable(const char* tname) const; - void SetMetatable(const String& tname) const; - void SetMetatable(int index) const; - void SetMemoryLimit(std::size_t memoryLimit); - void SetTable(int index = -3) const; - void SetTableRaw(int index = -3) const; - void SetTimeLimit(UInt32 timeLimit); - - bool ToBoolean(int index) const; - long long ToInteger(int index, bool* succeeded = nullptr) const; - double ToNumber(int index, bool* succeeded = nullptr) const; - const void* ToPointer(int index) const; - const char* ToString(int index, std::size_t* length = nullptr) const; - void* ToUserdata(int index) const; - void* ToUserdata(int index, const char* tname) const; - void* ToUserdata(int index, const String& tname) const; - LuaInstance& operator=(const LuaInstance&) = delete; - LuaInstance& operator=(LuaInstance&& instance) noexcept; - - static int GetIndexOfUpValue(int upValue); - static LuaInstance* GetInstance(lua_State* state); + LuaInstance& operator=(LuaInstance&& instance) = default; private: - template T CheckBounds(int index, long long value) const; - bool Run(int argCount, int resultCount); - static void* MemoryAllocator(void *ud, void *ptr, std::size_t osize, std::size_t nsize); - static int ProxyFunc(lua_State* state); - static void TimeLimiter(lua_State* state, lua_Debug* debug); + static void TimeLimiter(lua_State* internalState, lua_Debug* debug); std::size_t m_memoryLimit; std::size_t m_memoryUsage; UInt32 m_timeLimit; Clock m_clock; - String m_lastError; - lua_State* m_state; unsigned int m_level; }; } #include -#endif // NAZARA_LUASTATE_HPP +#endif // NAZARA_LUAINSTANCE_HPP diff --git a/include/Nazara/Lua/LuaInstance.inl b/include/Nazara/Lua/LuaInstance.inl index b30c7eca4..f4394eb6b 100644 --- a/include/Nazara/Lua/LuaInstance.inl +++ b/include/Nazara/Lua/LuaInstance.inl @@ -15,783 +15,4 @@ namespace Nz { - inline lua_State* LuaInstance::GetInternalState() const - { - return m_state; - } - - inline String LuaInstance::GetLastError() const - { - return m_lastError; - } - - inline std::size_t LuaInstance::GetMemoryLimit() const - { - return m_memoryLimit; - } - - inline std::size_t LuaInstance::GetMemoryUsage() const - { - return m_memoryUsage; - } - - inline UInt32 LuaInstance::GetTimeLimit() const - { - return m_timeLimit; - } - - // Functions args - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, bool* arg, TypeTag) - { - *arg = instance.CheckBoolean(index); - return 1; - } - - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, bool* arg, bool defValue, TypeTag) - { - *arg = instance.CheckBoolean(index, defValue); - return 1; - } - - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, std::string* arg, TypeTag) - { - std::size_t strLength = 0; - const char* str = instance.CheckString(index, &strLength); - - arg->assign(str, strLength); - - return 1; - } - - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, String* arg, TypeTag) - { - std::size_t strLength = 0; - const char* str = instance.CheckString(index, &strLength); - - arg->Set(str, strLength); - - return 1; - } - - template - std::enable_if_t::value && !EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) - { - using UnderlyingT = std::underlying_type_t; - return LuaImplQueryArg(instance, index, reinterpret_cast(arg), TypeTag()); - } - - template - std::enable_if_t::value && !EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) - { - using UnderlyingT = std::underlying_type_t; - return LuaImplQueryArg(instance, index, reinterpret_cast(arg), static_cast(defValue), TypeTag()); - } - - template - std::enable_if_t::value && EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) - { - using UnderlyingT = std::underlying_type_t; - - UnderlyingT pot2Val; - unsigned int ret = LuaImplQueryArg(instance, index, &pot2Val, TypeTag()); - - *arg = static_cast(IntegralLog2Pot(pot2Val)); - return ret; - } - - template - std::enable_if_t::value && EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) - { - using UnderlyingT = std::underlying_type_t; - - UnderlyingT pot2Val; - unsigned int ret = LuaImplQueryArg(instance, index, &pot2Val, 1U << static_cast(defValue), TypeTag()); - - *arg = static_cast(IntegralLog2Pot(pot2Val)); - return ret; - } - - template - unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Flags* arg, TypeTag>) - { - *arg = Flags(instance.CheckBoundInteger(index)); - return 1; - } - - template - std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) - { - *arg = static_cast(instance.CheckNumber(index)); - return 1; - } - - template - std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) - { - *arg = static_cast(instance.CheckNumber(index, static_cast(defValue))); - return 1; - } - - template - std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) - { - *arg = instance.CheckBoundInteger(index); - return 1; - } - - template - std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) - { - *arg = instance.CheckBoundInteger(index, defValue); - return 1; - } - - template - std::enable_if_t::value && !std::is_enum::value && !std::is_floating_point::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, const T& defValue, TypeTag tag) - { - if (instance.IsValid(index)) - return LuaImplQueryArg(instance, index, arg, tag); - else - { - *arg = defValue; - return 1; - } - } - - template - unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) - { - return LuaImplQueryArg(instance, index, arg, TypeTag()); - } - - template - unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, const T& defValue, TypeTag) - { - return LuaImplQueryArg(instance, index, arg, defValue, TypeTag()); - } - - // Function returns - inline int LuaImplReplyVal(const LuaInstance& instance, bool val, TypeTag) - { - instance.PushBoolean(val); - return 1; - } - - inline int LuaImplReplyVal(const LuaInstance& instance, double val, TypeTag) - { - instance.PushNumber(val); - return 1; - } - - inline int LuaImplReplyVal(const LuaInstance& instance, float val, TypeTag) - { - instance.PushNumber(val); - return 1; - } - - template - std::enable_if_t::value && !EnumAsFlags::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - using EnumT = typename std::underlying_type::type; - return LuaImplReplyVal(instance, static_cast(val), TypeTag()); - } - - template - std::enable_if_t::value && EnumAsFlags::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - Flags flags(val); - return LuaImplReplyVal(instance, flags, TypeTag()); - } - - template - int LuaImplReplyVal(const LuaInstance& instance, Flags val, TypeTag>) - { - instance.PushInteger(UInt32(val)); - return 1; - } - - template - std::enable_if_t::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - instance.PushInteger(val); - return 1; - } - - template - std::enable_if_t::value || std::is_enum::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - return LuaImplReplyVal(instance, val, TypeTag()); - } - - template - std::enable_if_t::value || std::is_enum::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - return LuaImplReplyVal(instance, val, TypeTag()); - } - - template - std::enable_if_t::value && !std::is_enum::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - return LuaImplReplyVal(instance, std::move(val), TypeTag()); - } - - template - std::enable_if_t::value && !std::is_enum::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - return LuaImplReplyVal(instance, std::move(val), TypeTag()); - } - - template - int LuaImplReplyVal(const LuaInstance& instance, T&& val, TypeTag) - { - return LuaImplReplyVal(instance, std::forward(val), TypeTag()); - } - - inline int LuaImplReplyVal(const LuaInstance& instance, std::string&& val, TypeTag) - { - instance.PushString(val.c_str(), val.size()); - return 1; - } - - template - inline int LuaImplReplyVal(const LuaInstance& instance, std::vector&& valContainer, TypeTag>) - { - std::size_t index = 1; - instance.PushTable(valContainer.size()); - for (T& val : valContainer) - { - instance.PushInteger(index++); - if (LuaImplReplyVal(instance, std::move(val), TypeTag()) != 1) - { - instance.Error("Couldn't create table: type need more than one place to store"); - return 0; - } - instance.SetTable(); - } - - return 1; - } - - inline int LuaImplReplyVal(const LuaInstance& instance, ByteArray&& val, TypeTag) - { - instance.PushString(reinterpret_cast(val.GetConstBuffer()), val.GetSize()); - return 1; - } - - inline int LuaImplReplyVal(const LuaInstance& instance, String&& val, TypeTag) - { - instance.PushString(std::move(val)); - return 1; - } - - template - int LuaImplReplyVal(const LuaInstance& instance, std::pair&& val, TypeTag>) - { - int retVal = 0; - - retVal += LuaImplReplyVal(instance, std::move(val.first), TypeTag()); - retVal += LuaImplReplyVal(instance, std::move(val.second), TypeTag()); - - return retVal; - } - - template - struct LuaImplArgProcesser; - - template<> - struct LuaImplArgProcesser - { - template - static unsigned int Process(const LuaInstance& instance, unsigned int argIndex, ArgContainer& args, DefArgContainer& defArgs) - { - return LuaImplQueryArg(instance, argIndex, &std::get(args), std::get() - N - 1>(defArgs), TypeTag()); - } - }; - - template<> - struct LuaImplArgProcesser - { - template - static unsigned int Process(const LuaInstance& instance, unsigned int argIndex, ArgContainer& args, DefArgContainer& defArgs) - { - NazaraUnused(defArgs); - - return LuaImplQueryArg(instance, argIndex, &std::get(args), TypeTag()); - } - }; - - template - class LuaImplFunctionProxy - { - public: - template - class Impl - { - static constexpr std::size_t ArgCount = sizeof...(Args); - static constexpr std::size_t DefArgCount = sizeof...(DefArgs); - - static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument"); - - static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount; - - public: - Impl(DefArgs... defArgs) : - m_defaultArgs(std::forward(defArgs)...) - { - } - - void ProcessArguments(const LuaInstance& instance) const - { - m_index = 1; - ProcessArgs<0, Args...>(instance); - } - - int Invoke(const LuaInstance& instance, void(*func)(Args...)) const - { - NazaraUnused(instance); - - Apply(func, m_args); - return 0; - } - - template - int Invoke(const LuaInstance& instance, Ret(*func)(Args...)) const - { - return LuaImplReplyVal(instance, std::move(Apply(func, m_args)), TypeTag()); - } - - private: - using ArgContainer = std::tuple>...>; - using DefArgContainer = std::tuple>...>; - - template - void ProcessArgs(const LuaInstance& instance) const - { - NazaraUnused(instance); - - // No argument to process - } - - template - void ProcessArgs(const LuaInstance& instance) const - { - LuaImplArgProcesser<(N >= FirstDefArg)>::template Process(instance, m_index, m_args, m_defaultArgs); - } - - template - void ProcessArgs(const LuaInstance& instance) const - { - ProcessArgs(instance); - ProcessArgs(instance); - } - - mutable ArgContainer m_args; - DefArgContainer m_defaultArgs; - mutable unsigned int m_index; - }; - }; - - template - class LuaImplMethodProxy - { - public: - template - class Impl - { - static constexpr std::size_t ArgCount = sizeof...(Args); - static constexpr std::size_t DefArgCount = sizeof...(DefArgs); - - static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument"); - - static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount; - - public: - Impl(DefArgs... defArgs) : - m_defaultArgs(std::forward(defArgs)...) - { - } - - void ProcessArguments(const LuaInstance& instance) const - { - m_index = 2; //< 1 being the instance - ProcessArgs<0, Args...>(instance); - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, T& object, void(P::*func)(Args...)) const - { - NazaraUnused(instance); - - Apply(object, func, m_args); - return 0; - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, T& object, Ret(P::*func)(Args...)) const - { - return LuaImplReplyVal(instance, std::move(Apply(object, func, m_args)), TypeTag()); - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, T& object, T&(P::*func)(Args...)) const - { - T& r = Apply(object, func, m_args); - if (&r == &object) - { - instance.PushValue(1); //< Userdata - return 1; - } - else - return LuaImplReplyVal(instance, r, TypeTag()); - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, const T& object, void(P::*func)(Args...) const) const - { - NazaraUnused(instance); - - Apply(object, func, m_args); - return 0; - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, const T& object, Ret(P::*func)(Args...) const) const - { - return LuaImplReplyVal(instance, std::move(Apply(object, func, m_args)), TypeTag()); - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, const T& object, const T&(P::*func)(Args...) const) const - { - const T& r = Apply(object, func, m_args); - if (&r == &object) - { - instance.PushValue(1); //< Userdata - return 1; - } - else - return LuaImplReplyVal(instance, r, TypeTag()); - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, T& object, void(P::*func)(Args...)) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - Apply(*object, func, m_args); - return 0; - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, T& object, Ret(P::*func)(Args...)) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - return LuaImplReplyVal(instance, std::move(Apply(*object, func, m_args)), TypeTag()); - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, T& object, typename PointedType::type&(P::*func)(Args...) const) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - const typename PointedType::type& r = Apply(*object, func, m_args); - if (&r == &*object) - { - instance.PushValue(1); //< Userdata - return 1; - } - else - return LuaImplReplyVal(instance, r, TypeTag()); - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, const T& object, void(P::*func)(Args...) const) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - Apply(*object, func, m_args); - return 0; - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, const T& object, Ret(P::*func)(Args...) const) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - return LuaImplReplyVal(instance, std::move(Apply(*object, func, m_args)), TypeTag()); - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, const T& object, const typename PointedType::type&(P::*func)(Args...) const) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - const typename PointedType::type& r = Apply(*object, func, m_args); - if (&r == &*object) - { - instance.PushValue(1); //< Userdata - return 1; - } - else - return LuaImplReplyVal(instance, r, TypeTag()); - } - - private: - using ArgContainer = std::tuple>...>; - using DefArgContainer = std::tuple>...>; - - template - void ProcessArgs(const LuaInstance& instance) const - { - NazaraUnused(instance); - - // No argument to process - } - - template - void ProcessArgs(const LuaInstance& instance) const - { - m_index += LuaImplArgProcesser<(N >= FirstDefArg)>::template Process(instance, m_index, m_args, m_defaultArgs); - } - - template - void ProcessArgs(const LuaInstance& instance) const - { - ProcessArgs(instance); - ProcessArgs(instance); - } - - mutable ArgContainer m_args; - DefArgContainer m_defaultArgs; - mutable unsigned int m_index; - }; - }; - - template - T LuaInstance::Check(int* index) const - { - NazaraAssert(index, "Invalid index pointer"); - - T object; - *index += LuaImplQueryArg(*this, *index, &object, TypeTag()); - - return object; - } - - template - T LuaInstance::Check(int* index, T defValue) const - { - NazaraAssert(index, "Invalid index pointer"); - - T object; - *index += LuaImplQueryArg(*this, *index, &object, defValue, TypeTag()); - - return object; - } - - template - inline T LuaInstance::CheckBoundInteger(int index) const - { - return CheckBounds(index, CheckInteger(index)); - } - - template - inline T LuaInstance::CheckBoundInteger(int index, T defValue) const - { - return CheckBounds(index, CheckInteger(index, defValue)); - } - - template - T LuaInstance::CheckField(const char* fieldName, int tableIndex) const - { - T object; - - GetField(fieldName, tableIndex); - tableIndex += LuaImplQueryArg(*this, -1, &object, TypeTag()); - Pop(); - - return object; - } - - template - T LuaInstance::CheckField(const String& fieldName, int tableIndex) const - { - return CheckField(fieldName.GetConstBuffer(), tableIndex); - } - - template - T LuaInstance::CheckField(const char* fieldName, T defValue, int tableIndex) const - { - T object; - - GetField(fieldName, tableIndex); - tableIndex += LuaImplQueryArg(*this, -1, &object, defValue, TypeTag()); - Pop(); - - return object; - } - - template - T LuaInstance::CheckField(const String& fieldName, T defValue, int tableIndex) const - { - return CheckField(fieldName.GetConstBuffer(), defValue, tableIndex); - } - - template - T LuaInstance::CheckGlobal(const char* fieldName) const - { - T object; - - GetGlobal(fieldName); - LuaImplQueryArg(*this, -1, &object, TypeTag()); - Pop(); - - return object; - } - - template - T LuaInstance::CheckGlobal(const String& fieldName) const - { - return CheckGlobal(fieldName.GetConstBuffer()); - } - - template - T LuaInstance::CheckGlobal(const char* fieldName, T defValue) const - { - T object; - - GetGlobal(fieldName); - LuaImplQueryArg(*this, -1, &object, defValue, TypeTag()); - Pop(); - - return object; - } - - template - T LuaInstance::CheckGlobal(const String& fieldName, T defValue) const - { - return CheckGlobal(fieldName.GetConstBuffer(), defValue); - } - - template - int LuaInstance::Push(T arg) const - { - return LuaImplReplyVal(*this, std::move(arg), TypeTag()); - } - - template - int LuaInstance::Push(T firstArg, T2 secondArg, Args... args) const - { - int valCount = 0; - valCount += Push(std::move(firstArg)); - valCount += Push(secondArg, std::forward(args)...); - - return valCount; - } - - template - void LuaInstance::PushField(const char* name, T&& arg, int tableIndex) const - { - Push(std::forward(arg)); - SetField(name, tableIndex); - } - - template - void LuaInstance::PushField(const String& name, T&& arg, int tableIndex) const - { - PushField(name.GetConstBuffer(), std::forward(arg), tableIndex); - } - - template - void LuaInstance::PushFunction(R(*func)(Args...), DefArgs&&... defArgs) const - { - typename LuaImplFunctionProxy::template Impl handler(std::forward(defArgs)...); - - PushFunction([func, handler] (LuaInstance& lua) -> int - { - handler.ProcessArguments(lua); - - return handler.Invoke(lua, func); - }); - } - - template - void LuaInstance::PushGlobal(const char* name, T&& arg) - { - Push(std::forward(arg)); - SetGlobal(name); - } - - template - void LuaInstance::PushGlobal(const String& name, T&& arg) - { - PushGlobal(name.GetConstBuffer(), std::forward(arg)); - } - - template - void LuaInstance::PushInstance(const char* tname, const T& instance) const - { - T* userdata = static_cast(PushUserdata(sizeof(T))); - PlacementNew(userdata, instance); - - SetMetatable(tname); - } - - template - void LuaInstance::PushInstance(const char* tname, T&& instance) const - { - T* userdata = static_cast(PushUserdata(sizeof(T))); - PlacementNew(userdata, std::move(instance)); - - SetMetatable(tname); - } - - template - void LuaInstance::PushInstance(const char* tname, Args&&... args) const - { - T* userdata = static_cast(PushUserdata(sizeof(T))); - PlacementNew(userdata, std::forward(args)...); - - SetMetatable(tname); - } - - template - T LuaInstance::CheckBounds(int index, long long value) const - { - constexpr long long minBounds = std::numeric_limits::min(); - constexpr long long maxBounds = std::numeric_limits::max(); - if (value < minBounds || value > maxBounds) - { - Nz::StringStream stream; - stream << "Argument #" << index << " is outside value range [" << minBounds << ", " << maxBounds << "] (" << value << ')'; - Error(stream); - } - - return static_cast(value); - } } diff --git a/include/Nazara/Lua/LuaState.hpp b/include/Nazara/Lua/LuaState.hpp new file mode 100644 index 000000000..a34ec27fd --- /dev/null +++ b/include/Nazara/Lua/LuaState.hpp @@ -0,0 +1,197 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LUASTATE_HPP +#define NAZARA_LUASTATE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +struct lua_Debug; +struct lua_State; + +namespace Nz +{ + class LuaInstance; + class LuaState; + + using LuaCFunction = int (*)(lua_State* internalState); + using LuaFunction = std::function; + + class NAZARA_LUA_API LuaState + { + public: + LuaState(const LuaState&) = default; + LuaState(LuaState&& instance) noexcept; + ~LuaState() = default; + + void ArgCheck(bool condition, unsigned int argNum, const char* error) const; + void ArgCheck(bool condition, unsigned int argNum, const String& error) const; + int ArgError(unsigned int argNum, const char* error) const; + int ArgError(unsigned int argNum, const String& error) const; + + bool Call(unsigned int argCount); + bool Call(unsigned int argCount, unsigned int resultCount); + + template T Check(int* index) const; + template T Check(int* index, T defValue) const; + void CheckAny(int index) const; + bool CheckBoolean(int index) const; + bool CheckBoolean(int index, bool defValue) const; + template T CheckBoundInteger(int index) const; + template T CheckBoundInteger(int index, T defValue) const; + template T CheckField(const char* fieldName, int tableIndex = -1) const; + template T CheckField(const String& fieldName, int tableIndex = -1) const; + template T CheckField(const char* fieldName, T defValue, int tableIndex = -1) const; + template T CheckField(const String& fieldName, T defValue, int tableIndex = -1) const; + long long CheckInteger(int index) const; + long long CheckInteger(int index, long long defValue) const; + template T CheckGlobal(const char* fieldName) const; + template T CheckGlobal(const String& fieldName) const; + template T CheckGlobal(const char* fieldName, T defValue) const; + template T CheckGlobal(const String& fieldName, T defValue) const; + double CheckNumber(int index) const; + double CheckNumber(int index, double defValue) const; + void CheckStack(int space, const char* error = nullptr) const; + void CheckStack(int space, const String& error) const; + const char* CheckString(int index, std::size_t* length = nullptr) const; + const char* CheckString(int index, const char* defValue, std::size_t* length = nullptr) const; + void CheckType(int index, LuaType type) const; + void* CheckUserdata(int index, const char* tname) const; + void* CheckUserdata(int index, const String& tname) const; + + bool Compare(int index1, int index2, LuaComparison comparison) const; + void Compute(LuaOperation operation) const; + + void Concatenate(int count) const; + + int CreateReference(); + void DestroyReference(int ref); + + String DumpStack() const; + + void Error(const char* message) const; + void Error(const String& message) const; + + bool Execute(const String& code); + bool ExecuteFromFile(const String& filePath); + bool ExecuteFromMemory(const void* data, std::size_t size); + bool ExecuteFromStream(Stream& stream); + + int GetAbsIndex(int index) const; + LuaType GetField(const char* fieldName, int tableIndex = -1) const; + LuaType GetField(const String& fieldName, int tableIndex = -1) const; + LuaType GetGlobal(const char* name) const; + LuaType GetGlobal(const String& name) const; + inline lua_State* GetInternalState() const; + inline String GetLastError() const; + LuaType GetMetatable(const char* tname) const; + LuaType GetMetatable(const String& tname) const; + bool GetMetatable(int index) const; + unsigned int GetStackTop() const; + LuaType GetTable(int index = -2) const; + LuaType GetTableRaw(int index = -2) const; + LuaType GetType(int index) const; + const char* GetTypeName(LuaType type) const; + + void Insert(int index) const; + + bool IsOfType(int index, LuaType type) const; + bool IsOfType(int index, const char* tname) const; + bool IsOfType(int index, const String& tname) const; + bool IsValid(int index) const; + + long long Length(int index) const; + std::size_t LengthRaw(int index) const; + + void MoveTo(LuaState* instance, int n) const; + + bool NewMetatable(const char* str); + bool NewMetatable(const String& str); + bool Next(int index = -2) const; + + void Pop(unsigned int n = 1U) const; + + template int Push(T arg) const; + template int Push(T firstArg, T2 secondArg, Args... args) const; + void PushBoolean(bool value) const; + void PushCFunction(LuaCFunction func, unsigned int upvalueCount = 0) const; + template void PushField(const char* name, T&& arg, int tableIndex = -2) const; + template void PushField(const String& name, T&& arg, int tableIndex = -2) const; + void PushFunction(LuaFunction func) const; + template void PushFunction(R(*func)(Args...), DefArgs&&... defArgs) const; + template void PushGlobal(const char* name, T&& arg); + template void PushGlobal(const String& name, T&& arg); + template void PushInstance(const char* tname, const T& instance) const; + template void PushInstance(const char* tname, T&& instance) const; + template void PushInstance(const char* tname, Args&&... args) const; + void PushInteger(long long value) const; + void PushLightUserdata(void* value) const; + void PushMetatable(const char* str) const; + void PushMetatable(const String& str) const; + void PushNil() const; + void PushNumber(double value) const; + void PushReference(int ref) const; + void PushString(const char* str) const; + void PushString(const char* str, std::size_t size) const; + void PushString(const String& str) const; + void PushTable(std::size_t sequenceElementCount = 0, std::size_t arrayElementCount = 0) const; + void* PushUserdata(std::size_t size) const; + void PushValue(int index) const; + + void Remove(int index) const; + void Replace(int index) const; + + void SetField(const char* name, int tableIndex = -2) const; + void SetField(const String& name, int tableIndex = -2) const; + void SetGlobal(const char* name); + void SetGlobal(const String& name); + void SetMetatable(const char* tname) const; + void SetMetatable(const String& tname) const; + void SetMetatable(int index) const; + void SetMemoryLimit(std::size_t memoryLimit); + void SetTable(int index = -3) const; + void SetTableRaw(int index = -3) const; + void SetTimeLimit(UInt32 timeLimit); + + bool ToBoolean(int index) const; + long long ToInteger(int index, bool* succeeded = nullptr) const; + double ToNumber(int index, bool* succeeded = nullptr) const; + const void* ToPointer(int index) const; + const char* ToString(int index, std::size_t* length = nullptr) const; + void* ToUserdata(int index) const; + void* ToUserdata(int index, const char* tname) const; + void* ToUserdata(int index, const String& tname) const; + + LuaState& operator=(const LuaState&) = default; + LuaState& operator=(LuaState&& instance) noexcept; + + static int GetIndexOfUpValue(int upValue); + static LuaState GetState(lua_State* internalState); + + protected: + LuaState(LuaInstance* instance, lua_State* internalState); + + template T CheckBounds(int index, long long value) const; + bool Run(int argCount, int resultCount); + + static int ProxyFunc(lua_State* internalState); + + String m_lastError; + LuaInstance* m_instance; + lua_State* m_state; + }; +} + +#include + +#endif // NAZARA_LUASTATE_HPP diff --git a/include/Nazara/Lua/LuaState.inl b/include/Nazara/Lua/LuaState.inl new file mode 100644 index 000000000..dbc9016cf --- /dev/null +++ b/include/Nazara/Lua/LuaState.inl @@ -0,0 +1,788 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + inline LuaState::LuaState(LuaInstance* instance, lua_State* internalState) : + m_instance(instance), + m_state(internalState) + { + } + + inline lua_State* LuaState::GetInternalState() const + { + return m_state; + } + + inline String LuaState::GetLastError() const + { + return m_lastError; + } + + // Functions args + inline unsigned int LuaImplQueryArg(const LuaState& instance, int index, bool* arg, TypeTag) + { + *arg = instance.CheckBoolean(index); + return 1; + } + + inline unsigned int LuaImplQueryArg(const LuaState& instance, int index, bool* arg, bool defValue, TypeTag) + { + *arg = instance.CheckBoolean(index, defValue); + return 1; + } + + inline unsigned int LuaImplQueryArg(const LuaState& instance, int index, std::string* arg, TypeTag) + { + std::size_t strLength = 0; + const char* str = instance.CheckString(index, &strLength); + + arg->assign(str, strLength); + + return 1; + } + + inline unsigned int LuaImplQueryArg(const LuaState& instance, int index, String* arg, TypeTag) + { + std::size_t strLength = 0; + const char* str = instance.CheckString(index, &strLength); + + arg->Set(str, strLength); + + return 1; + } + + template + std::enable_if_t::value && !EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag) + { + using UnderlyingT = std::underlying_type_t; + return LuaImplQueryArg(instance, index, reinterpret_cast(arg), TypeTag()); + } + + template + std::enable_if_t::value && !EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag) + { + using UnderlyingT = std::underlying_type_t; + return LuaImplQueryArg(instance, index, reinterpret_cast(arg), static_cast(defValue), TypeTag()); + } + + template + std::enable_if_t::value && EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag) + { + using UnderlyingT = std::underlying_type_t; + + UnderlyingT pot2Val; + unsigned int ret = LuaImplQueryArg(instance, index, &pot2Val, TypeTag()); + + *arg = static_cast(IntegralLog2Pot(pot2Val)); + return ret; + } + + template + std::enable_if_t::value && EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag) + { + using UnderlyingT = std::underlying_type_t; + + UnderlyingT pot2Val; + unsigned int ret = LuaImplQueryArg(instance, index, &pot2Val, 1U << static_cast(defValue), TypeTag()); + + *arg = static_cast(IntegralLog2Pot(pot2Val)); + return ret; + } + + template + unsigned int LuaImplQueryArg(const LuaState& instance, int index, Flags* arg, TypeTag>) + { + *arg = Flags(instance.CheckBoundInteger(index)); + return 1; + } + + template + std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag) + { + *arg = static_cast(instance.CheckNumber(index)); + return 1; + } + + template + std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag) + { + *arg = static_cast(instance.CheckNumber(index, static_cast(defValue))); + return 1; + } + + template + std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag) + { + *arg = instance.CheckBoundInteger(index); + return 1; + } + + template + std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag) + { + *arg = instance.CheckBoundInteger(index, defValue); + return 1; + } + + template + std::enable_if_t::value && !std::is_enum::value && !std::is_floating_point::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, const T& defValue, TypeTag tag) + { + if (instance.IsValid(index)) + return LuaImplQueryArg(instance, index, arg, tag); + else + { + *arg = defValue; + return 1; + } + } + + template + unsigned int LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag) + { + return LuaImplQueryArg(instance, index, arg, TypeTag()); + } + + template + unsigned int LuaImplQueryArg(const LuaState& instance, int index, T* arg, const T& defValue, TypeTag) + { + return LuaImplQueryArg(instance, index, arg, defValue, TypeTag()); + } + + // Function returns + inline int LuaImplReplyVal(const LuaState& instance, bool val, TypeTag) + { + instance.PushBoolean(val); + return 1; + } + + inline int LuaImplReplyVal(const LuaState& instance, double val, TypeTag) + { + instance.PushNumber(val); + return 1; + } + + inline int LuaImplReplyVal(const LuaState& instance, float val, TypeTag) + { + instance.PushNumber(val); + return 1; + } + + template + std::enable_if_t::value && !EnumAsFlags::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + using EnumT = typename std::underlying_type::type; + return LuaImplReplyVal(instance, static_cast(val), TypeTag()); + } + + template + std::enable_if_t::value && EnumAsFlags::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + Flags flags(val); + return LuaImplReplyVal(instance, flags, TypeTag()); + } + + template + int LuaImplReplyVal(const LuaState& instance, Flags val, TypeTag>) + { + instance.PushInteger(UInt32(val)); + return 1; + } + + template + std::enable_if_t::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + instance.PushInteger(val); + return 1; + } + + template + std::enable_if_t::value || std::is_enum::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + return LuaImplReplyVal(instance, val, TypeTag()); + } + + template + std::enable_if_t::value || std::is_enum::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + return LuaImplReplyVal(instance, val, TypeTag()); + } + + template + std::enable_if_t::value && !std::is_enum::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + return LuaImplReplyVal(instance, std::move(val), TypeTag()); + } + + template + std::enable_if_t::value && !std::is_enum::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + return LuaImplReplyVal(instance, std::move(val), TypeTag()); + } + + template + int LuaImplReplyVal(const LuaState& instance, T&& val, TypeTag) + { + return LuaImplReplyVal(instance, std::forward(val), TypeTag()); + } + + inline int LuaImplReplyVal(const LuaState& instance, std::string&& val, TypeTag) + { + instance.PushString(val.c_str(), val.size()); + return 1; + } + + template + inline int LuaImplReplyVal(const LuaState& instance, std::vector&& valContainer, TypeTag>) + { + std::size_t index = 1; + instance.PushTable(valContainer.size()); + for (T& val : valContainer) + { + instance.PushInteger(index++); + if (LuaImplReplyVal(instance, std::move(val), TypeTag()) != 1) + { + instance.Error("Couldn't create table: type need more than one place to store"); + return 0; + } + instance.SetTable(); + } + + return 1; + } + + inline int LuaImplReplyVal(const LuaState& instance, ByteArray&& val, TypeTag) + { + instance.PushString(reinterpret_cast(val.GetConstBuffer()), val.GetSize()); + return 1; + } + + inline int LuaImplReplyVal(const LuaState& instance, String&& val, TypeTag) + { + instance.PushString(std::move(val)); + return 1; + } + + template + int LuaImplReplyVal(const LuaState& instance, std::pair&& val, TypeTag>) + { + int retVal = 0; + + retVal += LuaImplReplyVal(instance, std::move(val.first), TypeTag()); + retVal += LuaImplReplyVal(instance, std::move(val.second), TypeTag()); + + return retVal; + } + + template + struct LuaImplArgProcesser; + + template<> + struct LuaImplArgProcesser + { + template + static unsigned int Process(const LuaState& instance, unsigned int argIndex, ArgContainer& args, DefArgContainer& defArgs) + { + return LuaImplQueryArg(instance, argIndex, &std::get(args), std::get() - N - 1>(defArgs), TypeTag()); + } + }; + + template<> + struct LuaImplArgProcesser + { + template + static unsigned int Process(const LuaState& instance, unsigned int argIndex, ArgContainer& args, DefArgContainer& defArgs) + { + NazaraUnused(defArgs); + + return LuaImplQueryArg(instance, argIndex, &std::get(args), TypeTag()); + } + }; + + template + class LuaImplFunctionProxy + { + public: + template + class Impl + { + static constexpr std::size_t ArgCount = sizeof...(Args); + static constexpr std::size_t DefArgCount = sizeof...(DefArgs); + + static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument"); + + static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount; + + public: + Impl(DefArgs... defArgs) : + m_defaultArgs(std::forward(defArgs)...) + { + } + + void ProcessArguments(const LuaState& instance) const + { + m_index = 1; + ProcessArgs<0, Args...>(instance); + } + + int Invoke(const LuaState& instance, void(*func)(Args...)) const + { + NazaraUnused(instance); + + Apply(func, m_args); + return 0; + } + + template + int Invoke(const LuaState& instance, Ret(*func)(Args...)) const + { + return LuaImplReplyVal(instance, std::move(Apply(func, m_args)), TypeTag()); + } + + private: + using ArgContainer = std::tuple>...>; + using DefArgContainer = std::tuple>...>; + + template + void ProcessArgs(const LuaState& instance) const + { + NazaraUnused(instance); + + // No argument to process + } + + template + void ProcessArgs(const LuaState& instance) const + { + LuaImplArgProcesser<(N >= FirstDefArg)>::template Process(instance, m_index, m_args, m_defaultArgs); + } + + template + void ProcessArgs(const LuaState& instance) const + { + ProcessArgs(instance); + ProcessArgs(instance); + } + + mutable ArgContainer m_args; + DefArgContainer m_defaultArgs; + mutable unsigned int m_index; + }; + }; + + template + class LuaImplMethodProxy + { + public: + template + class Impl + { + static constexpr std::size_t ArgCount = sizeof...(Args); + static constexpr std::size_t DefArgCount = sizeof...(DefArgs); + + static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument"); + + static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount; + + public: + Impl(DefArgs... defArgs) : + m_defaultArgs(std::forward(defArgs)...) + { + } + + void ProcessArguments(const LuaState& instance) const + { + m_index = 2; //< 1 being the instance + ProcessArgs<0, Args...>(instance); + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, T& object, void(P::*func)(Args...)) const + { + NazaraUnused(instance); + + Apply(object, func, m_args); + return 0; + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, T& object, Ret(P::*func)(Args...)) const + { + return LuaImplReplyVal(instance, std::move(Apply(object, func, m_args)), TypeTag()); + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, T& object, T&(P::*func)(Args...)) const + { + T& r = Apply(object, func, m_args); + if (&r == &object) + { + instance.PushValue(1); //< Userdata + return 1; + } + else + return LuaImplReplyVal(instance, r, TypeTag()); + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, const T& object, void(P::*func)(Args...) const) const + { + NazaraUnused(instance); + + Apply(object, func, m_args); + return 0; + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, const T& object, Ret(P::*func)(Args...) const) const + { + return LuaImplReplyVal(instance, std::move(Apply(object, func, m_args)), TypeTag()); + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, const T& object, const T&(P::*func)(Args...) const) const + { + const T& r = Apply(object, func, m_args); + if (&r == &object) + { + instance.PushValue(1); //< Userdata + return 1; + } + else + return LuaImplReplyVal(instance, r, TypeTag()); + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, T& object, void(P::*func)(Args...)) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + Apply(*object, func, m_args); + return 0; + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, T& object, Ret(P::*func)(Args...)) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + return LuaImplReplyVal(instance, std::move(Apply(*object, func, m_args)), TypeTag()); + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, T& object, typename PointedType::type&(P::*func)(Args...) const) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + const typename PointedType::type& r = Apply(*object, func, m_args); + if (&r == &*object) + { + instance.PushValue(1); //< Userdata + return 1; + } + else + return LuaImplReplyVal(instance, r, TypeTag()); + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, const T& object, void(P::*func)(Args...) const) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + Apply(*object, func, m_args); + return 0; + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, const T& object, Ret(P::*func)(Args...) const) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + return LuaImplReplyVal(instance, std::move(Apply(*object, func, m_args)), TypeTag()); + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, const T& object, const typename PointedType::type&(P::*func)(Args...) const) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + const typename PointedType::type& r = Apply(*object, func, m_args); + if (&r == &*object) + { + instance.PushValue(1); //< Userdata + return 1; + } + else + return LuaImplReplyVal(instance, r, TypeTag()); + } + + private: + using ArgContainer = std::tuple>...>; + using DefArgContainer = std::tuple>...>; + + template + void ProcessArgs(const LuaState& instance) const + { + NazaraUnused(instance); + + // No argument to process + } + + template + void ProcessArgs(const LuaState& instance) const + { + m_index += LuaImplArgProcesser<(N >= FirstDefArg)>::template Process(instance, m_index, m_args, m_defaultArgs); + } + + template + void ProcessArgs(const LuaState& instance) const + { + ProcessArgs(instance); + ProcessArgs(instance); + } + + mutable ArgContainer m_args; + DefArgContainer m_defaultArgs; + mutable unsigned int m_index; + }; + }; + + template + T LuaState::Check(int* index) const + { + NazaraAssert(index, "Invalid index pointer"); + + T object; + *index += LuaImplQueryArg(*this, *index, &object, TypeTag()); + + return object; + } + + template + T LuaState::Check(int* index, T defValue) const + { + NazaraAssert(index, "Invalid index pointer"); + + T object; + *index += LuaImplQueryArg(*this, *index, &object, defValue, TypeTag()); + + return object; + } + + template + inline T LuaState::CheckBoundInteger(int index) const + { + return CheckBounds(index, CheckInteger(index)); + } + + template + inline T LuaState::CheckBoundInteger(int index, T defValue) const + { + return CheckBounds(index, CheckInteger(index, defValue)); + } + + template + T LuaState::CheckField(const char* fieldName, int tableIndex) const + { + T object; + + GetField(fieldName, tableIndex); + tableIndex += LuaImplQueryArg(*this, -1, &object, TypeTag()); + Pop(); + + return object; + } + + template + T LuaState::CheckField(const String& fieldName, int tableIndex) const + { + return CheckField(fieldName.GetConstBuffer(), tableIndex); + } + + template + T LuaState::CheckField(const char* fieldName, T defValue, int tableIndex) const + { + T object; + + GetField(fieldName, tableIndex); + tableIndex += LuaImplQueryArg(*this, -1, &object, defValue, TypeTag()); + Pop(); + + return object; + } + + template + T LuaState::CheckField(const String& fieldName, T defValue, int tableIndex) const + { + return CheckField(fieldName.GetConstBuffer(), defValue, tableIndex); + } + + template + T LuaState::CheckGlobal(const char* fieldName) const + { + T object; + + GetGlobal(fieldName); + LuaImplQueryArg(*this, -1, &object, TypeTag()); + Pop(); + + return object; + } + + template + T LuaState::CheckGlobal(const String& fieldName) const + { + return CheckGlobal(fieldName.GetConstBuffer()); + } + + template + T LuaState::CheckGlobal(const char* fieldName, T defValue) const + { + T object; + + GetGlobal(fieldName); + LuaImplQueryArg(*this, -1, &object, defValue, TypeTag()); + Pop(); + + return object; + } + + template + T LuaState::CheckGlobal(const String& fieldName, T defValue) const + { + return CheckGlobal(fieldName.GetConstBuffer(), defValue); + } + + template + int LuaState::Push(T arg) const + { + return LuaImplReplyVal(*this, std::move(arg), TypeTag()); + } + + template + int LuaState::Push(T firstArg, T2 secondArg, Args... args) const + { + int valCount = 0; + valCount += Push(std::move(firstArg)); + valCount += Push(secondArg, std::forward(args)...); + + return valCount; + } + + template + void LuaState::PushField(const char* name, T&& arg, int tableIndex) const + { + Push(std::forward(arg)); + SetField(name, tableIndex); + } + + template + void LuaState::PushField(const String& name, T&& arg, int tableIndex) const + { + PushField(name.GetConstBuffer(), std::forward(arg), tableIndex); + } + + template + void LuaState::PushFunction(R(*func)(Args...), DefArgs&&... defArgs) const + { + typename LuaImplFunctionProxy::template Impl handler(std::forward(defArgs)...); + + PushFunction([func, handler] (LuaState& lua) -> int + { + handler.ProcessArguments(lua); + + return handler.Invoke(lua, func); + }); + } + + template + void LuaState::PushGlobal(const char* name, T&& arg) + { + Push(std::forward(arg)); + SetGlobal(name); + } + + template + void LuaState::PushGlobal(const String& name, T&& arg) + { + PushGlobal(name.GetConstBuffer(), std::forward(arg)); + } + + template + void LuaState::PushInstance(const char* tname, const T& instance) const + { + T* userdata = static_cast(PushUserdata(sizeof(T))); + PlacementNew(userdata, instance); + + SetMetatable(tname); + } + + template + void LuaState::PushInstance(const char* tname, T&& instance) const + { + T* userdata = static_cast(PushUserdata(sizeof(T))); + PlacementNew(userdata, std::move(instance)); + + SetMetatable(tname); + } + + template + void LuaState::PushInstance(const char* tname, Args&&... args) const + { + T* userdata = static_cast(PushUserdata(sizeof(T))); + PlacementNew(userdata, std::forward(args)...); + + SetMetatable(tname); + } + + template + T LuaState::CheckBounds(int index, long long value) const + { + constexpr long long minBounds = std::numeric_limits::min(); + constexpr long long maxBounds = std::numeric_limits::max(); + if (value < minBounds || value > maxBounds) + { + Nz::StringStream stream; + stream << "Argument #" << index << " is outside value range [" << minBounds << ", " << maxBounds << "] (" << value << ')'; + Error(stream); + } + + return static_cast(value); + } +} diff --git a/src/Nazara/Lua/LuaInstance.cpp b/src/Nazara/Lua/LuaInstance.cpp index 1c8f25567..607edc126 100644 --- a/src/Nazara/Lua/LuaInstance.cpp +++ b/src/Nazara/Lua/LuaInstance.cpp @@ -21,117 +21,16 @@ namespace Nz { namespace { - LuaType FromLuaType(int type) + int AtPanic(lua_State* internalState) { - switch (type) - { - case LUA_TBOOLEAN: - return LuaType_Boolean; - - case LUA_TFUNCTION: - return LuaType_Function; - - case LUA_TLIGHTUSERDATA: - return LuaType_LightUserdata; - - case LUA_TNIL: - return LuaType_Nil; - - case LUA_TNONE: - return LuaType_None; - - case LUA_TNUMBER: - return LuaType_Number; - - case LUA_TSTRING: - return LuaType_String; - - case LUA_TTABLE: - return LuaType_Table; - - case LUA_TTHREAD: - return LuaType_Thread; - - case LUA_TUSERDATA: - return LuaType_Userdata; - - default: - return LuaType_None; - } - } - - struct StreamData - { - Stream* stream; - char buffer[NAZARA_CORE_FILE_BUFFERSIZE]; - }; - - int AtPanic(lua_State* state) - { - String lastError(lua_tostring(state, -1)); + String lastError(lua_tostring(internalState, -1)); throw std::runtime_error("Lua panic: " + lastError); } - - const char* StreamReader(lua_State* state, void* data, std::size_t* size) - { - NazaraUnused(state); - - StreamData* streamData = static_cast(data); - - if (streamData->stream->EndOfStream()) - return nullptr; - else - { - *size = streamData->stream->Read(streamData->buffer, NAZARA_CORE_FILE_BUFFERSIZE); - return streamData->buffer; - } - } - - int s_comparisons[] = { - LUA_OPEQ, // LuaComparison_Equality - LUA_OPLT, // LuaComparison_Less - LUA_OPLE // LuaComparison_LessOrEqual - }; - - static_assert(sizeof(s_comparisons)/sizeof(int) == LuaComparison_Max+1, "Lua comparison array is incomplete"); - - int s_operations[] = { - LUA_OPADD, // LuaOperation_Addition - LUA_OPBAND, // LuaOperation_BitwiseAnd - LUA_OPSHL, // LuaOperation_BitwiseLeftShift - LUA_OPBNOT, // LuaOperation_BitwiseNot - LUA_OPBOR, // LuaOperation_BitwiseOr - LUA_OPSHR, // LuaOperation_BitwiseRightShift - LUA_OPBXOR, // LuaOperation_BitwiseXOr - LUA_OPDIV, // LuaOperation_Division - LUA_OPPOW, // LuaOperation_Exponentiation - LUA_OPIDIV, // LuaOperation_FloorDivision - LUA_OPMUL, // LuaOperation_Multiplication - LUA_OPMOD, // LuaOperation_Modulo - LUA_OPUNM, // LuaOperation_Negation - LUA_OPSUB // LuaOperation_Substraction - }; - - static_assert(sizeof(s_operations)/sizeof(int) == LuaOperation_Max+1, "Lua operation array is incomplete"); - - int s_types[] = { - LUA_TBOOLEAN, // LuaType_Boolean - LUA_TFUNCTION, // LuaType_Function - LUA_TLIGHTUSERDATA, // LuaType_LightUserdata - LUA_TNIL, // LuaType_Nil - LUA_TNUMBER, // LuaType_Number - LUA_TNONE, // LuaType_None - LUA_TSTRING, // LuaType_String - LUA_TTABLE, // LuaType_Table - LUA_TTHREAD, // LuaType_Thread - LUA_TUSERDATA // LuaType_Userdata - }; - - static_assert(sizeof(s_types)/sizeof(int) == LuaType_Max+1, "Lua type array is incomplete"); } LuaInstance::LuaInstance() : + LuaState(this, lua_newstate(MemoryAllocator, this)), m_memoryLimit(0), m_memoryUsage(0), m_timeLimit(1000), @@ -143,744 +42,12 @@ namespace Nz luaL_openlibs(m_state); } - LuaInstance::LuaInstance(LuaInstance&& instance) noexcept : - m_memoryLimit(instance.m_memoryLimit), - m_memoryUsage(instance.m_memoryUsage), - m_timeLimit(instance.m_timeLimit), - m_clock(std::move(instance.m_clock)), - m_lastError(std::move(instance.m_lastError)), - m_state(instance.m_state), - m_level(instance.m_level) - { - instance.m_state = nullptr; - - lua_setallocf(m_state, MemoryAllocator, this); - } - LuaInstance::~LuaInstance() { if (m_state) lua_close(m_state); } - void LuaInstance::ArgCheck(bool condition, unsigned int argNum, const char* error) const - { - luaL_argcheck(m_state, condition, argNum, error); - } - - void LuaInstance::ArgCheck(bool condition, unsigned int argNum, const String& error) const - { - luaL_argcheck(m_state, condition, argNum, error.GetConstBuffer()); - } - - int LuaInstance::ArgError(unsigned int argNum, const char* error) const - { - return luaL_argerror(m_state, argNum, error); - } - - int LuaInstance::ArgError(unsigned int argNum, const String& error) const - { - return luaL_argerror(m_state, argNum, error.GetConstBuffer()); - } - - bool LuaInstance::Call(unsigned int argCount) - { - return Run(argCount, LUA_MULTRET); - } - - bool LuaInstance::Call(unsigned int argCount, unsigned int resultCount) - { - return Run(argCount, resultCount); - } - - void LuaInstance::CheckAny(int index) const - { - luaL_checkany(m_state, index); - } - - bool LuaInstance::CheckBoolean(int index) const - { - if (lua_isnoneornil(m_state, index)) - { - const char* msg = lua_pushfstring(m_state, "%s expected, got %s", lua_typename(m_state, LUA_TBOOLEAN), luaL_typename(m_state, index)); - luaL_argerror(m_state, index, msg); // Lance une exception - return false; - } - - return lua_toboolean(m_state, index) != 0; - } - - bool LuaInstance::CheckBoolean(int index, bool defValue) const - { - if (lua_isnoneornil(m_state, index)) - return defValue; - - return lua_toboolean(m_state, index) != 0; - } - - long long LuaInstance::CheckInteger(int index) const - { - return luaL_checkinteger(m_state, index); - } - - long long LuaInstance::CheckInteger(int index, long long defValue) const - { - return luaL_optinteger(m_state, index, defValue); - } - - double LuaInstance::CheckNumber(int index) const - { - return luaL_checknumber(m_state, index); - } - - double LuaInstance::CheckNumber(int index, double defValue) const - { - return luaL_optnumber(m_state, index, defValue); - } - - void LuaInstance::CheckStack(int space, const char* error) const - { - luaL_checkstack(m_state, space, error); - } - - void LuaInstance::CheckStack(int space, const String& error) const - { - CheckStack(space, error.GetConstBuffer()); - } - - const char* LuaInstance::CheckString(int index, std::size_t* length) const - { - return luaL_checklstring(m_state, index, length); - } - - const char* LuaInstance::CheckString(int index, const char* defValue, std::size_t* length) const - { - return luaL_optlstring(m_state, index, defValue, length); - } - - void LuaInstance::CheckType(int index, LuaType type) const - { - #ifdef NAZARA_DEBUG - if (type > LuaType_Max) - { - NazaraError("Lua type out of enum"); - return; - } - #endif - - luaL_checktype(m_state, index, s_types[type]); - } - - void* LuaInstance::CheckUserdata(int index, const char* tname) const - { - return luaL_checkudata(m_state, index, tname); - } - - void* LuaInstance::CheckUserdata(int index, const String& tname) const - { - return luaL_checkudata(m_state, index, tname.GetConstBuffer()); - } - - bool LuaInstance::Compare(int index1, int index2, LuaComparison comparison) const - { - #ifdef NAZARA_DEBUG - if (comparison > LuaComparison_Max) - { - NazaraError("Lua comparison out of enum"); - return false; - } - #endif - - return (lua_compare(m_state, index1, index2, s_comparisons[comparison]) != 0); - } - - void LuaInstance::Compute(LuaOperation operation) const - { - #ifdef NAZARA_DEBUG - if (operation > LuaOperation_Max) - { - NazaraError("Lua operation out of enum"); - return; - } - #endif - - lua_arith(m_state, s_operations[operation]); - } - - void LuaInstance::Concatenate(int count) const - { - lua_concat(m_state, count); - } - - int LuaInstance::CreateReference() - { - return luaL_ref(m_state, LUA_REGISTRYINDEX); - } - - void LuaInstance::DestroyReference(int ref) - { - luaL_unref(m_state, LUA_REGISTRYINDEX, ref); - } - - String LuaInstance::DumpStack() const - { - StringStream stream; - unsigned int stackTop = GetStackTop(); - stream << stackTop << " entries\n"; - - for (unsigned int i = 1; i <= stackTop; ++i) - { - stream << i << ": "; - switch (GetType(i)) - { - case LuaType_Boolean: - stream << "Boolean(" << ToBoolean(i) << ')'; - break; - - case LuaType_Function: - stream << "Function(" << ToPointer(i) << ')'; - break; - - case LuaType_LightUserdata: - case LuaType_Userdata: - stream << "Userdata(" << ToUserdata(i) << ')'; - break; - - case LuaType_Nil: - stream << "Nil"; - break; - - case LuaType_None: - stream << "None"; - break; - - case LuaType_Number: - stream << "Number(" << ToNumber(i) << ')'; - break; - - case LuaType_String: - stream << "String(" << ToString(i) << ')'; - break; - - case LuaType_Table: - stream << "Table(" << ToPointer(i) << ')'; - break; - - case LuaType_Thread: - stream << "Thread(" << ToPointer(i) << ')'; - break; - - default: - stream << "Unknown(" << ToPointer(i) << ')'; - break; - } - - stream << '\n'; - } - - return stream.ToString(); - } - - void LuaInstance::Error(const char* message) const - { - luaL_error(m_state, message); - } - - void LuaInstance::Error(const String& message) const - { - luaL_error(m_state, message.GetConstBuffer()); - } - - bool LuaInstance::Execute(const String& code) - { - if (code.IsEmpty()) - return true; - - if (luaL_loadstring(m_state, code.GetConstBuffer()) != 0) - { - m_lastError = lua_tostring(m_state, -1); - lua_pop(m_state, 1); - - return false; - } - - return Run(0, 0); - } - - bool LuaInstance::ExecuteFromFile(const String& filePath) - { - File file(filePath); - if (!file.Open(OpenMode_ReadOnly | OpenMode_Text)) - { - NazaraError("Failed to open file"); - return false; - } - - std::size_t length = static_cast(file.GetSize()); - - String source(length, '\0'); - - if (file.Read(&source[0], length) != length) - { - NazaraError("Failed to read file"); - return false; - } - - file.Close(); - - return Execute(source); - } - - bool LuaInstance::ExecuteFromMemory(const void* data, std::size_t size) - { - MemoryView stream(data, size); - return ExecuteFromStream(stream); - } - - bool LuaInstance::ExecuteFromStream(Stream& stream) - { - StreamData data; - data.stream = &stream; - - if (lua_load(m_state, StreamReader, &data, "C++", nullptr) != 0) - { - m_lastError = lua_tostring(m_state, -1); - lua_pop(m_state, 1); - - return false; - } - - return Run(0, 0); - } - - int LuaInstance::GetAbsIndex(int index) const - { - return lua_absindex(m_state, index); - } - - LuaType LuaInstance::GetField(const char* fieldName, int tableIndex) const - { - return FromLuaType(lua_getfield(m_state, tableIndex, fieldName)); - } - - LuaType LuaInstance::GetField(const String& fieldName, int tableIndex) const - { - return FromLuaType(lua_getfield(m_state, tableIndex, fieldName.GetConstBuffer())); - } - - LuaType LuaInstance::GetGlobal(const char* name) const - { - return FromLuaType(lua_getglobal(m_state, name)); - } - - LuaType LuaInstance::GetGlobal(const String& name) const - { - return FromLuaType(lua_getglobal(m_state, name.GetConstBuffer())); - } - - LuaType LuaInstance::GetMetatable(const char* tname) const - { - return FromLuaType(luaL_getmetatable(m_state, tname)); - } - - LuaType LuaInstance::GetMetatable(const String& tname) const - { - return FromLuaType(luaL_getmetatable(m_state, tname.GetConstBuffer())); - } - - bool LuaInstance::GetMetatable(int index) const - { - return lua_getmetatable(m_state, index) != 0; - } - - unsigned int LuaInstance::GetStackTop() const - { - return static_cast(lua_gettop(m_state)); - } - - LuaType LuaInstance::GetTable(int index) const - { - return FromLuaType(lua_gettable(m_state, index)); - } - - LuaType LuaInstance::GetTableRaw(int index) const - { - return FromLuaType(lua_rawget(m_state, index)); - } - - LuaType LuaInstance::GetType(int index) const - { - return FromLuaType(lua_type(m_state, index)); - } - - const char* LuaInstance::GetTypeName(LuaType type) const - { - #ifdef NAZARA_DEBUG - if (type > LuaType_Max) - { - NazaraError("Lua type out of enum"); - return nullptr; - } - #endif - - return lua_typename(m_state, s_types[type]); - } - - void LuaInstance::Insert(int index) const - { - lua_insert(m_state, index); - } - - bool LuaInstance::IsOfType(int index, LuaType type) const - { - switch (type) - { - case LuaType_Boolean: - return lua_isboolean(m_state, index) != 0; - - case LuaType_Function: - return lua_isfunction(m_state, index) != 0; - - case LuaType_LightUserdata: - return lua_islightuserdata(m_state, index) != 0; - - case LuaType_Nil: - return lua_isnil(m_state, index) != 0; - - case LuaType_None: - return lua_isnone(m_state, index) != 0; - - case LuaType_Number: - return lua_isnumber(m_state, index) != 0; - - case LuaType_String: - return lua_isstring(m_state, index) != 0; - - case LuaType_Table: - return lua_istable(m_state, index) != 0; - - case LuaType_Thread: - return lua_isthread(m_state, index) != 0; - - case LuaType_Userdata: - return lua_isuserdata(m_state, index) != 0; - } - - NazaraError("Lua type not handled (0x" + String::Number(type, 16) + ')'); - return false; - } - - bool LuaInstance::IsOfType(int index, const char* tname) const - { - void* ud = luaL_testudata(m_state, index, tname); - return ud != nullptr; - } - - bool LuaInstance::IsOfType(int index, const String& tname) const - { - return IsOfType(index, tname.GetConstBuffer()); - } - - bool LuaInstance::IsValid(int index) const - { - return lua_isnoneornil(m_state, index) == 0; - } - - long long LuaInstance::Length(int index) const - { - return luaL_len(m_state, index); - } - - std::size_t LuaInstance::LengthRaw(int index) const - { - return lua_rawlen(m_state, index); - } - - void LuaInstance::MoveTo(LuaInstance* instance, int n) const - { - lua_xmove(m_state, instance->m_state, n); - } - - bool LuaInstance::NewMetatable(const char* str) - { - return luaL_newmetatable(m_state, str) != 0; - } - - bool LuaInstance::NewMetatable(const String& str) - { - return luaL_newmetatable(m_state, str.GetConstBuffer()) != 0; - } - - bool LuaInstance::Next(int index) const - { - return lua_next(m_state, index) != 0; - } - - void LuaInstance::Pop(unsigned int n) const - { - lua_pop(m_state, static_cast(n)); - } - - void LuaInstance::PushBoolean(bool value) const - { - lua_pushboolean(m_state, (value) ? 1 : 0); - } - - void LuaInstance::PushCFunction(LuaCFunction func, unsigned int upvalueCount) const - { - lua_pushcclosure(m_state, func, upvalueCount); - } - - void LuaInstance::PushFunction(LuaFunction func) const - { - LuaFunction* luaFunc = static_cast(lua_newuserdata(m_state, sizeof(LuaFunction))); - PlacementNew(luaFunc, std::move(func)); - - lua_pushcclosure(m_state, ProxyFunc, 1); - } - - void LuaInstance::PushInteger(long long value) const - { - lua_pushinteger(m_state, value); - } - - void LuaInstance::PushLightUserdata(void* value) const - { - lua_pushlightuserdata(m_state, value); - } - - void LuaInstance::PushMetatable(const char* str) const - { - luaL_getmetatable(m_state, str); - } - - void LuaInstance::PushMetatable(const String& str) const - { - luaL_getmetatable(m_state, str.GetConstBuffer()); - } - - void LuaInstance::PushNil() const - { - lua_pushnil(m_state); - } - - void LuaInstance::PushNumber(double value) const - { - lua_pushnumber(m_state, value); - } - - void LuaInstance::PushReference(int ref) const - { - lua_rawgeti(m_state, LUA_REGISTRYINDEX, ref); - } - - void LuaInstance::PushString(const char* str) const - { - lua_pushstring(m_state, str); - } - - void LuaInstance::PushString(const char* str, std::size_t size) const - { - lua_pushlstring(m_state, str, size); - } - - void LuaInstance::PushString(const String& str) const - { - lua_pushlstring(m_state, str.GetConstBuffer(), str.GetSize()); - } - - void LuaInstance::PushTable(std::size_t sequenceElementCount, std::size_t arrayElementCount) const - { - constexpr std::size_t maxInt = std::numeric_limits::max(); - lua_createtable(m_state, static_cast(std::min(sequenceElementCount, maxInt)), static_cast(std::min(arrayElementCount, maxInt))); - } - - void* LuaInstance::PushUserdata(std::size_t size) const - { - return lua_newuserdata(m_state, size); - } - - void LuaInstance::PushValue(int index) const - { - lua_pushvalue(m_state, index); - } - - void LuaInstance::Remove(int index) const - { - lua_remove(m_state, index); - } - - void LuaInstance::Replace(int index) const - { - lua_replace(m_state, index); - } - - void LuaInstance::SetField(const char* name, int tableIndex) const - { - lua_setfield(m_state, tableIndex, name); - } - - void LuaInstance::SetField(const String& name, int tableIndex) const - { - lua_setfield(m_state, tableIndex, name.GetConstBuffer()); - } - - void LuaInstance::SetGlobal(const char* name) - { - lua_setglobal(m_state, name); - } - - void LuaInstance::SetGlobal(const String& name) - { - lua_setglobal(m_state, name.GetConstBuffer()); - } - - void LuaInstance::SetMetatable(const char* tname) const - { - luaL_setmetatable(m_state, tname); - } - - void LuaInstance::SetMetatable(const String& tname) const - { - luaL_setmetatable(m_state, tname.GetConstBuffer()); - } - - void LuaInstance::SetMetatable(int index) const - { - lua_setmetatable(m_state, index); - } - - void LuaInstance::SetMemoryLimit(std::size_t memoryLimit) - { - m_memoryLimit = memoryLimit; - } - - void LuaInstance::SetTable(int index) const - { - lua_settable(m_state, index); - } - - void LuaInstance::SetTableRaw(int index) const - { - lua_rawset(m_state, index); - } - - void LuaInstance::SetTimeLimit(UInt32 timeLimit) - { - if (m_timeLimit != timeLimit) - { - if (m_timeLimit == 0) - lua_sethook(m_state, TimeLimiter, LUA_MASKCOUNT, 1000); - else if (timeLimit == 0) - lua_sethook(m_state, TimeLimiter, 0, 1000); - - m_timeLimit = timeLimit; - } - } - - bool LuaInstance::ToBoolean(int index) const - { - return lua_toboolean(m_state, index) != 0; - } - - long long LuaInstance::ToInteger(int index, bool* succeeded) const - { - int success; - long long result = lua_tointegerx(m_state, index, &success); - - if (succeeded) - *succeeded = (success != 0); - - return result; - } - - double LuaInstance::ToNumber(int index, bool* succeeded) const - { - int success; - double result = lua_tonumberx(m_state, index, &success); - - if (succeeded) - *succeeded = (success != 0); - - return result; - } - - const void* LuaInstance::ToPointer(int index) const - { - return lua_topointer(m_state, index); - } - - const char* LuaInstance::ToString(int index, std::size_t* length) const - { - return lua_tolstring(m_state, index, length); - } - - void* LuaInstance::ToUserdata(int index) const - { - return lua_touserdata(m_state, index); - } - - void* LuaInstance::ToUserdata(int index, const char* tname) const - { - return luaL_testudata(m_state, index, tname); - } - - void* LuaInstance::ToUserdata(int index, const String& tname) const - { - return luaL_testudata(m_state, index, tname.GetConstBuffer()); - } - - LuaInstance& LuaInstance::operator=(LuaInstance&& instance) noexcept - { - m_clock = std::move(instance.m_clock); - m_lastError = std::move(instance.m_lastError); - m_level = instance.m_level; - m_memoryLimit = instance.m_memoryLimit; - m_memoryUsage = instance.m_memoryUsage; - m_state = instance.m_state; - m_timeLimit = instance.m_timeLimit; - - instance.m_state = nullptr; - - // Update allocator pointer - lua_setallocf(m_state, MemoryAllocator, this); - - return *this; - } - - int LuaInstance::GetIndexOfUpValue(int upValue) - { - return lua_upvalueindex(upValue); - } - - LuaInstance* LuaInstance::GetInstance(lua_State* state) - { - LuaInstance* instance; - lua_getallocf(state, reinterpret_cast(&instance)); - - return instance; - } - - bool LuaInstance::Run(int argCount, int resultCount) - { - if (m_level++ == 0) - m_clock.Restart(); - - int status = lua_pcall(m_state, argCount, resultCount, 0); - - m_level--; - - if (status != 0) - { - m_lastError = lua_tostring(m_state, -1); - lua_pop(m_state, 1); - - return false; - } - - return true; - } - void* LuaInstance::MemoryAllocator(void* ud, void* ptr, std::size_t osize, std::size_t nsize) { LuaInstance* instance = static_cast(ud); @@ -912,18 +79,14 @@ namespace Nz } } - int LuaInstance::ProxyFunc(lua_State* state) - { - LuaFunction& func = *static_cast(lua_touserdata(state, lua_upvalueindex(1))); - return func(*GetInstance(state)); - } - - void LuaInstance::TimeLimiter(lua_State* state, lua_Debug* debug) + void LuaInstance::TimeLimiter(lua_State* internalState, lua_Debug* debug) { NazaraUnused(debug); - LuaInstance* instance = GetInstance(state); + LuaInstance* instance; + lua_getallocf(internalState, reinterpret_cast(&instance)); + if (instance->m_clock.GetMilliseconds() > instance->m_timeLimit) - luaL_error(state, "maximum execution time exceeded"); + luaL_error(internalState, "maximum execution time exceeded"); } } diff --git a/src/Nazara/Lua/LuaState.cpp b/src/Nazara/Lua/LuaState.cpp new file mode 100644 index 000000000..f71504ab7 --- /dev/null +++ b/src/Nazara/Lua/LuaState.cpp @@ -0,0 +1,834 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace + { + LuaType FromLuaType(int type) + { + switch (type) + { + case LUA_TBOOLEAN: + return LuaType_Boolean; + + case LUA_TFUNCTION: + return LuaType_Function; + + case LUA_TLIGHTUSERDATA: + return LuaType_LightUserdata; + + case LUA_TNIL: + return LuaType_Nil; + + case LUA_TNONE: + return LuaType_None; + + case LUA_TNUMBER: + return LuaType_Number; + + case LUA_TSTRING: + return LuaType_String; + + case LUA_TTABLE: + return LuaType_Table; + + case LUA_TTHREAD: + return LuaType_Thread; + + case LUA_TUSERDATA: + return LuaType_Userdata; + + default: + return LuaType_None; + } + } + + struct StreamData + { + Stream* stream; + char buffer[NAZARA_CORE_FILE_BUFFERSIZE]; + }; + + const char* StreamReader(lua_State* internalState, void* data, std::size_t* size) + { + NazaraUnused(internalState); + + StreamData* streamData = static_cast(data); + + if (streamData->stream->EndOfStream()) + return nullptr; + else + { + *size = streamData->stream->Read(streamData->buffer, NAZARA_CORE_FILE_BUFFERSIZE); + return streamData->buffer; + } + } + + int s_comparisons[] = { + LUA_OPEQ, // LuaComparison_Equality + LUA_OPLT, // LuaComparison_Less + LUA_OPLE // LuaComparison_LessOrEqual + }; + + static_assert(sizeof(s_comparisons)/sizeof(int) == LuaComparison_Max+1, "Lua comparison array is incomplete"); + + int s_operations[] = { + LUA_OPADD, // LuaOperation_Addition + LUA_OPBAND, // LuaOperation_BitwiseAnd + LUA_OPSHL, // LuaOperation_BitwiseLeftShift + LUA_OPBNOT, // LuaOperation_BitwiseNot + LUA_OPBOR, // LuaOperation_BitwiseOr + LUA_OPSHR, // LuaOperation_BitwiseRightShift + LUA_OPBXOR, // LuaOperation_BitwiseXOr + LUA_OPDIV, // LuaOperation_Division + LUA_OPPOW, // LuaOperation_Exponentiation + LUA_OPIDIV, // LuaOperation_FloorDivision + LUA_OPMUL, // LuaOperation_Multiplication + LUA_OPMOD, // LuaOperation_Modulo + LUA_OPUNM, // LuaOperation_Negation + LUA_OPSUB // LuaOperation_Substraction + }; + + static_assert(sizeof(s_operations)/sizeof(int) == LuaOperation_Max+1, "Lua operation array is incomplete"); + + int s_types[] = { + LUA_TBOOLEAN, // LuaType_Boolean + LUA_TFUNCTION, // LuaType_Function + LUA_TLIGHTUSERDATA, // LuaType_LightUserdata + LUA_TNIL, // LuaType_Nil + LUA_TNUMBER, // LuaType_Number + LUA_TNONE, // LuaType_None + LUA_TSTRING, // LuaType_String + LUA_TTABLE, // LuaType_Table + LUA_TTHREAD, // LuaType_Thread + LUA_TUSERDATA // LuaType_Userdata + }; + + static_assert(sizeof(s_types)/sizeof(int) == LuaType_Max+1, "Lua type array is incomplete"); + } + + LuaState::LuaState(LuaState&& state) noexcept : + m_lastError(state.m_lastError), + m_instance(state.m_instance), + m_state(state.m_state) + { + } + + void LuaState::ArgCheck(bool condition, unsigned int argNum, const char* error) const + { + luaL_argcheck(m_state, condition, argNum, error); + } + + void LuaState::ArgCheck(bool condition, unsigned int argNum, const String& error) const + { + luaL_argcheck(m_state, condition, argNum, error.GetConstBuffer()); + } + + int LuaState::ArgError(unsigned int argNum, const char* error) const + { + return luaL_argerror(m_state, argNum, error); + } + + int LuaState::ArgError(unsigned int argNum, const String& error) const + { + return luaL_argerror(m_state, argNum, error.GetConstBuffer()); + } + + bool LuaState::Call(unsigned int argCount) + { + return Run(argCount, LUA_MULTRET); + } + + bool LuaState::Call(unsigned int argCount, unsigned int resultCount) + { + return Run(argCount, resultCount); + } + + void LuaState::CheckAny(int index) const + { + luaL_checkany(m_state, index); + } + + bool LuaState::CheckBoolean(int index) const + { + if (lua_isnoneornil(m_state, index)) + { + const char* msg = lua_pushfstring(m_state, "%s expected, got %s", lua_typename(m_state, LUA_TBOOLEAN), luaL_typename(m_state, index)); + luaL_argerror(m_state, index, msg); // Lance une exception + return false; + } + + return lua_toboolean(m_state, index) != 0; + } + + bool LuaState::CheckBoolean(int index, bool defValue) const + { + if (lua_isnoneornil(m_state, index)) + return defValue; + + return lua_toboolean(m_state, index) != 0; + } + + long long LuaState::CheckInteger(int index) const + { + return luaL_checkinteger(m_state, index); + } + + long long LuaState::CheckInteger(int index, long long defValue) const + { + return luaL_optinteger(m_state, index, defValue); + } + + double LuaState::CheckNumber(int index) const + { + return luaL_checknumber(m_state, index); + } + + double LuaState::CheckNumber(int index, double defValue) const + { + return luaL_optnumber(m_state, index, defValue); + } + + void LuaState::CheckStack(int space, const char* error) const + { + luaL_checkstack(m_state, space, error); + } + + void LuaState::CheckStack(int space, const String& error) const + { + CheckStack(space, error.GetConstBuffer()); + } + + const char* LuaState::CheckString(int index, std::size_t* length) const + { + return luaL_checklstring(m_state, index, length); + } + + const char* LuaState::CheckString(int index, const char* defValue, std::size_t* length) const + { + return luaL_optlstring(m_state, index, defValue, length); + } + + void LuaState::CheckType(int index, LuaType type) const + { + #ifdef NAZARA_DEBUG + if (type > LuaType_Max) + { + NazaraError("Lua type out of enum"); + return; + } + #endif + + luaL_checktype(m_state, index, s_types[type]); + } + + void* LuaState::CheckUserdata(int index, const char* tname) const + { + return luaL_checkudata(m_state, index, tname); + } + + void* LuaState::CheckUserdata(int index, const String& tname) const + { + return luaL_checkudata(m_state, index, tname.GetConstBuffer()); + } + + bool LuaState::Compare(int index1, int index2, LuaComparison comparison) const + { + #ifdef NAZARA_DEBUG + if (comparison > LuaComparison_Max) + { + NazaraError("Lua comparison out of enum"); + return false; + } + #endif + + return (lua_compare(m_state, index1, index2, s_comparisons[comparison]) != 0); + } + + void LuaState::Compute(LuaOperation operation) const + { + #ifdef NAZARA_DEBUG + if (operation > LuaOperation_Max) + { + NazaraError("Lua operation out of enum"); + return; + } + #endif + + lua_arith(m_state, s_operations[operation]); + } + + void LuaState::Concatenate(int count) const + { + lua_concat(m_state, count); + } + + int LuaState::CreateReference() + { + return luaL_ref(m_state, LUA_REGISTRYINDEX); + } + + void LuaState::DestroyReference(int ref) + { + luaL_unref(m_state, LUA_REGISTRYINDEX, ref); + } + + String LuaState::DumpStack() const + { + StringStream stream; + unsigned int stackTop = GetStackTop(); + stream << stackTop << " entries\n"; + + for (unsigned int i = 1; i <= stackTop; ++i) + { + stream << i << ": "; + switch (GetType(i)) + { + case LuaType_Boolean: + stream << "Boolean(" << ToBoolean(i) << ')'; + break; + + case LuaType_Function: + stream << "Function(" << ToPointer(i) << ')'; + break; + + case LuaType_LightUserdata: + case LuaType_Userdata: + stream << "Userdata(" << ToUserdata(i) << ')'; + break; + + case LuaType_Nil: + stream << "Nil"; + break; + + case LuaType_None: + stream << "None"; + break; + + case LuaType_Number: + stream << "Number(" << ToNumber(i) << ')'; + break; + + case LuaType_String: + stream << "String(" << ToString(i) << ')'; + break; + + case LuaType_Table: + stream << "Table(" << ToPointer(i) << ')'; + break; + + case LuaType_Thread: + stream << "Thread(" << ToPointer(i) << ')'; + break; + + default: + stream << "Unknown(" << ToPointer(i) << ')'; + break; + } + + stream << '\n'; + } + + return stream.ToString(); + } + + void LuaState::Error(const char* message) const + { + luaL_error(m_state, message); + } + + void LuaState::Error(const String& message) const + { + luaL_error(m_state, message.GetConstBuffer()); + } + + bool LuaState::Execute(const String& code) + { + if (code.IsEmpty()) + return true; + + if (luaL_loadstring(m_state, code.GetConstBuffer()) != 0) + { + m_lastError = lua_tostring(m_state, -1); + lua_pop(m_state, 1); + + return false; + } + + return Run(0, 0); + } + + bool LuaState::ExecuteFromFile(const String& filePath) + { + File file(filePath); + if (!file.Open(OpenMode_ReadOnly | OpenMode_Text)) + { + NazaraError("Failed to open file"); + return false; + } + + std::size_t length = static_cast(file.GetSize()); + + String source(length, '\0'); + + if (file.Read(&source[0], length) != length) + { + NazaraError("Failed to read file"); + return false; + } + + file.Close(); + + return Execute(source); + } + + bool LuaState::ExecuteFromMemory(const void* data, std::size_t size) + { + MemoryView stream(data, size); + return ExecuteFromStream(stream); + } + + bool LuaState::ExecuteFromStream(Stream& stream) + { + StreamData data; + data.stream = &stream; + + if (lua_load(m_state, StreamReader, &data, "C++", nullptr) != 0) + { + m_lastError = lua_tostring(m_state, -1); + lua_pop(m_state, 1); + + return false; + } + + return Run(0, 0); + } + + int LuaState::GetAbsIndex(int index) const + { + return lua_absindex(m_state, index); + } + + LuaType LuaState::GetField(const char* fieldName, int tableIndex) const + { + return FromLuaType(lua_getfield(m_state, tableIndex, fieldName)); + } + + LuaType LuaState::GetField(const String& fieldName, int tableIndex) const + { + return FromLuaType(lua_getfield(m_state, tableIndex, fieldName.GetConstBuffer())); + } + + LuaType LuaState::GetGlobal(const char* name) const + { + return FromLuaType(lua_getglobal(m_state, name)); + } + + LuaType LuaState::GetGlobal(const String& name) const + { + return FromLuaType(lua_getglobal(m_state, name.GetConstBuffer())); + } + + LuaType LuaState::GetMetatable(const char* tname) const + { + return FromLuaType(luaL_getmetatable(m_state, tname)); + } + + LuaType LuaState::GetMetatable(const String& tname) const + { + return FromLuaType(luaL_getmetatable(m_state, tname.GetConstBuffer())); + } + + bool LuaState::GetMetatable(int index) const + { + return lua_getmetatable(m_state, index) != 0; + } + + unsigned int LuaState::GetStackTop() const + { + return static_cast(lua_gettop(m_state)); + } + + LuaType LuaState::GetTable(int index) const + { + return FromLuaType(lua_gettable(m_state, index)); + } + + LuaType LuaState::GetTableRaw(int index) const + { + return FromLuaType(lua_rawget(m_state, index)); + } + + LuaType LuaState::GetType(int index) const + { + return FromLuaType(lua_type(m_state, index)); + } + + const char* LuaState::GetTypeName(LuaType type) const + { + #ifdef NAZARA_DEBUG + if (type > LuaType_Max) + { + NazaraError("Lua type out of enum"); + return nullptr; + } + #endif + + return lua_typename(m_state, s_types[type]); + } + + void LuaState::Insert(int index) const + { + lua_insert(m_state, index); + } + + bool LuaState::IsOfType(int index, LuaType type) const + { + switch (type) + { + case LuaType_Boolean: + return lua_isboolean(m_state, index) != 0; + + case LuaType_Function: + return lua_isfunction(m_state, index) != 0; + + case LuaType_LightUserdata: + return lua_islightuserdata(m_state, index) != 0; + + case LuaType_Nil: + return lua_isnil(m_state, index) != 0; + + case LuaType_None: + return lua_isnone(m_state, index) != 0; + + case LuaType_Number: + return lua_isnumber(m_state, index) != 0; + + case LuaType_String: + return lua_isstring(m_state, index) != 0; + + case LuaType_Table: + return lua_istable(m_state, index) != 0; + + case LuaType_Thread: + return lua_isthread(m_state, index) != 0; + + case LuaType_Userdata: + return lua_isuserdata(m_state, index) != 0; + } + + NazaraError("Lua type not handled (0x" + String::Number(type, 16) + ')'); + return false; + } + + bool LuaState::IsOfType(int index, const char* tname) const + { + void* ud = luaL_testudata(m_state, index, tname); + return ud != nullptr; + } + + bool LuaState::IsOfType(int index, const String& tname) const + { + return IsOfType(index, tname.GetConstBuffer()); + } + + bool LuaState::IsValid(int index) const + { + return lua_isnoneornil(m_state, index) == 0; + } + + long long LuaState::Length(int index) const + { + return luaL_len(m_state, index); + } + + std::size_t LuaState::LengthRaw(int index) const + { + return lua_rawlen(m_state, index); + } + + void LuaState::MoveTo(LuaState* instance, int n) const + { + lua_xmove(m_state, instance->m_state, n); + } + + bool LuaState::NewMetatable(const char* str) + { + return luaL_newmetatable(m_state, str) != 0; + } + + bool LuaState::NewMetatable(const String& str) + { + return luaL_newmetatable(m_state, str.GetConstBuffer()) != 0; + } + + bool LuaState::Next(int index) const + { + return lua_next(m_state, index) != 0; + } + + void LuaState::Pop(unsigned int n) const + { + lua_pop(m_state, static_cast(n)); + } + + void LuaState::PushBoolean(bool value) const + { + lua_pushboolean(m_state, (value) ? 1 : 0); + } + + void LuaState::PushCFunction(LuaCFunction func, unsigned int upvalueCount) const + { + lua_pushcclosure(m_state, func, upvalueCount); + } + + void LuaState::PushFunction(LuaFunction func) const + { + LuaFunction* luaFunc = static_cast(lua_newuserdata(m_state, sizeof(LuaFunction))); + PlacementNew(luaFunc, std::move(func)); + + lua_pushcclosure(m_state, ProxyFunc, 1); + } + + void LuaState::PushInteger(long long value) const + { + lua_pushinteger(m_state, value); + } + + void LuaState::PushLightUserdata(void* value) const + { + lua_pushlightuserdata(m_state, value); + } + + void LuaState::PushMetatable(const char* str) const + { + luaL_getmetatable(m_state, str); + } + + void LuaState::PushMetatable(const String& str) const + { + luaL_getmetatable(m_state, str.GetConstBuffer()); + } + + void LuaState::PushNil() const + { + lua_pushnil(m_state); + } + + void LuaState::PushNumber(double value) const + { + lua_pushnumber(m_state, value); + } + + void LuaState::PushReference(int ref) const + { + lua_rawgeti(m_state, LUA_REGISTRYINDEX, ref); + } + + void LuaState::PushString(const char* str) const + { + lua_pushstring(m_state, str); + } + + void LuaState::PushString(const char* str, std::size_t size) const + { + lua_pushlstring(m_state, str, size); + } + + void LuaState::PushString(const String& str) const + { + lua_pushlstring(m_state, str.GetConstBuffer(), str.GetSize()); + } + + void LuaState::PushTable(std::size_t sequenceElementCount, std::size_t arrayElementCount) const + { + constexpr std::size_t maxInt = std::numeric_limits::max(); + lua_createtable(m_state, static_cast(std::min(sequenceElementCount, maxInt)), static_cast(std::min(arrayElementCount, maxInt))); + } + + void* LuaState::PushUserdata(std::size_t size) const + { + return lua_newuserdata(m_state, size); + } + + void LuaState::PushValue(int index) const + { + lua_pushvalue(m_state, index); + } + + void LuaState::Remove(int index) const + { + lua_remove(m_state, index); + } + + void LuaState::Replace(int index) const + { + lua_replace(m_state, index); + } + + void LuaState::SetField(const char* name, int tableIndex) const + { + lua_setfield(m_state, tableIndex, name); + } + + void LuaState::SetField(const String& name, int tableIndex) const + { + lua_setfield(m_state, tableIndex, name.GetConstBuffer()); + } + + void LuaState::SetGlobal(const char* name) + { + lua_setglobal(m_state, name); + } + + void LuaState::SetGlobal(const String& name) + { + lua_setglobal(m_state, name.GetConstBuffer()); + } + + void LuaState::SetMetatable(const char* tname) const + { + luaL_setmetatable(m_state, tname); + } + + void LuaState::SetMetatable(const String& tname) const + { + luaL_setmetatable(m_state, tname.GetConstBuffer()); + } + + void LuaState::SetMetatable(int index) const + { + lua_setmetatable(m_state, index); + } + + void LuaState::SetTable(int index) const + { + lua_settable(m_state, index); + } + + void LuaState::SetTableRaw(int index) const + { + lua_rawset(m_state, index); + } + + bool LuaState::ToBoolean(int index) const + { + return lua_toboolean(m_state, index) != 0; + } + + long long LuaState::ToInteger(int index, bool* succeeded) const + { + int success; + long long result = lua_tointegerx(m_state, index, &success); + + if (succeeded) + *succeeded = (success != 0); + + return result; + } + + double LuaState::ToNumber(int index, bool* succeeded) const + { + int success; + double result = lua_tonumberx(m_state, index, &success); + + if (succeeded) + *succeeded = (success != 0); + + return result; + } + + const void* LuaState::ToPointer(int index) const + { + return lua_topointer(m_state, index); + } + + const char* LuaState::ToString(int index, std::size_t* length) const + { + return lua_tolstring(m_state, index, length); + } + + void* LuaState::ToUserdata(int index) const + { + return lua_touserdata(m_state, index); + } + + void* LuaState::ToUserdata(int index, const char* tname) const + { + return luaL_testudata(m_state, index, tname); + } + + void* LuaState::ToUserdata(int index, const String& tname) const + { + return luaL_testudata(m_state, index, tname.GetConstBuffer()); + } + + LuaState& LuaState::operator=(LuaState&& state) noexcept + { + m_instance = state.m_instance; + m_lastError = std::move(state.m_lastError); + m_state = state.m_state; + + return *this; + } + + bool LuaState::Run(int argCount, int resultCount) + { + if (m_instance->m_level++ == 0) + m_instance->m_clock.Restart(); + + int status = lua_pcall(m_state, argCount, resultCount, 0); + + m_instance->m_level--; + + if (status != 0) + { + m_lastError = lua_tostring(m_state, -1); + lua_pop(m_state, 1); + + return false; + } + + return true; + } + + int LuaState::GetIndexOfUpValue(int upValue) + { + return lua_upvalueindex(upValue); + } + + LuaState LuaState::GetState(lua_State* internalState) + { + LuaInstance* instance; + lua_getallocf(internalState, reinterpret_cast(&instance)); + + return LuaState(instance, internalState); + } + + int LuaState::ProxyFunc(lua_State* internalState) + { + LuaFunction& func = *static_cast(lua_touserdata(internalState, lua_upvalueindex(1))); + LuaState state = GetState(internalState); + + return func(state); + } + +} From 01edc4fb218d670e1c561ef1f354cd5b794abef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 8 Jun 2017 15:53:17 +0200 Subject: [PATCH 68/73] Add coroutine support (WIP) --- include/Nazara/Lua/LuaCoroutine.hpp | 44 +++++++++++++++++++++++ include/Nazara/Lua/LuaCoroutine.inl | 25 +++++++++++++ include/Nazara/Lua/LuaInstance.hpp | 1 + include/Nazara/Lua/LuaState.hpp | 12 +++---- include/Nazara/Lua/LuaState.inl | 8 +++-- src/Nazara/Lua/LuaCoroutine.cpp | 55 +++++++++++++++++++++++++++++ src/Nazara/Lua/LuaInstance.cpp | 2 +- src/Nazara/Lua/LuaState.cpp | 23 ++++++++---- 8 files changed, 154 insertions(+), 16 deletions(-) create mode 100644 include/Nazara/Lua/LuaCoroutine.hpp create mode 100644 include/Nazara/Lua/LuaCoroutine.inl create mode 100644 src/Nazara/Lua/LuaCoroutine.cpp diff --git a/include/Nazara/Lua/LuaCoroutine.hpp b/include/Nazara/Lua/LuaCoroutine.hpp new file mode 100644 index 000000000..b145cfe22 --- /dev/null +++ b/include/Nazara/Lua/LuaCoroutine.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LUACOROUTINE_HPP +#define NAZARA_LUACOROUTINE_HPP + +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_LUA_API LuaCoroutine : public LuaState + { + friend class LuaState; + + public: + LuaCoroutine(const LuaCoroutine&) = delete; + inline LuaCoroutine(LuaCoroutine&& instance); + ~LuaCoroutine(); + + bool CanResume() const; + + Ternary Resume(unsigned int argCount = 0); + + LuaCoroutine& operator=(const LuaCoroutine&) = delete; + inline LuaCoroutine& operator=(LuaCoroutine&& instance); + + private: + LuaCoroutine(lua_State* internalState, int refIndex); + + bool Run(int argCount, int resultCount) override; + + int m_ref; + }; +} + +#include + +#endif // NAZARA_LUACOROUTINE_HPP diff --git a/include/Nazara/Lua/LuaCoroutine.inl b/include/Nazara/Lua/LuaCoroutine.inl new file mode 100644 index 000000000..7dcdd0e07 --- /dev/null +++ b/include/Nazara/Lua/LuaCoroutine.inl @@ -0,0 +1,25 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + inline LuaCoroutine::LuaCoroutine(LuaCoroutine&& instance) : + LuaState(std::move(instance)), + m_ref(instance.m_ref) + { + instance.m_ref = -1; + } + + inline LuaCoroutine& LuaCoroutine::operator=(LuaCoroutine&& instance) + { + LuaState::operator=(std::move(instance)); + + m_ref = instance.m_ref; + instance.m_ref = -1; + + return *this; + } +} diff --git a/include/Nazara/Lua/LuaInstance.hpp b/include/Nazara/Lua/LuaInstance.hpp index 45d19ddba..a5d631645 100644 --- a/include/Nazara/Lua/LuaInstance.hpp +++ b/include/Nazara/Lua/LuaInstance.hpp @@ -16,6 +16,7 @@ namespace Nz { class NAZARA_LUA_API LuaInstance : public LuaState { + friend class LuaCoroutine; friend class LuaState; public: diff --git a/include/Nazara/Lua/LuaState.hpp b/include/Nazara/Lua/LuaState.hpp index a34ec27fd..f3bfdc34a 100644 --- a/include/Nazara/Lua/LuaState.hpp +++ b/include/Nazara/Lua/LuaState.hpp @@ -21,6 +21,7 @@ struct lua_State; namespace Nz { + class LuaCoroutine; class LuaInstance; class LuaState; @@ -115,6 +116,7 @@ namespace Nz void MoveTo(LuaState* instance, int n) const; + LuaCoroutine NewCoroutine(); bool NewMetatable(const char* str); bool NewMetatable(const String& str); bool Next(int index = -2) const; @@ -158,10 +160,8 @@ namespace Nz void SetMetatable(const char* tname) const; void SetMetatable(const String& tname) const; void SetMetatable(int index) const; - void SetMemoryLimit(std::size_t memoryLimit); void SetTable(int index = -3) const; void SetTableRaw(int index = -3) const; - void SetTimeLimit(UInt32 timeLimit); bool ToBoolean(int index) const; long long ToInteger(int index, bool* succeeded = nullptr) const; @@ -176,18 +176,18 @@ namespace Nz LuaState& operator=(LuaState&& instance) noexcept; static int GetIndexOfUpValue(int upValue); - static LuaState GetState(lua_State* internalState); + static LuaInstance& GetInstance(lua_State* internalState); + static inline LuaState GetState(lua_State* internalState); protected: - LuaState(LuaInstance* instance, lua_State* internalState); + LuaState(lua_State* internalState); template T CheckBounds(int index, long long value) const; - bool Run(int argCount, int resultCount); + virtual bool Run(int argCount, int resultCount); static int ProxyFunc(lua_State* internalState); String m_lastError; - LuaInstance* m_instance; lua_State* m_state; }; } diff --git a/include/Nazara/Lua/LuaState.inl b/include/Nazara/Lua/LuaState.inl index dbc9016cf..fa4ecaaf0 100644 --- a/include/Nazara/Lua/LuaState.inl +++ b/include/Nazara/Lua/LuaState.inl @@ -15,8 +15,7 @@ namespace Nz { - inline LuaState::LuaState(LuaInstance* instance, lua_State* internalState) : - m_instance(instance), + inline LuaState::LuaState(lua_State* internalState) : m_state(internalState) { } @@ -785,4 +784,9 @@ namespace Nz return static_cast(value); } + + inline LuaState LuaState::GetState(lua_State* internalState) + { + return LuaState(internalState); + } } diff --git a/src/Nazara/Lua/LuaCoroutine.cpp b/src/Nazara/Lua/LuaCoroutine.cpp new file mode 100644 index 000000000..ea73af31a --- /dev/null +++ b/src/Nazara/Lua/LuaCoroutine.cpp @@ -0,0 +1,55 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz +{ + LuaCoroutine::LuaCoroutine(lua_State* internalState, int refIndex) : + LuaState(internalState), + m_ref(refIndex) + { + } + + LuaCoroutine::~LuaCoroutine() + { + if (m_ref >= 0) + DestroyReference(m_ref); + } + + bool LuaCoroutine::CanResume() const + { + return lua_status(m_state) == LUA_YIELD; + } + + Ternary LuaCoroutine::Resume(unsigned int argCount) + { + LuaInstance& instance = GetInstance(m_state); + if (instance.m_level++ == 0) + instance.m_clock.Restart(); + + int status = lua_resume(m_state, nullptr, argCount); + instance.m_level--; + + if (status == LUA_OK) + return Ternary_True; + else if (status == LUA_YIELD) + return Ternary_Unknown; + else + { + m_lastError = ToString(-1); + Pop(); + return Ternary_False; + } + } + + bool LuaCoroutine::Run(int argCount, int /*resultCount*/) + { + return Resume(argCount) != Ternary_False; + } +} diff --git a/src/Nazara/Lua/LuaInstance.cpp b/src/Nazara/Lua/LuaInstance.cpp index 607edc126..a0d5d3ff7 100644 --- a/src/Nazara/Lua/LuaInstance.cpp +++ b/src/Nazara/Lua/LuaInstance.cpp @@ -30,7 +30,7 @@ namespace Nz } LuaInstance::LuaInstance() : - LuaState(this, lua_newstate(MemoryAllocator, this)), + LuaState(nullptr), m_memoryLimit(0), m_memoryUsage(0), m_timeLimit(1000), diff --git a/src/Nazara/Lua/LuaState.cpp b/src/Nazara/Lua/LuaState.cpp index f71504ab7..94170aee0 100644 --- a/src/Nazara/Lua/LuaState.cpp +++ b/src/Nazara/Lua/LuaState.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -127,7 +128,6 @@ namespace Nz LuaState::LuaState(LuaState&& state) noexcept : m_lastError(state.m_lastError), - m_instance(state.m_instance), m_state(state.m_state) { } @@ -570,6 +570,14 @@ namespace Nz lua_xmove(m_state, instance->m_state, n); } + LuaCoroutine LuaState::NewCoroutine() + { + lua_State* thread = lua_newthread(m_state); + int ref = luaL_ref(m_state, LUA_REGISTRYINDEX); + + return LuaCoroutine(thread, ref); + } + bool LuaState::NewMetatable(const char* str) { return luaL_newmetatable(m_state, str) != 0; @@ -783,7 +791,6 @@ namespace Nz LuaState& LuaState::operator=(LuaState&& state) noexcept { - m_instance = state.m_instance; m_lastError = std::move(state.m_lastError); m_state = state.m_state; @@ -792,12 +799,14 @@ namespace Nz bool LuaState::Run(int argCount, int resultCount) { - if (m_instance->m_level++ == 0) - m_instance->m_clock.Restart(); + LuaInstance& instance = GetInstance(m_state); + + if (instance.m_level++ == 0) + instance.m_clock.Restart(); int status = lua_pcall(m_state, argCount, resultCount, 0); - m_instance->m_level--; + instance.m_level--; if (status != 0) { @@ -815,12 +824,12 @@ namespace Nz return lua_upvalueindex(upValue); } - LuaState LuaState::GetState(lua_State* internalState) + LuaInstance& LuaState::GetInstance(lua_State* internalState) { LuaInstance* instance; lua_getallocf(internalState, reinterpret_cast(&instance)); - return LuaState(instance, internalState); + return *instance; } int LuaState::ProxyFunc(lua_State* internalState) From 9117deb609b927d9e7abb52bf5629218f001c96b Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 9 Jun 2017 01:46:04 +0200 Subject: [PATCH 69/73] Update global headers --- include/Nazara/Core.hpp | 1 + include/Nazara/Lua.hpp | 2 ++ include/Nazara/Network.hpp | 1 + include/Nazara/Utility.hpp | 2 ++ 4 files changed, 6 insertions(+) diff --git a/include/Nazara/Core.hpp b/include/Nazara/Core.hpp index 419ddaae9..606d6969a 100644 --- a/include/Nazara/Core.hpp +++ b/include/Nazara/Core.hpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Lua.hpp b/include/Nazara/Lua.hpp index a0e68204c..bd7ddb24c 100644 --- a/include/Nazara/Lua.hpp +++ b/include/Nazara/Lua.hpp @@ -33,6 +33,8 @@ #include #include #include +#include #include +#include #endif // NAZARA_GLOBAL_LUA_HPP diff --git a/include/Nazara/Network.hpp b/include/Nazara/Network.hpp index 41b7fce71..1b2dc72c5 100644 --- a/include/Nazara/Network.hpp +++ b/include/Nazara/Network.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Utility.hpp b/include/Nazara/Utility.hpp index 3734b919e..fbb100476 100644 --- a/include/Nazara/Utility.hpp +++ b/include/Nazara/Utility.hpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,7 @@ #include #include #include +#include #include #include #include From 4ce7db09d602741420d460176f095b0c6a2726cb Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 9 Jun 2017 01:47:15 +0200 Subject: [PATCH 70/73] Lua/LuaCoroutine: Fix inline include --- include/Nazara/Lua/LuaCoroutine.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Nazara/Lua/LuaCoroutine.hpp b/include/Nazara/Lua/LuaCoroutine.hpp index b145cfe22..a740f635b 100644 --- a/include/Nazara/Lua/LuaCoroutine.hpp +++ b/include/Nazara/Lua/LuaCoroutine.hpp @@ -39,6 +39,6 @@ namespace Nz }; } -#include +#include #endif // NAZARA_LUACOROUTINE_HPP From 35ba78510be8ce3d4814d3c816e8cdcb14c6017b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 9 Jun 2017 02:06:14 +0200 Subject: [PATCH 71/73] Fix compilation --- src/Nazara/Lua/LuaCoroutine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nazara/Lua/LuaCoroutine.cpp b/src/Nazara/Lua/LuaCoroutine.cpp index ea73af31a..197244134 100644 --- a/src/Nazara/Lua/LuaCoroutine.cpp +++ b/src/Nazara/Lua/LuaCoroutine.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace Nz From ab1eccde8247f579184c047933796eb51b8e90c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 9 Jun 2017 02:07:51 +0200 Subject: [PATCH 72/73] Fix compilation --- src/Nazara/Lua/LuaCoroutine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nazara/Lua/LuaCoroutine.cpp b/src/Nazara/Lua/LuaCoroutine.cpp index ea73af31a..197244134 100644 --- a/src/Nazara/Lua/LuaCoroutine.cpp +++ b/src/Nazara/Lua/LuaCoroutine.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace Nz From 78182502e3db5c786c96d8d7b61973cd7b33e4f6 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 10 Jun 2017 22:29:17 +0200 Subject: [PATCH 73/73] Lua/LuaInstance: Fix missing memory/time methods --- include/Nazara/Lua/LuaInstance.hpp | 9 ++++++++ include/Nazara/Lua/LuaInstance.inl | 36 ++++++++++++++++++++++-------- src/Nazara/Lua/LuaInstance.cpp | 18 ++++++++++----- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/include/Nazara/Lua/LuaInstance.hpp b/include/Nazara/Lua/LuaInstance.hpp index a5d631645..93374958b 100644 --- a/include/Nazara/Lua/LuaInstance.hpp +++ b/include/Nazara/Lua/LuaInstance.hpp @@ -25,10 +25,19 @@ namespace Nz LuaInstance(LuaInstance&& instance) = default; ~LuaInstance(); + inline std::size_t GetMemoryLimit() const; + inline std::size_t GetMemoryUsage() const; + inline UInt32 GetTimeLimit() const; + + inline void SetMemoryLimit(std::size_t memoryLimit); + inline void SetTimeLimit(UInt32 limit); + LuaInstance& operator=(const LuaInstance&) = delete; LuaInstance& operator=(LuaInstance&& instance) = default; private: + inline void SetMemoryUsage(std::size_t memoryUsage); + static void* MemoryAllocator(void *ud, void *ptr, std::size_t osize, std::size_t nsize); static void TimeLimiter(lua_State* internalState, lua_Debug* debug); diff --git a/include/Nazara/Lua/LuaInstance.inl b/include/Nazara/Lua/LuaInstance.inl index f4394eb6b..6752eb0e0 100644 --- a/include/Nazara/Lua/LuaInstance.inl +++ b/include/Nazara/Lua/LuaInstance.inl @@ -3,16 +3,34 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace Nz { + inline std::size_t LuaInstance::GetMemoryLimit() const + { + return m_memoryLimit; + } + + inline std::size_t LuaInstance::GetMemoryUsage() const + { + return m_memoryUsage; + } + + inline UInt32 LuaInstance::GetTimeLimit() const + { + return m_timeLimit; + } + + inline void LuaInstance::SetMemoryLimit(std::size_t memoryLimit) + { + m_memoryLimit = m_memoryLimit; + } + + inline void LuaInstance::SetTimeLimit(UInt32 limit) + { + m_timeLimit = limit; + } } + +#include diff --git a/src/Nazara/Lua/LuaInstance.cpp b/src/Nazara/Lua/LuaInstance.cpp index a0d5d3ff7..cd47ac5c7 100644 --- a/src/Nazara/Lua/LuaInstance.cpp +++ b/src/Nazara/Lua/LuaInstance.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -48,15 +49,22 @@ namespace Nz lua_close(m_state); } + inline void LuaInstance::SetMemoryUsage(std::size_t memoryUsage) + { + m_memoryUsage = memoryUsage; + } + void* LuaInstance::MemoryAllocator(void* ud, void* ptr, std::size_t osize, std::size_t nsize) { LuaInstance* instance = static_cast(ud); - std::size_t& memoryLimit = instance->m_memoryLimit; - std::size_t& memoryUsage = instance->m_memoryUsage; + std::size_t memoryLimit = instance->GetMemoryLimit(); + std::size_t memoryUsage = instance->GetMemoryUsage(); if (nsize == 0) { - memoryUsage -= osize; + assert(memoryUsage >= osize); + + instance->SetMemoryUsage(memoryUsage - osize); std::free(ptr); return nullptr; @@ -73,7 +81,7 @@ namespace Nz return nullptr; } - memoryUsage = usage; + instance->SetMemoryUsage(usage); return std::realloc(ptr, nsize); } @@ -86,7 +94,7 @@ namespace Nz LuaInstance* instance; lua_getallocf(internalState, reinterpret_cast(&instance)); - if (instance->m_clock.GetMilliseconds() > instance->m_timeLimit) + if (instance->m_clock.GetMilliseconds() > instance->GetTimeLimit()) luaL_error(internalState, "maximum execution time exceeded"); } }