diff --git a/.gitmodules b/.gitmodules index 4d4ad583f9..4ae9400cff 100644 --- a/.gitmodules +++ b/.gitmodules @@ -51,3 +51,6 @@ [submodule "Externals/gtest"] path = Externals/gtest url = https://github.com/google/googletest.git +[submodule "Externals/rcheevos/rcheevos"] + path = Externals/rcheevos/rcheevos + url = https://github.com/RetroAchievements/rcheevos.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fd3972ad2..ae86d33b42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence, show the current gam option(USE_MGBA "Enables GBA controllers emulation using libmgba" ON) option(ENABLE_AUTOUPDATE "Enables support for automatic updates" ON) option(STEAM "Creates a build for Steam" OFF) +option(USE_RETRO_ACHIEVEMENTS "Enables integration with retroachievements.org" ON) # Maintainers: if you consider blanket disabling this for your users, please # consider the following points: @@ -975,6 +976,10 @@ add_subdirectory(Externals/rangeset) add_subdirectory(Externals/FatFs) +if (USE_RETRO_ACHIEVEMENTS) + add_subdirectory(Externals/rcheevos) +endif() + ######################################## # Pre-build events: Define configuration variables and write SCM info header # diff --git a/Externals/enet/CMakeLists.txt b/Externals/enet/CMakeLists.txt index 7f9a2473df..7088bf3291 100644 --- a/Externals/enet/CMakeLists.txt +++ b/Externals/enet/CMakeLists.txt @@ -8,7 +8,7 @@ include(CheckStructHasMember) include(CheckTypeSize) if(HAIKU) - set(CMAKE_REQUIRED_LIBRARIES network) + set(CMAKE_REQUIRED_LIBRARIES network) endif(HAIKU) check_function_exists("fcntl" HAS_FCNTL) @@ -25,7 +25,7 @@ check_type_size("socklen_t" HAS_SOCKLEN_T BUILTIN_TYPES_ONLY) unset(CMAKE_EXTRA_INCLUDE_FILES) if(HAIKU) - unset(CMAKE_REQUIRED_LIBRARIES) + unset(CMAKE_REQUIRED_LIBRARIES) endif() if(HAS_FCNTL) @@ -61,18 +61,44 @@ endif() include_directories(${PROJECT_SOURCE_DIR}/include) +set(INCLUDE_FILES_PREFIX include/enet) +set(INCLUDE_FILES + ${INCLUDE_FILES_PREFIX}/callbacks.h + ${INCLUDE_FILES_PREFIX}/enet.h + ${INCLUDE_FILES_PREFIX}/list.h + ${INCLUDE_FILES_PREFIX}/protocol.h + ${INCLUDE_FILES_PREFIX}/time.h + ${INCLUDE_FILES_PREFIX}/types.h + ${INCLUDE_FILES_PREFIX}/unix.h + ${INCLUDE_FILES_PREFIX}/utility.h + ${INCLUDE_FILES_PREFIX}/win32.h +) + +set(SOURCE_FILES + callbacks.c + compress.c + host.c + list.c + packet.c + peer.c + protocol.c + unix.c + win32.c) + +source_group(include FILES ${INCLUDE_FILES}) +source_group(source FILES ${SOURCE_FILES}) + add_library(enet STATIC - callbacks.c - compress.c - host.c - list.c - packet.c - peer.c - protocol.c - unix.c - win32.c - ) + ${INCLUDE_FILES} + ${SOURCE_FILES} +) + dolphin_disable_warnings_msvc(enet) + +if (MINGW) + target_link_libraries(enet winmm ws2_32) +endif() + if(HAIKU) - target_link_libraries(enet network) + target_link_libraries(enet network) endif(HAIKU) diff --git a/Externals/enet/ChangeLog b/Externals/enet/ChangeLog index 663c7b731c..e182076425 100644 --- a/Externals/enet/ChangeLog +++ b/Externals/enet/ChangeLog @@ -1,4 +1,25 @@ +ENet 1.3.17 (November 15, 2020): + +* fixes for sender getting too far ahead of receiver that can cause instability with reliable packets + +ENet 1.3.16 (September 8, 2020): + +* fix bug in unreliable fragment queuing +* use single output queue for reliable and unreliable packets for saner ordering +* revert experimental throttle changes that were less stable than prior algorithm + +ENet 1.3.15 (April 20, 2020): + +* quicker RTT initialization +* use fractional precision for RTT calculations +* fixes for packet throttle with low RTT variance +* miscellaneous socket bug fixes + +ENet 1.3.14 (January 27, 2019): + +* bug fix for enet_peer_disconnect_later() * use getaddrinfo and getnameinfo where available +* miscellaneous cleanups ENet 1.3.13 (April 30, 2015): diff --git a/Externals/enet/Doxyfile b/Externals/enet/Doxyfile index 597ef1af1c..6b4d06fb29 100644 --- a/Externals/enet/Doxyfile +++ b/Externals/enet/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "ENet" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = v1.3.13 +PROJECT_NUMBER = v1.3.17 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/Externals/enet/LICENSE b/Externals/enet/LICENSE index 436053efda..6906f8eb0b 100644 --- a/Externals/enet/LICENSE +++ b/Externals/enet/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2002-2015 Lee Salzman +Copyright (c) 2002-2020 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: diff --git a/Externals/enet/Makefile.am b/Externals/enet/Makefile.am index e839463c41..d029ed1faf 100644 --- a/Externals/enet/Makefile.am +++ b/Externals/enet/Makefile.am @@ -16,7 +16,7 @@ enetinclude_HEADERS = \ lib_LTLIBRARIES = libenet.la libenet_la_SOURCES = callbacks.c compress.c host.c list.c packet.c peer.c protocol.c unix.c win32.c # see info '(libtool) Updating version info' before making a release -libenet_la_LDFLAGS = $(AM_LDFLAGS) -version-info 7:1:0 +libenet_la_LDFLAGS = $(AM_LDFLAGS) -version-info 7:5:0 AM_CPPFLAGS = -I$(top_srcdir)/include ACLOCAL_AMFLAGS = -Im4 diff --git a/Externals/enet/README b/Externals/enet/README index 54b2d21304..3b6318b22a 100644 --- a/Externals/enet/README +++ b/Externals/enet/README @@ -1,4 +1,4 @@ -Please visit the ENet homepage at http://enet.bespin.org for installation +Please visit the ENet homepage at http://sauerbraten.org/enet/ for installation and usage instructions. If you obtained this package from github, the quick description on how to build diff --git a/Externals/enet/configure.ac b/Externals/enet/configure.ac index a4206dbcc3..e0c745d6d4 100644 --- a/Externals/enet/configure.ac +++ b/Externals/enet/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([libenet], [1.3.13]) +AC_INIT([libenet], [1.3.17]) AC_CONFIG_SRCDIR([include/enet/enet.h]) AM_INIT_AUTOMAKE([foreign]) diff --git a/Externals/enet/docs/license.dox b/Externals/enet/docs/license.dox index 924393bb91..9991a7f9a5 100644 --- a/Externals/enet/docs/license.dox +++ b/Externals/enet/docs/license.dox @@ -1,7 +1,7 @@ /** @page License License -Copyright (c) 2002-2015 Lee Salzman +Copyright (c) 2002-2020 Lee Salzman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/Externals/enet/docs/mainpage.dox b/Externals/enet/docs/mainpage.dox index 7fbbee1d54..eb6c8b857f 100644 --- a/Externals/enet/docs/mainpage.dox +++ b/Externals/enet/docs/mainpage.dox @@ -36,7 +36,7 @@ portable, and easily embeddable. You can retrieve the source to ENet by downloading it in either .tar.gz form or accessing the github distribution directly. -The most recent stable release (1.3.13) can be downloaded here. +The most recent stable release (1.3.17) can be downloaded here. The last release that is protocol compatible with the 1.2 series or earlier (1.2.5) can be downloaded here. You can find the most recent ENet source at the github repository. @@ -53,7 +53,7 @@ The en /** @page IRCChannel IRC Channel -Join the \#enet channel on the freenode IRC network (irc.freenode.net) for real-time discussion about the ENet library. +Join the \#enet channel on the Libera Chat IRC network (irc.libera.chat) for real-time discussion about the ENet library. */ diff --git a/Externals/enet/docs/tutorial.dox b/Externals/enet/docs/tutorial.dox index e91eae825a..19a7a45e72 100644 --- a/Externals/enet/docs/tutorial.dox +++ b/Externals/enet/docs/tutorial.dox @@ -102,8 +102,8 @@ may be simultaneously open. client = enet_host_create (NULL /* create a client host */, 1 /* only allow 1 outgoing connection */, 2 /* allow up 2 channels to be used, 0 and 1 */, - 57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */, - 14400 / 8 /* 56K modem with 14 Kbps upstream bandwidth */); + 0 /* assume any amount of incoming bandwidth */, + 0 /* assume any amount of outgoing bandwidth */); if (client == NULL) { diff --git a/Externals/enet/host.c b/Externals/enet/host.c index 3be6c0922c..fff946a392 100644 --- a/Externals/enet/host.c +++ b/Externals/enet/host.c @@ -96,6 +96,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL host -> totalSentPackets = 0; host -> totalReceivedData = 0; host -> totalReceivedPackets = 0; + host -> totalQueued = 0; host -> connectedPeers = 0; host -> bandwidthLimitedPeers = 0; @@ -123,9 +124,8 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL enet_list_clear (& currentPeer -> acknowledgements); enet_list_clear (& currentPeer -> sentReliableCommands); - enet_list_clear (& currentPeer -> sentUnreliableCommands); - enet_list_clear (& currentPeer -> outgoingReliableCommands); - enet_list_clear (& currentPeer -> outgoingUnreliableCommands); + enet_list_clear (& currentPeer -> outgoingCommands); + enet_list_clear (& currentPeer -> outgoingSendReliableCommands); enet_list_clear (& currentPeer -> dispatchedCommands); enet_peer_reset (currentPeer); @@ -161,6 +161,16 @@ enet_host_destroy (ENetHost * host) enet_free (host); } +enet_uint32 +enet_host_random (ENetHost * host) +{ + /* Mulberry32 by Tommy Ettinger */ + enet_uint32 n = (host -> randomSeed += 0x6D2B79F5U); + n = (n ^ (n >> 15)) * (n | 1U); + n ^= n + (n ^ (n >> 7)) * (n | 61U); + return n ^ (n >> 14); +} + /** Initiates a connection to a foreign host. @param host host seeking the connection @param address destination for the connection @@ -200,7 +210,8 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC currentPeer -> channelCount = channelCount; currentPeer -> state = ENET_PEER_STATE_CONNECTING; currentPeer -> address = * address; - currentPeer -> connectID = ++ host -> randomSeed; + currentPeer -> connectID = enet_host_random (host); + currentPeer -> mtu = host -> mtu; if (host -> outgoingBandwidth == 0) currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; diff --git a/Externals/enet/include/enet/enet.h b/Externals/enet/include/enet/enet.h index 5e21ee8ea9..be59c10796 100644 --- a/Externals/enet/include/enet/enet.h +++ b/Externals/enet/include/enet/enet.h @@ -25,7 +25,7 @@ extern "C" #define ENET_VERSION_MAJOR 1 #define ENET_VERSION_MINOR 3 -#define ENET_VERSION_PATCH 13 +#define ENET_VERSION_PATCH 17 #define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) #define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF) #define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF) @@ -62,7 +62,8 @@ typedef enum _ENetSocketOption ENET_SOCKOPT_RCVTIMEO = 6, ENET_SOCKOPT_SNDTIMEO = 7, ENET_SOCKOPT_ERROR = 8, - ENET_SOCKOPT_NODELAY = 9 + ENET_SOCKOPT_NODELAY = 9, + ENET_SOCKOPT_TTL = 10 } ENetSocketOption; typedef enum _ENetSocketShutdown @@ -138,7 +139,11 @@ typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); * (not supported for reliable packets) * * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead - + * + * ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable + * (instead of reliable) sends if it exceeds the MTU + * + * ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into @sa ENetPacketFlag */ typedef struct _ENetPacket @@ -165,7 +170,7 @@ typedef struct _ENetOutgoingCommand enet_uint16 unreliableSequenceNumber; enet_uint32 sentTime; enet_uint32 roundTripTimeout; - enet_uint32 roundTripTimeoutLimit; + enet_uint32 queueTime; enet_uint32 fragmentOffset; enet_uint16 fragmentLength; enet_uint16 sendAttempts; @@ -246,6 +251,12 @@ typedef struct _ENetChannel ENetList incomingUnreliableCommands; } ENetChannel; +typedef enum _ENetPeerFlag +{ + ENET_PEER_FLAG_NEEDS_DISPATCH = (1 << 0), + ENET_PEER_FLAG_CONTINUE_SENDING = (1 << 1) +} ENetPeerFlag; + /** * An ENet peer which data packets may be sent or received from. * @@ -303,11 +314,11 @@ typedef struct _ENetPeer enet_uint16 outgoingReliableSequenceNumber; ENetList acknowledgements; ENetList sentReliableCommands; - ENetList sentUnreliableCommands; - ENetList outgoingReliableCommands; - ENetList outgoingUnreliableCommands; + ENetList outgoingSendReliableCommands; + ENetList outgoingCommands; ENetList dispatchedCommands; - int needsDispatch; + enet_uint16 flags; + enet_uint16 reserved; enet_uint16 incomingUnsequencedGroup; enet_uint16 outgoingUnsequencedGroup; enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; @@ -366,7 +377,7 @@ typedef struct _ENetHost size_t channelLimit; /**< maximum number of channels allowed for connected peers */ enet_uint32 serviceTime; ENetList dispatchQueue; - int continueSending; + enet_uint32 totalQueued; size_t packetSize; enet_uint16 headerFlags; ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; @@ -405,7 +416,7 @@ typedef enum _ENetEventType ENET_EVENT_TYPE_CONNECT = 1, /** a peer has disconnected. This event is generated on a successful - * completion of a disconnect initiated by enet_pper_disconnect, if + * completion of a disconnect initiated by enet_peer_disconnect, if * a peer has timed out, or if a connection request intialized by * enet_host_connect has timed out. The peer field contains the peer * which disconnected. The data field contains user supplied data @@ -505,6 +516,17 @@ ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSock /** @defgroup Address ENet address functions @{ */ + +/** Attempts to parse the printable form of the IP address in the parameter hostName + and sets the host field in the address parameter if successful. + @param address destination to store the parsed IP address + @param hostName IP address to parse + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host_ip (ENetAddress * address, const char * hostName); + /** Attempts to resolve the host named by the parameter hostName and sets the host field in the address parameter if successful. @param address destination to store resolved address @@ -555,6 +577,7 @@ ENET_API void enet_host_channel_limit (ENetHost *, size_t); ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); extern void enet_host_bandwidth_throttle (ENetHost *); extern enet_uint32 enet_host_random_seed (void); +extern enet_uint32 enet_host_random (ENetHost *); ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *); ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID); @@ -568,12 +591,13 @@ ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32 ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); extern int enet_peer_throttle (ENetPeer *, enet_uint32); extern void enet_peer_reset_queues (ENetPeer *); +extern int enet_peer_has_outgoing_commands (ENetPeer *); extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *); extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32); extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16); -extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *); -extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *); +extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *, ENetIncomingCommand *); +extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *, ENetIncomingCommand *); extern void enet_peer_on_connect (ENetPeer *); extern void enet_peer_on_disconnect (ENetPeer *); diff --git a/Externals/enet/include/enet/unix.h b/Externals/enet/include/enet/unix.h index a59e340606..b55be33103 100644 --- a/Externals/enet/include/enet/unix.h +++ b/Externals/enet/include/enet/unix.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/Externals/enet/include/enet/utility.h b/Externals/enet/include/enet/utility.h index e48a476be3..b04bb7a5b3 100644 --- a/Externals/enet/include/enet/utility.h +++ b/Externals/enet/include/enet/utility.h @@ -7,6 +7,7 @@ #define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) #define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) +#define ENET_DIFFERENCE(x, y) ((x) < (y) ? (y) - (x) : (x) - (y)) #endif /* __ENET_UTILITY_H__ */ diff --git a/Externals/enet/include/enet/win32.h b/Externals/enet/include/enet/win32.h index e73ca9d052..6fbd7c02c8 100644 --- a/Externals/enet/include/enet/win32.h +++ b/Externals/enet/include/enet/win32.h @@ -11,6 +11,8 @@ #pragma warning (disable: 4244) // 64bit to 32bit int #pragma warning (disable: 4018) // signed/unsigned mismatch #pragma warning (disable: 4146) // unary minus operator applied to unsigned type +#define _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_WARNINGS #endif #endif diff --git a/Externals/enet/packet.c b/Externals/enet/packet.c index 5fa78b28ae..d51c640404 100644 --- a/Externals/enet/packet.c +++ b/Externals/enet/packet.c @@ -98,53 +98,46 @@ enet_packet_resize (ENetPacket * packet, size_t dataLength) return 0; } -static int initializedCRC32 = 0; -static enet_uint32 crcTable [256]; - -static enet_uint32 -reflect_crc (int val, int bits) +static const enet_uint32 crcTable [256] = { - int result = 0, bit; + 0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x5005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0xBDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; - for (bit = 0; bit < bits; bit ++) - { - if(val & 1) result |= 1 << (bits - 1 - bit); - val >>= 1; - } - - return result; -} - -static void -initialize_crc32 (void) -{ - int byte; - - for (byte = 0; byte < 256; ++ byte) - { - enet_uint32 crc = reflect_crc (byte, 8) << 24; - int offset; - - for(offset = 0; offset < 8; ++ offset) - { - if (crc & 0x80000000) - crc = (crc << 1) ^ 0x04c11db7; - else - crc <<= 1; - } - - crcTable [byte] = reflect_crc (crc, 32); - } - - initializedCRC32 = 1; -} - enet_uint32 enet_crc32 (const ENetBuffer * buffers, size_t bufferCount) { enet_uint32 crc = 0xFFFFFFFF; - - if (! initializedCRC32) initialize_crc32 (); while (bufferCount -- > 0) { @@ -153,7 +146,7 @@ enet_crc32 (const ENetBuffer * buffers, size_t bufferCount) while (data < dataEnd) { - crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++]; + crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++]; } ++ buffers; diff --git a/Externals/enet/peer.c b/Externals/enet/peer.c index e2d0872bd3..a7ac012079 100644 --- a/Externals/enet/peer.c +++ b/Externals/enet/peer.c @@ -66,7 +66,7 @@ enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt) peer -> packetThrottle = peer -> packetThrottleLimit; } else - if (rtt < peer -> lastRoundTripTime) + if (rtt <= peer -> lastRoundTripTime) { peer -> packetThrottle += peer -> packetThrottleAcceleration; @@ -90,6 +90,13 @@ enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt) } /** Queues a packet to be sent. + + On success, ENet will assume ownership of the packet, and so enet_packet_destroy + should not be called on it thereafter. On failure, the caller still must destroy + the packet on its own as ENet has not queued the packet. The caller can also + check the packet's referenceCount field after sending to check if ENet queued + the packet and thus incremented the referenceCount. + @param peer destination for the packet @param channelID channel on which to send @param packet packet to send @@ -99,7 +106,7 @@ enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt) int enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet) { - ENetChannel * channel = & peer -> channels [channelID]; + ENetChannel * channel; ENetProtocol command; size_t fragmentLength; @@ -108,6 +115,7 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet) packet -> dataLength > peer -> host -> maximumPacketSize) return -1; + channel = & peer -> channels [channelID]; fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment); if (peer -> host -> checksum != NULL) fragmentLength -= sizeof(enet_uint32); @@ -268,7 +276,7 @@ enet_peer_reset_outgoing_commands (ENetList * queue) } static void -enet_peer_remove_incoming_commands (ENetList * queue, ENetListIterator startCommand, ENetListIterator endCommand) +enet_peer_remove_incoming_commands (ENetList * queue, ENetListIterator startCommand, ENetListIterator endCommand, ENetIncomingCommand * excludeCommand) { ENetListIterator currentCommand; @@ -278,6 +286,9 @@ enet_peer_remove_incoming_commands (ENetList * queue, ENetListIterator startComm currentCommand = enet_list_next (currentCommand); + if (incomingCommand == excludeCommand) + continue; + enet_list_remove (& incomingCommand -> incomingCommandList); if (incomingCommand -> packet != NULL) @@ -298,7 +309,7 @@ enet_peer_remove_incoming_commands (ENetList * queue, ENetListIterator startComm static void enet_peer_reset_incoming_commands (ENetList * queue) { - enet_peer_remove_incoming_commands(queue, enet_list_begin (queue), enet_list_end (queue)); + enet_peer_remove_incoming_commands(queue, enet_list_begin (queue), enet_list_end (queue), NULL); } void @@ -306,20 +317,19 @@ enet_peer_reset_queues (ENetPeer * peer) { ENetChannel * channel; - if (peer -> needsDispatch) + if (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH) { enet_list_remove (& peer -> dispatchList); - peer -> needsDispatch = 0; + peer -> flags &= ~ ENET_PEER_FLAG_NEEDS_DISPATCH; } while (! enet_list_empty (& peer -> acknowledgements)) enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements))); enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands); - enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands); - enet_peer_reset_outgoing_commands (& peer -> outgoingReliableCommands); - enet_peer_reset_outgoing_commands (& peer -> outgoingUnreliableCommands); + enet_peer_reset_outgoing_commands (& peer -> outgoingCommands); + enet_peer_reset_outgoing_commands (& peer -> outgoingSendReliableCommands); enet_peer_reset_incoming_commands (& peer -> dispatchedCommands); if (peer -> channels != NULL && peer -> channelCount > 0) @@ -418,6 +428,7 @@ enet_peer_reset (ENetPeer * peer) peer -> outgoingUnsequencedGroup = 0; peer -> eventData = 0; peer -> totalWaitingData = 0; + peer -> flags = 0; memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); @@ -560,6 +571,17 @@ enet_peer_disconnect (ENetPeer * peer, enet_uint32 data) } } +int +enet_peer_has_outgoing_commands (ENetPeer * peer) +{ + if (enet_list_empty (& peer -> outgoingCommands) && + enet_list_empty (& peer -> outgoingSendReliableCommands) && + enet_list_empty (& peer -> sentReliableCommands)) + return 0; + + return 1; +} + /** Request a disconnection from a peer, but only after all queued outgoing packets are sent. @param peer peer to request a disconnection @param data data describing the disconnection @@ -570,9 +592,7 @@ void enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data) { if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) && - ! (enet_list_empty (& peer -> outgoingReliableCommands) && - enet_list_empty (& peer -> outgoingUnreliableCommands) && - enet_list_empty (& peer -> sentReliableCommands))) + enet_peer_has_outgoing_commands (peer)) { peer -> state = ENET_PEER_STATE_DISCONNECT_LATER; peer -> eventData = data; @@ -616,8 +636,6 @@ enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, void enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoingCommand) { - ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID]; - peer -> outgoingDataTotal += enet_protocol_command_size (outgoingCommand -> command.header.command) + outgoingCommand -> fragmentLength; if (outgoingCommand -> command.header.channelID == 0xFF) @@ -628,36 +646,40 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin outgoingCommand -> unreliableSequenceNumber = 0; } else - if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) { - ++ channel -> outgoingReliableSequenceNumber; - channel -> outgoingUnreliableSequenceNumber = 0; + ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID]; - outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; - outgoingCommand -> unreliableSequenceNumber = 0; - } - else - if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED) - { - ++ peer -> outgoingUnsequencedGroup; + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + { + ++ channel -> outgoingReliableSequenceNumber; + channel -> outgoingUnreliableSequenceNumber = 0; - outgoingCommand -> reliableSequenceNumber = 0; - outgoingCommand -> unreliableSequenceNumber = 0; + outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED) + { + ++ peer -> outgoingUnsequencedGroup; + + outgoingCommand -> reliableSequenceNumber = 0; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + { + if (outgoingCommand -> fragmentOffset == 0) + ++ channel -> outgoingUnreliableSequenceNumber; + + outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber; + } } - 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 = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber); + outgoingCommand -> queueTime = ++ peer -> host -> totalQueued; switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) { @@ -668,15 +690,16 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup); break; - + default: break; } - if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) - enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand); + if ((outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0 && + outgoingCommand -> packet != NULL) + enet_list_insert (enet_list_end (& peer -> outgoingSendReliableCommands), outgoingCommand); else - enet_list_insert (enet_list_end (& peer -> outgoingUnreliableCommands), outgoingCommand); + enet_list_insert (enet_list_end (& peer -> outgoingCommands), outgoingCommand); } ENetOutgoingCommand * @@ -699,7 +722,7 @@ enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, } void -enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * channel) +enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * channel, ENetIncomingCommand * queuedCommand) { ENetListIterator droppedCommand, startCommand, currentCommand; @@ -724,11 +747,11 @@ enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * { enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); - if (! peer -> needsDispatch) + if (! (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH)) { enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); - peer -> needsDispatch = 1; + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; } droppedCommand = currentCommand; @@ -752,11 +775,11 @@ enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * { enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); - if (! peer -> needsDispatch) + if (! (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH)) { enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); - peer -> needsDispatch = 1; + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; } } } @@ -768,21 +791,21 @@ enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * { enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); - if (! peer -> needsDispatch) + if (! (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH)) { enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); - peer -> needsDispatch = 1; + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; } droppedCommand = currentCommand; } - enet_peer_remove_incoming_commands (& channel -> incomingUnreliableCommands, enet_list_begin (& channel -> incomingUnreliableCommands), droppedCommand); + enet_peer_remove_incoming_commands (& channel -> incomingUnreliableCommands, enet_list_begin (& channel -> incomingUnreliableCommands), droppedCommand, queuedCommand); } void -enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * channel) +enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * channel, ENetIncomingCommand * queuedCommand) { ENetListIterator currentCommand; @@ -809,15 +832,15 @@ enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * ch enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingReliableCommands), enet_list_previous (currentCommand)); - if (! peer -> needsDispatch) + if (! (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH)) { enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); - peer -> needsDispatch = 1; + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; } if (! enet_list_empty (& channel -> incomingUnreliableCommands)) - enet_peer_dispatch_incoming_unreliable_commands (peer, channel); + enet_peer_dispatch_incoming_unreliable_commands (peer, channel, queuedCommand); } ENetIncomingCommand * @@ -975,11 +998,11 @@ enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, { case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: - enet_peer_dispatch_incoming_reliable_commands (peer, channel); + enet_peer_dispatch_incoming_reliable_commands (peer, channel, incomingCommand); break; default: - enet_peer_dispatch_incoming_unreliable_commands (peer, channel); + enet_peer_dispatch_incoming_unreliable_commands (peer, channel, incomingCommand); break; } diff --git a/Externals/enet/protocol.c b/Externals/enet/protocol.c index 29d648732d..b7af48df06 100644 --- a/Externals/enet/protocol.c +++ b/Externals/enet/protocol.c @@ -9,7 +9,7 @@ #include "enet/time.h" #include "enet/enet.h" -static size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] = +static const size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] = { 0, sizeof (ENetProtocolAcknowledge), @@ -48,11 +48,11 @@ enet_protocol_dispatch_state (ENetHost * host, ENetPeer * peer, ENetPeerState st { enet_protocol_change_state (host, peer, state); - if (! peer -> needsDispatch) + if (! (peer -> flags & ENET_PEER_FLAG_NEEDS_DISPATCH)) { enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList); - peer -> needsDispatch = 1; + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; } } @@ -63,7 +63,7 @@ enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event) { ENetPeer * peer = (ENetPeer *) enet_list_remove (enet_list_begin (& host -> dispatchQueue)); - peer -> needsDispatch = 0; + peer -> flags &= ~ ENET_PEER_FLAG_NEEDS_DISPATCH; switch (peer -> state) { @@ -101,7 +101,7 @@ enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event) if (! enet_list_empty (& peer -> dispatchedCommands)) { - peer -> needsDispatch = 1; + peer -> flags |= ENET_PEER_FLAG_NEEDS_DISPATCH; enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList); } @@ -159,13 +159,16 @@ enet_protocol_notify_disconnect (ENetHost * host, ENetPeer * peer, ENetEvent * e } static void -enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer) +enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer, ENetList * sentUnreliableCommands) { ENetOutgoingCommand * outgoingCommand; - while (! enet_list_empty (& peer -> sentUnreliableCommands)) + if (enet_list_empty (sentUnreliableCommands)) + return; + + do { - outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentUnreliableCommands); + outgoingCommand = (ENetOutgoingCommand *) enet_list_front (sentUnreliableCommands); enet_list_remove (& outgoingCommand -> outgoingCommandList); @@ -182,7 +185,36 @@ enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer) } enet_free (outgoingCommand); + } while (! enet_list_empty (sentUnreliableCommands)); + + if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER && + ! enet_peer_has_outgoing_commands (peer)) + enet_peer_disconnect (peer, peer -> eventData); +} + +static ENetOutgoingCommand * +enet_protocol_find_sent_reliable_command (ENetList * list, enet_uint16 reliableSequenceNumber, enet_uint8 channelID) +{ + ENetListIterator currentCommand; + + for (currentCommand = enet_list_begin (list); + currentCommand != enet_list_end (list); + currentCommand = enet_list_next (currentCommand)) + { + ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + if (! (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)) + continue; + + if (outgoingCommand -> sendAttempts < 1) + break; + + if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber && + outgoingCommand -> command.header.channelID == channelID) + return outgoingCommand; } + + return NULL; } static ENetProtocolCommand @@ -206,21 +238,9 @@ enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliabl if (currentCommand == enet_list_end (& peer -> sentReliableCommands)) { - for (currentCommand = enet_list_begin (& peer -> outgoingReliableCommands); - currentCommand != enet_list_end (& peer -> outgoingReliableCommands); - currentCommand = enet_list_next (currentCommand)) - { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - if (outgoingCommand -> sendAttempts < 1) return ENET_PROTOCOL_COMMAND_NONE; - - if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber && - outgoingCommand -> command.header.channelID == channelID) - break; - } - - if (currentCommand == enet_list_end (& peer -> outgoingReliableCommands)) - return ENET_PROTOCOL_COMMAND_NONE; + outgoingCommand = enet_protocol_find_sent_reliable_command (& peer -> outgoingCommands, reliableSequenceNumber, channelID); + if (outgoingCommand == NULL) + outgoingCommand = enet_protocol_find_sent_reliable_command (& peer -> outgoingSendReliableCommands, reliableSequenceNumber, channelID); wasSent = 0; } @@ -320,6 +340,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; peer -> connectID = command -> connect.connectID; peer -> address = host -> receivedAddress; + peer -> mtu = host -> mtu; peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> connect.outgoingPeerID); peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.incomingBandwidth); peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.outgoingBandwidth); @@ -364,7 +385,8 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) mtu = ENET_PROTOCOL_MAXIMUM_MTU; - peer -> mtu = mtu; + if (mtu < peer -> mtu) + peer -> mtu = mtu; if (host -> outgoingBandwidth == 0 && peer -> incomingBandwidth == 0) @@ -531,7 +553,8 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength); * currentData += fragmentLength; - if (fragmentLength > host -> maximumPacketSize || + if (fragmentLength <= 0 || + fragmentLength > host -> maximumPacketSize || * currentData < host -> receivedData || * currentData > & host -> receivedData [host -> receivedDataLength]) return -1; @@ -555,6 +578,7 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT || fragmentNumber >= fragmentCount || totalLength > host -> maximumPacketSize || + totalLength < fragmentCount || fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset) return -1; @@ -614,7 +638,7 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet fragmentLength); if (startCommand -> fragmentsRemaining <= 0) - enet_peer_dispatch_incoming_reliable_commands (peer, channel); + enet_peer_dispatch_incoming_reliable_commands (peer, channel, NULL); } return 0; @@ -732,7 +756,7 @@ enet_protocol_handle_send_unreliable_fragment (ENetHost * host, ENetPeer * peer, fragmentLength); if (startCommand -> fragmentsRemaining <= 0) - enet_peer_dispatch_incoming_unreliable_commands (peer, channel); + enet_peer_dispatch_incoming_unreliable_commands (peer, channel, NULL); } return 0; @@ -842,42 +866,53 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * if (ENET_TIME_LESS (host -> serviceTime, receivedSentTime)) return 0; - peer -> lastReceiveTime = host -> serviceTime; - peer -> earliestTimeout = 0; - roundTripTime = ENET_TIME_DIFFERENCE (host -> serviceTime, receivedSentTime); + roundTripTime = ENET_MAX (roundTripTime, 1); - enet_peer_throttle (peer, roundTripTime); - - peer -> roundTripTimeVariance -= peer -> roundTripTimeVariance / 4; - - if (roundTripTime >= peer -> roundTripTime) + if (peer -> lastReceiveTime > 0) { - peer -> roundTripTime += (roundTripTime - peer -> roundTripTime) / 8; - peer -> roundTripTimeVariance += (roundTripTime - peer -> roundTripTime) / 4; + enet_peer_throttle (peer, roundTripTime); + + peer -> roundTripTimeVariance -= peer -> roundTripTimeVariance / 4; + + if (roundTripTime >= peer -> roundTripTime) + { + enet_uint32 diff = roundTripTime - peer -> roundTripTime; + peer -> roundTripTimeVariance += diff / 4; + peer -> roundTripTime += diff / 8; + } + else + { + enet_uint32 diff = peer -> roundTripTime - roundTripTime; + peer -> roundTripTimeVariance += diff / 4; + peer -> roundTripTime -= diff / 8; + } } else { - peer -> roundTripTime -= (peer -> roundTripTime - roundTripTime) / 8; - peer -> roundTripTimeVariance += (peer -> roundTripTime - roundTripTime) / 4; + peer -> roundTripTime = roundTripTime; + peer -> roundTripTimeVariance = (roundTripTime + 1) / 2; } if (peer -> roundTripTime < peer -> lowestRoundTripTime) peer -> lowestRoundTripTime = peer -> roundTripTime; - if (peer -> roundTripTimeVariance > peer -> highestRoundTripTimeVariance) + if (peer -> roundTripTimeVariance > peer -> highestRoundTripTimeVariance) peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; if (peer -> packetThrottleEpoch == 0 || ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> packetThrottleEpoch) >= peer -> packetThrottleInterval) { peer -> lastRoundTripTime = peer -> lowestRoundTripTime; - peer -> lastRoundTripTimeVariance = peer -> highestRoundTripTimeVariance; + peer -> lastRoundTripTimeVariance = ENET_MAX (peer -> highestRoundTripTimeVariance, 1); peer -> lowestRoundTripTime = peer -> roundTripTime; peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; peer -> packetThrottleEpoch = host -> serviceTime; } + peer -> lastReceiveTime = ENET_MAX (host -> serviceTime, 1); + peer -> earliestTimeout = 0; + receivedReliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedReliableSequenceNumber); commandNumber = enet_protocol_remove_sent_reliable_command (peer, receivedReliableSequenceNumber, command -> header.channelID); @@ -899,9 +934,7 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * break; case ENET_PEER_STATE_DISCONNECT_LATER: - if (enet_list_empty (& peer -> outgoingReliableCommands) && - enet_list_empty (& peer -> outgoingUnreliableCommands) && - enet_list_empty (& peer -> sentReliableCommands)) + if (! enet_peer_has_outgoing_commands (peer)) enet_peer_disconnect (peer, peer -> eventData); break; @@ -1253,7 +1286,7 @@ enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) } } - return -1; + return 0; } static void @@ -1273,7 +1306,7 @@ enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer) buffer >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || peer -> mtu - host -> packetSize < sizeof (ENetProtocolAcknowledge)) { - host -> continueSending = 1; + peer -> flags |= ENET_PEER_FLAG_CONTINUE_SENDING; break; } @@ -1309,115 +1342,15 @@ enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer) host -> bufferCount = buffer - host -> buffers; } -static void -enet_protocol_send_unreliable_outgoing_commands (ENetHost * host, ENetPeer * peer) -{ - ENetProtocol * command = & host -> commands [host -> commandCount]; - ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; - ENetOutgoingCommand * outgoingCommand; - ENetListIterator currentCommand; - - currentCommand = enet_list_begin (& peer -> outgoingUnreliableCommands); - - while (currentCommand != enet_list_end (& peer -> outgoingUnreliableCommands)) - { - size_t commandSize; - - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK]; - - if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || - buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || - peer -> mtu - host -> packetSize < commandSize || - (outgoingCommand -> packet != NULL && - peer -> mtu - host -> packetSize < commandSize + outgoingCommand -> fragmentLength)) - { - host -> continueSending = 1; - - break; - } - - currentCommand = enet_list_next (currentCommand); - - if (outgoingCommand -> packet != NULL && outgoingCommand -> fragmentOffset == 0) - { - peer -> packetThrottleCounter += ENET_PEER_PACKET_THROTTLE_COUNTER; - peer -> packetThrottleCounter %= ENET_PEER_PACKET_THROTTLE_SCALE; - - if (peer -> packetThrottleCounter > peer -> packetThrottle) - { - enet_uint16 reliableSequenceNumber = outgoingCommand -> reliableSequenceNumber, - unreliableSequenceNumber = outgoingCommand -> unreliableSequenceNumber; - for (;;) - { - -- outgoingCommand -> packet -> referenceCount; - - if (outgoingCommand -> packet -> referenceCount == 0) - enet_packet_destroy (outgoingCommand -> packet); - - enet_list_remove (& outgoingCommand -> outgoingCommandList); - enet_free (outgoingCommand); - - if (currentCommand == enet_list_end (& peer -> outgoingUnreliableCommands)) - break; - - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - if (outgoingCommand -> reliableSequenceNumber != reliableSequenceNumber || - outgoingCommand -> unreliableSequenceNumber != unreliableSequenceNumber) - break; - - currentCommand = enet_list_next (currentCommand); - } - - continue; - } - } - - buffer -> data = command; - buffer -> dataLength = commandSize; - - host -> packetSize += buffer -> dataLength; - - * command = outgoingCommand -> command; - - enet_list_remove (& outgoingCommand -> outgoingCommandList); - - if (outgoingCommand -> packet != NULL) - { - ++ buffer; - - buffer -> data = outgoingCommand -> packet -> data + outgoingCommand -> fragmentOffset; - buffer -> dataLength = outgoingCommand -> fragmentLength; - - host -> packetSize += buffer -> dataLength; - - enet_list_insert (enet_list_end (& peer -> sentUnreliableCommands), outgoingCommand); - } - else - enet_free (outgoingCommand); - - ++ command; - ++ buffer; - } - - host -> commandCount = command - host -> commands; - host -> bufferCount = buffer - host -> buffers; - - if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER && - enet_list_empty (& peer -> outgoingReliableCommands) && - enet_list_empty (& peer -> outgoingUnreliableCommands) && - enet_list_empty (& peer -> sentReliableCommands)) - enet_peer_disconnect (peer, peer -> eventData); -} - static int enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * event) { ENetOutgoingCommand * outgoingCommand; - ENetListIterator currentCommand, insertPosition; + ENetListIterator currentCommand, insertPosition, insertSendReliablePosition; currentCommand = enet_list_begin (& peer -> sentReliableCommands); - insertPosition = enet_list_begin (& peer -> outgoingReliableCommands); + insertPosition = enet_list_begin (& peer -> outgoingCommands); + insertSendReliablePosition = enet_list_begin (& peer -> outgoingSendReliableCommands); while (currentCommand != enet_list_end (& peer -> sentReliableCommands)) { @@ -1434,7 +1367,7 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even if (peer -> earliestTimeout != 0 && (ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMaximum || - (outgoingCommand -> roundTripTimeout >= outgoingCommand -> roundTripTimeoutLimit && + ((1 << (outgoingCommand -> sendAttempts - 1)) >= peer -> timeoutLimit && ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMinimum))) { enet_protocol_notify_disconnect (host, peer, event); @@ -1442,14 +1375,18 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even return 1; } - if (outgoingCommand -> packet != NULL) - peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; - ++ peer -> packetsLost; outgoingCommand -> roundTripTimeout *= 2; - enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList)); + if (outgoingCommand -> packet != NULL) + { + peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; + + enet_list_insert (insertSendReliablePosition, enet_list_remove (& outgoingCommand -> outgoingCommandList)); + } + else + enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList)); if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) && ! enet_list_empty (& peer -> sentReliableCommands)) @@ -1464,61 +1401,79 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even } static int -enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) +enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer, ENetList * sentUnreliableCommands) { ENetProtocol * command = & host -> commands [host -> commandCount]; ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; ENetOutgoingCommand * outgoingCommand; - ENetListIterator currentCommand; - ENetChannel *channel; - enet_uint16 reliableWindow; + ENetListIterator currentCommand, currentSendReliableCommand; + ENetChannel *channel = NULL; + enet_uint16 reliableWindow = 0; size_t commandSize; - int windowExceeded = 0, windowWrap = 0, canPing = 1; + int windowWrap = 0, canPing = 1; - currentCommand = enet_list_begin (& peer -> outgoingReliableCommands); - - while (currentCommand != enet_list_end (& peer -> outgoingReliableCommands)) + currentCommand = enet_list_begin (& peer -> outgoingCommands); + currentSendReliableCommand = enet_list_begin (& peer -> outgoingSendReliableCommands); + + for (;;) { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; + if (currentCommand != enet_list_end (& peer -> outgoingCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; - channel = outgoingCommand -> command.header.channelID < peer -> channelCount ? & peer -> channels [outgoingCommand -> command.header.channelID] : NULL; - reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - if (channel != NULL) - { - if (! windowWrap && - outgoingCommand -> sendAttempts < 1 && - ! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) && - (channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE || - channel -> usedReliableWindows & ((((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) << reliableWindow) | - (((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow))))) - windowWrap = 1; - if (windowWrap) - { - currentCommand = enet_list_next (currentCommand); - - continue; - } + if (currentSendReliableCommand != enet_list_end (& peer -> outgoingSendReliableCommands) && + ENET_TIME_LESS (((ENetOutgoingCommand *) currentSendReliableCommand) -> queueTime, outgoingCommand -> queueTime)) + goto useSendReliableCommand; + + currentCommand = enet_list_next (currentCommand); } - - if (outgoingCommand -> packet != NULL) + else + if (currentSendReliableCommand != enet_list_end (& peer -> outgoingSendReliableCommands)) { - if (! windowExceeded) + useSendReliableCommand: + outgoingCommand = (ENetOutgoingCommand *) currentSendReliableCommand; + currentSendReliableCommand = enet_list_next (currentSendReliableCommand); + } + else + break; + + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + { + channel = outgoingCommand -> command.header.channelID < peer -> channelCount ? & peer -> channels [outgoingCommand -> command.header.channelID] : NULL; + reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (channel != NULL) + { + if (windowWrap) + continue; + else + if (outgoingCommand -> sendAttempts < 1 && + ! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) && + (channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE || + channel -> usedReliableWindows & ((((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) << reliableWindow) | + (((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow))))) + { + windowWrap = 1; + currentSendReliableCommand = enet_list_end (& peer -> outgoingSendReliableCommands); + + continue; + } + } + + if (outgoingCommand -> packet != NULL) { enet_uint32 windowSize = (peer -> packetThrottle * peer -> windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE; - + if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > ENET_MAX (windowSize, peer -> mtu)) - windowExceeded = 1; - } - if (windowExceeded) - { - currentCommand = enet_list_next (currentCommand); + { + currentSendReliableCommand = enet_list_end (& peer -> outgoingSendReliableCommands); - continue; + continue; + } } + + canPing = 0; } - canPing = 0; - commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK]; if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || @@ -1526,40 +1481,82 @@ enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) (outgoingCommand -> packet != NULL && (enet_uint16) (peer -> mtu - host -> packetSize) < (enet_uint16) (commandSize + outgoingCommand -> fragmentLength))) { - host -> continueSending = 1; - + peer -> flags |= ENET_PEER_FLAG_CONTINUE_SENDING; + break; } - currentCommand = enet_list_next (currentCommand); - - if (channel != NULL && outgoingCommand -> sendAttempts < 1) + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) { - channel -> usedReliableWindows |= 1 << reliableWindow; - ++ channel -> reliableWindows [reliableWindow]; - } + if (channel != NULL && outgoingCommand -> sendAttempts < 1) + { + channel -> usedReliableWindows |= 1 << reliableWindow; + ++ channel -> reliableWindows [reliableWindow]; + } - ++ outgoingCommand -> sendAttempts; + ++ outgoingCommand -> sendAttempts; - if (outgoingCommand -> roundTripTimeout == 0) - { - outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance; - outgoingCommand -> roundTripTimeoutLimit = peer -> timeoutLimit * outgoingCommand -> roundTripTimeout; + if (outgoingCommand -> roundTripTimeout == 0) + outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance; + + if (enet_list_empty (& peer -> sentReliableCommands)) + peer -> nextTimeout = host -> serviceTime + outgoingCommand -> roundTripTimeout; + + enet_list_insert (enet_list_end (& peer -> sentReliableCommands), + enet_list_remove (& outgoingCommand -> outgoingCommandList)); + + outgoingCommand -> sentTime = host -> serviceTime; + + host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME; + + peer -> reliableDataInTransit += outgoingCommand -> fragmentLength; } + else + { + if (outgoingCommand -> packet != NULL && outgoingCommand -> fragmentOffset == 0) + { + peer -> packetThrottleCounter += ENET_PEER_PACKET_THROTTLE_COUNTER; + peer -> packetThrottleCounter %= ENET_PEER_PACKET_THROTTLE_SCALE; - if (enet_list_empty (& peer -> sentReliableCommands)) - peer -> nextTimeout = host -> serviceTime + outgoingCommand -> roundTripTimeout; + if (peer -> packetThrottleCounter > peer -> packetThrottle) + { + enet_uint16 reliableSequenceNumber = outgoingCommand -> reliableSequenceNumber, + unreliableSequenceNumber = outgoingCommand -> unreliableSequenceNumber; + for (;;) + { + -- outgoingCommand -> packet -> referenceCount; - enet_list_insert (enet_list_end (& peer -> sentReliableCommands), - enet_list_remove (& outgoingCommand -> outgoingCommandList)); + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); - outgoingCommand -> sentTime = host -> serviceTime; + enet_list_remove (& outgoingCommand -> outgoingCommandList); + enet_free (outgoingCommand); + + if (currentCommand == enet_list_end (& peer -> outgoingCommands)) + break; + + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + if (outgoingCommand -> reliableSequenceNumber != reliableSequenceNumber || + outgoingCommand -> unreliableSequenceNumber != unreliableSequenceNumber) + break; + + currentCommand = enet_list_next (currentCommand); + } + + continue; + } + } + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + + if (outgoingCommand -> packet != NULL) + enet_list_insert (enet_list_end (sentUnreliableCommands), outgoingCommand); + } buffer -> data = command; buffer -> dataLength = commandSize; host -> packetSize += buffer -> dataLength; - host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME; * command = outgoingCommand -> command; @@ -1571,9 +1568,10 @@ enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) buffer -> dataLength = outgoingCommand -> fragmentLength; host -> packetSize += outgoingCommand -> fragmentLength; - - peer -> reliableDataInTransit += outgoingCommand -> fragmentLength; } + else + if (! (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)) + enet_free (outgoingCommand); ++ peer -> packetsSent; @@ -1584,6 +1582,11 @@ enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) host -> commandCount = command - host -> commands; host -> bufferCount = buffer - host -> buffers; + if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER && + ! enet_peer_has_outgoing_commands (peer) && + enet_list_empty (sentUnreliableCommands)) + enet_peer_disconnect (peer, peer -> eventData); + return canPing; } @@ -1592,22 +1595,24 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch { enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)]; ENetProtocolHeader * header = (ENetProtocolHeader *) headerData; - ENetPeer * currentPeer; - int sentLength; + int sentLength = 0; size_t shouldCompress = 0; - - host -> continueSending = 1; + ENetList sentUnreliableCommands; - while (host -> continueSending) - for (host -> continueSending = 0, - currentPeer = host -> peers; + enet_list_clear (& sentUnreliableCommands); + + for (int sendPass = 0, continueSending = 0; sendPass <= continueSending; ++ sendPass) + for (ENetPeer * currentPeer = host -> peers; currentPeer < & host -> peers [host -> peerCount]; ++ currentPeer) { if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED || - currentPeer -> state == ENET_PEER_STATE_ZOMBIE) + currentPeer -> state == ENET_PEER_STATE_ZOMBIE || + (sendPass > 0 && ! (currentPeer -> flags & ENET_PEER_FLAG_CONTINUE_SENDING))) continue; + currentPeer -> flags &= ~ ENET_PEER_FLAG_CONTINUE_SENDING; + host -> headerFlags = 0; host -> commandCount = 0; host -> bufferCount = 1; @@ -1624,24 +1629,22 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE) return 1; else - continue; + goto nextPeer; } - if ((enet_list_empty (& currentPeer -> outgoingReliableCommands) || - enet_protocol_send_reliable_outgoing_commands (host, currentPeer)) && + if (((enet_list_empty (& currentPeer -> outgoingCommands) && + enet_list_empty (& currentPeer -> outgoingSendReliableCommands)) || + enet_protocol_check_outgoing_commands (host, currentPeer, & sentUnreliableCommands)) && enet_list_empty (& currentPeer -> sentReliableCommands) && ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= currentPeer -> pingInterval && currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing)) { enet_peer_ping (currentPeer); - enet_protocol_send_reliable_outgoing_commands (host, currentPeer); + enet_protocol_check_outgoing_commands (host, currentPeer, & sentUnreliableCommands); } - - if (! enet_list_empty (& currentPeer -> outgoingUnreliableCommands)) - enet_protocol_send_unreliable_outgoing_commands (host, currentPeer); if (host -> commandCount == 0) - continue; + goto nextPeer; if (currentPeer -> packetLossEpoch == 0) currentPeer -> packetLossEpoch = host -> serviceTime; @@ -1652,21 +1655,11 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> 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 (& currentPeer -> outgoingReliableCommands), enet_list_size (& currentPeer -> outgoingUnreliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0); + printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %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 (& currentPeer -> outgoingCommands) + enet_list_size (& currentPeer -> outgoingSendReliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0); #endif - - currentPeer -> packetLossVariance -= currentPeer -> packetLossVariance / 4; - if (packetLoss >= currentPeer -> packetLoss) - { - currentPeer -> packetLoss += (packetLoss - currentPeer -> packetLoss) / 8; - currentPeer -> packetLossVariance += (packetLoss - currentPeer -> packetLoss) / 4; - } - else - { - currentPeer -> packetLoss -= (currentPeer -> packetLoss - packetLoss) / 8; - currentPeer -> packetLossVariance += (currentPeer -> packetLoss - packetLoss) / 4; - } + currentPeer -> packetLossVariance = (currentPeer -> packetLossVariance * 3 + ENET_DIFFERENCE (packetLoss, currentPeer -> packetLoss)) / 4; + currentPeer -> packetLoss = (currentPeer -> packetLoss * 7 + packetLoss) / 8; currentPeer -> packetLossEpoch = host -> serviceTime; currentPeer -> packetsSent = 0; @@ -1724,13 +1717,17 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount); - enet_protocol_remove_sent_unreliable_commands (currentPeer); + enet_protocol_remove_sent_unreliable_commands (currentPeer, & sentUnreliableCommands); if (sentLength < 0) return -1; host -> totalSentData += sentLength; host -> totalSentPackets ++; + + nextPeer: + if (currentPeer -> flags & ENET_PEER_FLAG_CONTINUE_SENDING) + continueSending = sendPass + 1; } return 0; diff --git a/Externals/enet/unix.c b/Externals/enet/unix.c index 90e55b146b..2c7d847dd9 100644 --- a/Externals/enet/unix.c +++ b/Externals/enet/unix.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -51,10 +50,10 @@ #endif #ifdef HAS_POLL -#include +#include #endif -#ifndef HAS_SOCKLEN_T +#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined) typedef int socklen_t; #endif @@ -101,6 +100,19 @@ enet_time_set (enet_uint32 newTimeBase) timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase; } +int +enet_address_set_host_ip (ENetAddress * address, const char * name) +{ +#ifdef HAS_INET_PTON + if (! inet_pton (AF_INET, name, & address -> host)) +#else + if (! inet_aton (name, (struct in_addr *) & address -> host)) +#endif + return -1; + + return 0; +} + int enet_address_set_host (ENetAddress * address, const char * name) { @@ -136,7 +148,7 @@ enet_address_set_host (ENetAddress * address, const char * name) char buffer [2048]; int errnum; -#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__GNU__) gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); #else hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum); @@ -153,14 +165,7 @@ enet_address_set_host (ENetAddress * address, const char * name) } #endif -#ifdef HAS_INET_PTON - if (! inet_pton (AF_INET, name, & address -> host)) -#else - if (! inet_aton (name, (struct in_addr *) & address -> host)) -#endif - return -1; - - return 0; + return enet_address_set_host_ip (address, name); } int @@ -204,7 +209,7 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng return 0; } if (err != EAI_NONAME) - return 0; + return -1; #else struct in_addr in; struct hostent * hostEntry = NULL; @@ -215,7 +220,7 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng in.s_addr = address -> host; -#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__GNU__) gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); #else hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum); @@ -343,6 +348,10 @@ enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int)); break; + case ENET_SOCKOPT_TTL: + result = setsockopt (socket, IPPROTO_IP, IP_TTL, (char *) & value, sizeof (int)); + break; + default: break; } @@ -361,6 +370,11 @@ enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value) result = getsockopt (socket, SOL_SOCKET, SO_ERROR, value, & len); break; + case ENET_SOCKOPT_TTL: + len = sizeof (int); + result = getsockopt (socket, IPPROTO_IP, IP_TTL, (char *) value, & len); + break; + default: break; } diff --git a/Externals/enet/win32.c b/Externals/enet/win32.c index 5cc167997c..0953466a3d 100644 --- a/Externals/enet/win32.c +++ b/Externals/enet/win32.c @@ -8,6 +8,7 @@ #include "enet/enet.h" #include #include +#include static enet_uint32 timeBase = 0; @@ -59,6 +60,32 @@ enet_time_set (enet_uint32 newTimeBase) timeBase = (enet_uint32) timeGetTime () - newTimeBase; } +int +enet_address_set_host_ip (ENetAddress * address, const char * name) +{ + enet_uint8 vals [4] = { 0, 0, 0, 0 }; + int i; + + for (i = 0; i < 4; ++ i) + { + const char * next = name + 1; + if (* name != '0') + { + long val = strtol (name, (char **) & next, 10); + if (val < 0 || val > 255 || next == name || next - name > 3) + return -1; + vals [i] = (enet_uint8) val; + } + + if (* next != (i < 3 ? '.' : '\0')) + return -1; + name = next + 1; + } + + memcpy (& address -> host, vals, sizeof (enet_uint32)); + return 0; +} + int enet_address_set_host (ENetAddress * address, const char * name) { @@ -67,13 +94,7 @@ enet_address_set_host (ENetAddress * address, const char * name) hostEntry = gethostbyname (name); if (hostEntry == NULL || hostEntry -> h_addrtype != AF_INET) - { - unsigned long host = inet_addr (name); - if (host == INADDR_NONE) - return -1; - address -> host = host; - return 0; - } + return enet_address_set_host_ip (address, name); address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; @@ -211,6 +232,10 @@ enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int)); break; + case ENET_SOCKOPT_TTL: + result = setsockopt (socket, IPPROTO_IP, IP_TTL, (char *) & value, sizeof (int)); + break; + default: break; } @@ -228,6 +253,11 @@ enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value) result = getsockopt (socket, SOL_SOCKET, SO_ERROR, (char *) value, & len); break; + case ENET_SOCKOPT_TTL: + len = sizeof(int); + result = getsockopt (socket, IPPROTO_IP, IP_TTL, (char *) value, & len); + break; + default: break; } @@ -296,7 +326,7 @@ enet_socket_send (ENetSocket socket, size_t bufferCount) { struct sockaddr_in sin; - DWORD sentLength; + DWORD sentLength = 0; if (address != NULL) { @@ -334,7 +364,7 @@ enet_socket_receive (ENetSocket socket, { INT sinLength = sizeof (struct sockaddr_in); DWORD flags = 0, - recvLength; + recvLength = 0; struct sockaddr_in sin; if (WSARecvFrom (socket, diff --git a/Externals/rcheevos/CMakeLists.txt b/Externals/rcheevos/CMakeLists.txt new file mode 100644 index 0000000000..0fea1f9873 --- /dev/null +++ b/Externals/rcheevos/CMakeLists.txt @@ -0,0 +1,49 @@ +add_library(rcheevos + rcheevos/include/rc_api_editor.h + rcheevos/include/rc_api_info.h + rcheevos/include/rc_api_request.h + rcheevos/include/rc_api_runtime.h + rcheevos/include/rc_api_user.h + rcheevos/include/rc_consoles.h + rcheevos/include/rc_error.h + rcheevos/include/rc_hash.h + rcheevos/include/rcheevos.h + rcheevos/include/rc_runtime.h + rcheevos/include/rc_runtime_types.h + rcheevos/include/rc_url.h + rcheevos/src/rapi/rc_api_common.c + rcheevos/src/rapi/rc_api_common.h + rcheevos/src/rapi/rc_api_editor.c + rcheevos/src/rapi/rc_api_info.c + rcheevos/src/rapi/rc_api_runtime.c + rcheevos/src/rapi/rc_api_user.c + rcheevos/src/rcheevos/alloc.c + rcheevos/src/rcheevos/compat.c + rcheevos/src/rcheevos/condition.c + rcheevos/src/rcheevos/condset.c + rcheevos/src/rcheevos/consoleinfo.c + rcheevos/src/rcheevos/format.c + rcheevos/src/rcheevos/lboard.c + rcheevos/src/rcheevos/memref.c + rcheevos/src/rcheevos/operand.c + rcheevos/src/rcheevos/rc_compat.h + rcheevos/src/rcheevos/rc_internal.h + rcheevos/src/rcheevos/rc_validate.c + rcheevos/src/rcheevos/rc_validate.h + rcheevos/src/rcheevos/richpresence.c + rcheevos/src/rcheevos/runtime.c + rcheevos/src/rcheevos/runtime_progress.c + rcheevos/src/rcheevos/trigger.c + rcheevos/src/rcheevos/value.c + rcheevos/src/rhash/hash.c + rcheevos/src/rhash/md5.c + rcheevos/src/rhash/md5.h + rcheevos/src/rurl/url.c +) + +target_include_directories(rcheevos PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/rcheevos/include") +target_include_directories(rcheevos INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}") +target_compile_definitions(rcheevos PRIVATE "RC_DISABLE_LUA=1" "RCHEEVOS_URL_SSL") +if(CMAKE_SYSTEM_NAME MATCHES "Windows") + target_compile_definitions(rcheevos PRIVATE "_CRT_SECURE_NO_WARNINGS") +endif() diff --git a/Externals/rcheevos/exports.props b/Externals/rcheevos/exports.props new file mode 100644 index 0000000000..d5e26ded5e --- /dev/null +++ b/Externals/rcheevos/exports.props @@ -0,0 +1,13 @@ + + + + + $(ExternalsDir)rcheevos;%(AdditionalIncludeDirectories) + + + + + {CC99A910-3752-4465-95AA-7DC240D92A99} + + + diff --git a/Externals/rcheevos/rcheevos b/Externals/rcheevos/rcheevos new file mode 160000 index 0000000000..c5304a61bc --- /dev/null +++ b/Externals/rcheevos/rcheevos @@ -0,0 +1 @@ +Subproject commit c5304a61bcf256ae80fcd1c8f64ad9646aaea757 diff --git a/Externals/rcheevos/rcheevos.vcxproj b/Externals/rcheevos/rcheevos.vcxproj new file mode 100644 index 0000000000..cde8fd6ecd --- /dev/null +++ b/Externals/rcheevos/rcheevos.vcxproj @@ -0,0 +1,71 @@ + + + + + + {CC99A910-3752-4465-95AA-7DC240D92A99} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RC_DISABLE_LUA;RCHEEVOS_URL_SSL;%(PreprocessorDefinitions) + $(ProjectDir)rcheevos\include;%(AdditionalIncludeDirectories) + + + + + + \ No newline at end of file diff --git a/Source/Core/Common/CommonPaths.h b/Source/Core/Common/CommonPaths.h index a72dcf19e3..2bc56339e1 100644 --- a/Source/Core/Common/CommonPaths.h +++ b/Source/Core/Common/CommonPaths.h @@ -112,6 +112,7 @@ #define LOGGER_CONFIG "Logger.ini" #define DUALSHOCKUDPCLIENT_CONFIG "DSUClient.ini" #define FREELOOK_CONFIG "FreeLook.ini" +#define RETROACHIEVEMENTS_CONFIG "RetroAchievements.ini" // Files in the directory returned by GetUserPath(D_LOGS_IDX) #define MAIN_LOG "dolphin.log" diff --git a/Source/Core/Common/Config/Config.cpp b/Source/Core/Common/Config/Config.cpp index 4a55ab5b7b..ff3a8c6783 100644 --- a/Source/Core/Common/Config/Config.cpp +++ b/Source/Core/Common/Config/Config.cpp @@ -160,7 +160,8 @@ static const std::map system_to_name = { {System::DualShockUDPClient, "DualShockUDPClient"}, {System::FreeLook, "FreeLook"}, {System::Session, "Session"}, - {System::GameSettingsOnly, "GameSettingsOnly"}}; + {System::GameSettingsOnly, "GameSettingsOnly"}, + {System::Achievements, "Achievements"}}; const std::string& GetSystemName(System system) { diff --git a/Source/Core/Common/Config/Enums.h b/Source/Core/Common/Config/Enums.h index 1f6d0a1966..69d8c954c3 100644 --- a/Source/Core/Common/Config/Enums.h +++ b/Source/Core/Common/Config/Enums.h @@ -34,6 +34,7 @@ enum class System FreeLook, Session, GameSettingsOnly, + Achievements, }; constexpr std::array SEARCH_ORDER{{ diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index d456952980..b97185e769 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -847,6 +847,8 @@ static void RebuildUserDirectories(unsigned int dir_index) s_user_paths[F_DUALSHOCKUDPCLIENTCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DUALSHOCKUDPCLIENT_CONFIG; s_user_paths[F_FREELOOKCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + FREELOOK_CONFIG; + s_user_paths[F_RETROACHIEVEMENTSCONFIG_IDX] = + s_user_paths[D_CONFIG_IDX] + RETROACHIEVEMENTS_CONFIG; s_user_paths[F_MAINLOG_IDX] = s_user_paths[D_LOGS_IDX] + MAIN_LOG; s_user_paths[F_MEM1DUMP_IDX] = s_user_paths[D_DUMP_IDX] + MEM1_DUMP; s_user_paths[F_MEM2DUMP_IDX] = s_user_paths[D_DUMP_IDX] + MEM2_DUMP; diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index cadabbd541..f6dc396966 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -85,6 +85,7 @@ enum F_DUALSHOCKUDPCLIENTCONFIG_IDX, F_FREELOOKCONFIG_IDX, F_GBABIOS_IDX, + F_RETROACHIEVEMENTSCONFIG_IDX, NUM_PATH_INDICES }; diff --git a/Source/Core/Common/TraversalClient.cpp b/Source/Core/Common/TraversalClient.cpp index 4c416a0bdb..f3ab481a51 100644 --- a/Source/Core/Common/TraversalClient.cpp +++ b/Source/Core/Common/TraversalClient.cpp @@ -333,6 +333,7 @@ bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 liste g_MainNetHost.reset(); return false; } + host->mtu = std::min(host->mtu, NetPlay::MAX_ENET_MTU); g_MainNetHost.reset(host); g_TraversalClient.reset(new TraversalClient(g_MainNetHost.get(), server, server_port)); } diff --git a/Source/Core/Common/WorkQueueThread.h b/Source/Core/Common/WorkQueueThread.h index be3c3198d4..be723299b2 100644 --- a/Source/Core/Common/WorkQueueThread.h +++ b/Source/Core/Common/WorkQueueThread.h @@ -124,7 +124,7 @@ public: if (m_idle && !m_cancelling.load()) return; - m_wait_cond_var.wait(lg, [&] { return m_idle && m_cancelling.load(); }); + m_wait_cond_var.wait(lg, [&] { return m_idle && !m_cancelling; }); } // If the worker polls IsCanceling(), it can abort its work when Cancelling diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp new file mode 100644 index 0000000000..7e0fa5a9d9 --- /dev/null +++ b/Source/Core/Core/AchievementManager.cpp @@ -0,0 +1,114 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef USE_RETRO_ACHIEVEMENTS + +#include "Core/AchievementManager.h" +#include "Common/HttpRequest.h" +#include "Common/WorkQueueThread.h" +#include "Config/AchievementSettings.h" +#include "Core/Core.h" + +AchievementManager* AchievementManager::GetInstance() +{ + static AchievementManager s_instance; + return &s_instance; +} + +void AchievementManager::Init() +{ + if (!m_is_runtime_initialized && Config::Get(Config::RA_ENABLED)) + { + rc_runtime_init(&m_runtime); + m_is_runtime_initialized = true; + m_queue.Reset("AchievementManagerQueue", [](const std::function& func) { func(); }); + LoginAsync("", [](ResponseType r_type) {}); + } +} + +AchievementManager::ResponseType AchievementManager::Login(const std::string& password) +{ + return VerifyCredentials(password); +} + +void AchievementManager::LoginAsync(const std::string& password, const LoginCallback& callback) +{ + m_queue.EmplaceItem([this, password, callback] { callback(VerifyCredentials(password)); }); +} + +bool AchievementManager::IsLoggedIn() const +{ + return m_login_data.response.succeeded; +} + +void AchievementManager::Logout() +{ + Config::SetBaseOrCurrent(Config::RA_API_TOKEN, ""); + rc_api_destroy_login_response(&m_login_data); + m_login_data.response.succeeded = 0; +} + +void AchievementManager::Shutdown() +{ + m_is_runtime_initialized = false; + m_queue.Shutdown(); + // DON'T log out - keep those credentials for next run. + rc_api_destroy_login_response(&m_login_data); + m_login_data.response.succeeded = 0; + rc_runtime_destroy(&m_runtime); +} + +AchievementManager::ResponseType AchievementManager::VerifyCredentials(const std::string& password) +{ + std::string username = Config::Get(Config::RA_USERNAME); + std::string api_token = Config::Get(Config::RA_API_TOKEN); + rc_api_login_request_t login_request = { + .username = username.c_str(), .api_token = api_token.c_str(), .password = password.c_str()}; + ResponseType r_type = Request( + login_request, &m_login_data, rc_api_init_login_request, rc_api_process_login_response); + if (r_type == ResponseType::SUCCESS) + Config::SetBaseOrCurrent(Config::RA_API_TOKEN, m_login_data.api_token); + return r_type; +} + +// Every RetroAchievements API call, with only a partial exception for fetch_image, follows +// the same design pattern (here, X is the name of the call): +// Create a specific rc_api_X_request_t struct and populate with the necessary values +// Call rc_api_init_X_request to convert this into a generic rc_api_request_t struct +// Perform the HTTP request using the url and post_data in the rc_api_request_t struct +// Call rc_api_process_X_response to convert the raw string HTTP response into a +// rc_api_X_response_t struct +// Use the data in the rc_api_X_response_t struct as needed +// Call rc_api_destroy_X_response when finished with the response struct to free memory +template +AchievementManager::ResponseType AchievementManager::Request( + RcRequest rc_request, RcResponse* rc_response, + const std::function& init_request, + const std::function& process_response) +{ + rc_api_request_t api_request; + Common::HttpRequest http_request; + init_request(&api_request, &rc_request); + auto http_response = http_request.Post(api_request.url, api_request.post_data); + rc_api_destroy_request(&api_request); + if (http_response.has_value() && http_response->size() > 0) + { + const std::string response_str(http_response->begin(), http_response->end()); + process_response(rc_response, response_str.c_str()); + if (rc_response->response.succeeded) + { + return ResponseType::SUCCESS; + } + else + { + Logout(); + return ResponseType::INVALID_CREDENTIALS; + } + } + else + { + return ResponseType::CONNECTION_FAILED; + } +} + +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h new file mode 100644 index 0000000000..91fd9339ef --- /dev/null +++ b/Source/Core/Core/AchievementManager.h @@ -0,0 +1,54 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifdef USE_RETRO_ACHIEVEMENTS +#include +#include +#include +#include + +#include +#include + +#include "Common/Event.h" +#include "Common/WorkQueueThread.h" + +class AchievementManager +{ +public: + enum class ResponseType + { + SUCCESS, + INVALID_CREDENTIALS, + CONNECTION_FAILED, + UNKNOWN_FAILURE + }; + using LoginCallback = std::function; + + static AchievementManager* GetInstance(); + void Init(); + ResponseType Login(const std::string& password); + void LoginAsync(const std::string& password, const LoginCallback& callback); + bool IsLoggedIn() const; + void Logout(); + void Shutdown(); + +private: + AchievementManager() = default; + + ResponseType VerifyCredentials(const std::string& password); + + template + ResponseType Request(RcRequest rc_request, RcResponse* rc_response, + const std::function& init_request, + const std::function& process_response); + + rc_runtime_t m_runtime{}; + bool m_is_runtime_initialized = false; + rc_api_login_response_t m_login_data{}; + Common::WorkQueueThread> m_queue; +}; // class AchievementManager + +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 6a0e52d686..bd6b603048 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -1,4 +1,6 @@ add_library(core + AchievementManager.cpp + AchievementManager.h ActionReplay.cpp ActionReplay.h ARDecrypt.cpp @@ -21,6 +23,8 @@ add_library(core CheatSearch.cpp CheatSearch.h CommonTitles.h + Config/AchievementSettings.cpp + Config/AchievementSettings.h Config/DefaultLocale.cpp Config/DefaultLocale.h Config/FreeLookSettings.cpp @@ -751,3 +755,8 @@ if(MSVC) # Add precompiled header target_link_libraries(core PRIVATE use_pch) endif() + +if(USE_RETRO_ACHIEVEMENTS) + target_link_libraries(core PRIVATE rcheevos) + target_compile_definitions(core PRIVATE -DUSE_RETRO_ACHIEVEMENTS) +endif() \ No newline at end of file diff --git a/Source/Core/Core/Config/AchievementSettings.cpp b/Source/Core/Core/Config/AchievementSettings.cpp new file mode 100644 index 0000000000..f7ec642881 --- /dev/null +++ b/Source/Core/Core/Config/AchievementSettings.cpp @@ -0,0 +1,16 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Core/Config/AchievementSettings.h" + +#include + +#include "Common/Config/Config.h" + +namespace Config +{ +// Configuration Information +const Info RA_ENABLED{{System::Achievements, "Achievements", "Enabled"}, false}; +const Info RA_USERNAME{{System::Achievements, "Achievements", "Username"}, ""}; +const Info RA_API_TOKEN{{System::Achievements, "Achievements", "ApiToken"}, ""}; +} // namespace Config diff --git a/Source/Core/Core/Config/AchievementSettings.h b/Source/Core/Core/Config/AchievementSettings.h new file mode 100644 index 0000000000..8f26769d7f --- /dev/null +++ b/Source/Core/Core/Config/AchievementSettings.h @@ -0,0 +1,14 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "Common/Config/Config.h" + +namespace Config +{ +// Configuration Information +extern const Info RA_ENABLED; +extern const Info RA_USERNAME; +extern const Info RA_API_TOKEN; +} // namespace Config diff --git a/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp index acce10521b..6b8ed12e7b 100644 --- a/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/BaseConfigLoader.cpp @@ -94,6 +94,7 @@ const std::map system_to_ini = { {Config::System::Debugger, F_DEBUGGERCONFIG_IDX}, {Config::System::DualShockUDPClient, F_DUALSHOCKUDPCLIENTCONFIG_IDX}, {Config::System::FreeLook, F_FREELOOKCONFIG_IDX}, + {Config::System::Achievements, F_RETROACHIEVEMENTSCONFIG_IDX}, // Config::System::Session should not be added to this list }; diff --git a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp index d7746baa41..852fbb74ca 100644 --- a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp +++ b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp @@ -7,6 +7,7 @@ #include #include "Common/Config/Config.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/GraphicsSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Config/UISettings.h" @@ -37,6 +38,12 @@ bool IsSettingSaveable(const Config::Location& config_location) &Config::WIIMOTE_3_SOURCE.GetLocation(), &Config::WIIMOTE_4_SOURCE.GetLocation(), &Config::WIIMOTE_BB_SOURCE.GetLocation(), + + // Achievements + + &Config::RA_ENABLED.GetLocation(), + &Config::RA_USERNAME.GetLocation(), + &Config::RA_API_TOKEN.GetLocation(), }; return std::any_of(begin(s_setting_saveable), end(s_setting_saveable), diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index 404ae5eef4..db5027fd08 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -144,6 +144,8 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay return; } + m_client->mtu = std::min(m_client->mtu, NetPlay::MAX_ENET_MTU); + ENetAddress addr; enet_address_set_host(&addr, address.c_str()); addr.port = port; diff --git a/Source/Core/Core/NetPlayProto.h b/Source/Core/Core/NetPlayProto.h index 5d84e92c78..cfe498ca31 100644 --- a/Source/Core/Core/NetPlayProto.h +++ b/Source/Core/Core/NetPlayProto.h @@ -220,6 +220,7 @@ enum class SyncCodeID : u8 constexpr u32 MAX_NAME_LENGTH = 30; constexpr size_t CHUNKED_DATA_UNIT_SIZE = 16384; +constexpr u32 MAX_ENET_MTU = 1392; // see https://github.com/lsalzman/enet/issues/132 enum : u8 { diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index bb4a8b8750..483ead7218 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -151,7 +151,10 @@ NetPlayServer::NetPlayServer(const u16 port, const bool forward_port, NetPlayUI* serverAddr.port = port; m_server = enet_host_create(&serverAddr, 10, CHANNEL_COUNT, 0, 0); if (m_server != nullptr) + { + m_server->mtu = std::min(m_server->mtu, NetPlay::MAX_ENET_MTU); m_server->intercept = ENetUtil::InterceptCallback; + } SetupIndex(); } diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index c99d353df6..44048669a6 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -161,6 +161,7 @@ + @@ -172,6 +173,7 @@ + @@ -795,6 +797,7 @@ + @@ -805,6 +808,7 @@ + diff --git a/Source/Core/DolphinLib.vcxproj b/Source/Core/DolphinLib.vcxproj index d474a4fefc..3f5acdb7ca 100644 --- a/Source/Core/DolphinLib.vcxproj +++ b/Source/Core/DolphinLib.vcxproj @@ -52,6 +52,7 @@ + diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index e9d24bc4d1..36693b83bc 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -616,18 +616,8 @@ if(APPLE) if(MACOS_CODE_SIGNING) # Code sign make file builds - add_custom_command(TARGET dolphin-emu - POST_BUILD COMMAND - /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY}" --deep --options=runtime --entitlements "${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu$<$:Debug>.entitlements" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Dolphin.app" || true) - - # Code sign builds for build systems that do have release/debug variants (Xcode) - add_custom_command(TARGET dolphin-emu - POST_BUILD COMMAND - /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY}" --deep --options=runtime --entitlements "${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmuDebug.entitlements" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}/Dolphin.app" || true) - - add_custom_command(TARGET dolphin-emu - POST_BUILD COMMAND - /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY}" --deep --options=runtime --entitlements "${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu.entitlements" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}/Dolphin.app" || true) + add_custom_command(TARGET dolphin-emu POST_BUILD + COMMAND /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY}" --deep --options=runtime --entitlements "${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu$<$:Debug>.entitlements" "$") endif() else() install(TARGETS dolphin-emu RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) @@ -686,4 +676,9 @@ endif() if(USE_DISCORD_PRESENCE) target_compile_definitions(dolphin-emu PRIVATE -DUSE_DISCORD_PRESENCE) -endif() \ No newline at end of file +endif() + +if(USE_RETRO_ACHIEVEMENTS) + target_link_libraries(dolphin-emu PRIVATE rcheevos) + target_compile_definitions(dolphin-emu PRIVATE -DUSE_RETRO_ACHIEVEMENTS) +endif() diff --git a/Source/Core/DolphinQt/Config/FilesystemWidget.cpp b/Source/Core/DolphinQt/Config/FilesystemWidget.cpp index d9d053f0b1..6fefcdc1ee 100644 --- a/Source/Core/DolphinQt/Config/FilesystemWidget.cpp +++ b/Source/Core/DolphinQt/Config/FilesystemWidget.cpp @@ -62,6 +62,7 @@ void FilesystemWidget::CreateWidgets() m_tree_view = new QTreeView(this); m_tree_view->setModel(m_tree_model); m_tree_view->setContextMenuPolicy(Qt::CustomContextMenu); + m_tree_model->setParent(m_tree_view); auto* header = m_tree_view->header(); diff --git a/Source/Core/DolphinQt/Config/LogConfigWidget.cpp b/Source/Core/DolphinQt/Config/LogConfigWidget.cpp index dab59e63d9..607d3618c2 100644 --- a/Source/Core/DolphinQt/Config/LogConfigWidget.cpp +++ b/Source/Core/DolphinQt/Config/LogConfigWidget.cpp @@ -47,6 +47,7 @@ void LogConfigWidget::CreateWidgets() m_verbosity_warning = new QRadioButton(tr("Warning")); m_verbosity_info = new QRadioButton(tr("Info")); m_verbosity_debug = new QRadioButton(tr("Debug")); + m_verbosity_debug->setVisible(Common::Log::MAX_LOGLEVEL == Common::Log::LogLevel::LDEBUG); auto* outputs = new QGroupBox(tr("Logger Outputs")); auto* outputs_layout = new QVBoxLayout; @@ -77,10 +78,7 @@ void LogConfigWidget::CreateWidgets() verbosity_layout->addWidget(m_verbosity_error); verbosity_layout->addWidget(m_verbosity_warning); verbosity_layout->addWidget(m_verbosity_info); - if constexpr (Common::Log::MAX_LOGLEVEL == Common::Log::LogLevel::LDEBUG) - { - verbosity_layout->addWidget(m_verbosity_debug); - } + verbosity_layout->addWidget(m_verbosity_debug); layout->addWidget(outputs); outputs_layout->addWidget(m_out_file); diff --git a/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp b/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp index 0c3646ec7a..34dd7b767e 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp @@ -249,12 +249,12 @@ void MemoryWidget::CreateWidgets() QMenuBar* menubar = new QMenuBar(sidebar); menubar->setNativeMenuBar(false); - QMenu* menu_import = new QMenu(tr("&Import")); + QMenu* menu_import = new QMenu(tr("&Import"), menubar); menu_import->addAction(tr("&Load file to current address"), this, &MemoryWidget::OnSetValueFromFile); menubar->addMenu(menu_import); - QMenu* menu_export = new QMenu(tr("&Export")); + QMenu* menu_export = new QMenu(tr("&Export"), menubar); menu_export->addAction(tr("Dump &MRAM"), this, &MemoryWidget::OnDumpMRAM); menu_export->addAction(tr("Dump &ExRAM"), this, &MemoryWidget::OnDumpExRAM); menu_export->addAction(tr("Dump &ARAM"), this, &MemoryWidget::OnDumpARAM); diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index 06228dc44b..e82b7d0234 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -439,6 +439,7 @@ + diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 12abe73821..480e1dee16 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -37,6 +37,7 @@ #include "Common/Version.h" #include "Common/WindowSystemInfo.h" +#include "Core/AchievementManager.h" #include "Core/Boot/Boot.h" #include "Core/BootManager.h" #include "Core/CommonTitles.h" @@ -222,6 +223,11 @@ MainWindow::MainWindow(std::unique_ptr boot_parameters, InitControllers(); +#ifdef USE_RETRO_ACHIEVEMENTS + // This has to be done before CreateComponents() so it's initialized. + AchievementManager::GetInstance()->Init(); +#endif // USE_RETRO_ACHIEVEMENTS + CreateComponents(); ConnectGameList(); @@ -301,6 +307,10 @@ MainWindow::~MainWindow() Settings::Instance().ResetNetPlayClient(); Settings::Instance().ResetNetPlayServer(); +#ifdef USE_RETRO_ACHIEVEMENTS + AchievementManager::GetInstance()->Shutdown(); +#endif // USE_RETRO_ACHIEVEMENTS + delete m_render_widget; delete m_netplay_dialog; diff --git a/Source/Core/DolphinQt/RenderWidget.cpp b/Source/Core/DolphinQt/RenderWidget.cpp index c39621ad73..8393434530 100644 --- a/Source/Core/DolphinQt/RenderWidget.cpp +++ b/Source/Core/DolphinQt/RenderWidget.cpp @@ -488,10 +488,11 @@ void RenderWidget::PassEventToPresenter(const QEvent* event) const u32 key = static_cast(key_event->key() & 0x1FF); const char* chars = nullptr; + QByteArray utf8; if (is_down) { - auto utf8 = key_event->text().toUtf8(); + utf8 = key_event->text().toUtf8(); if (utf8.size()) chars = utf8.constData(); diff --git a/Source/Core/DolphinQt/Settings/InterfacePane.cpp b/Source/Core/DolphinQt/Settings/InterfacePane.cpp index e7e73f30c0..f4d2222943 100644 --- a/Source/Core/DolphinQt/Settings/InterfacePane.cpp +++ b/Source/Core/DolphinQt/Settings/InterfacePane.cpp @@ -189,7 +189,8 @@ void InterfacePane::CreateInGame() m_vboxlayout_hide_mouse->addWidget(m_radio_cursor_visible_never); m_vboxlayout_hide_mouse->addWidget(m_radio_cursor_visible_always); - m_checkbox_lock_mouse = new QCheckBox(tr("Lock Mouse Cursor")); + // this ends up not being managed unless _WIN32, so lets not leak + m_checkbox_lock_mouse = new QCheckBox(tr("Lock Mouse Cursor"), this); m_checkbox_lock_mouse->setToolTip(tr("Will lock the Mouse Cursor to the Render Widget as long as " "it has focus. You can set a hotkey to unlock it.")); diff --git a/Source/Core/MacUpdater/CMakeLists.txt b/Source/Core/MacUpdater/CMakeLists.txt index dc09866822..d610a02bfa 100644 --- a/Source/Core/MacUpdater/CMakeLists.txt +++ b/Source/Core/MacUpdater/CMakeLists.txt @@ -47,17 +47,14 @@ if (${IBTOOL} STREQUAL "IBTOOL-NOTFOUND") endif() foreach(sb ${STORYBOARDS}) - set(MacUpdater_BIN_DIR ${CMAKE_BINARY_DIR}/Binaries) - - if (CMAKE_GENERATOR STREQUAL Xcode) - string(APPEND MacUpdater_BIN_DIR "/\${CONFIGURATION}") - endif() - - add_custom_command(TARGET MacUpdater POST_BUILD - COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text - --compile ${MacUpdater_BUNDLE_PATH}/Contents/Resources/${sb}c - ${CMAKE_CURRENT_SOURCE_DIR}/${sb} - COMMENT "Compiling Storyboard ${sb}...") + set(output ${CMAKE_CURRENT_BINARY_DIR}/${sb}c) + set(input ${CMAKE_CURRENT_SOURCE_DIR}/${sb}) + add_custom_command(OUTPUT ${output} + COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text --compile ${output} ${input} + DEPENDS ${input} + COMMENT "Compiling Storyboard ${sb}...") + target_sources(MacUpdater PRIVATE ${output}) + set_source_files_properties(${output} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) endforeach() if(MACOS_CODE_SIGNING) @@ -65,14 +62,6 @@ if(MACOS_CODE_SIGNING) set(MACOS_CODE_SIGNING_IDENTITY_UPDATER "${MACOS_CODE_SIGNING_IDENTITY}") endif() - # Make file build code sign add_custom_command(TARGET MacUpdater POST_BUILD - COMMAND test ${MacUpdater_BUNDLE_PATH} || /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY_UPDATER}" --deep --options runtime ${MacUpdater_BUNDLE_PATH}) - - # Xcode build code sign - add_custom_command(TARGET MacUpdater POST_BUILD - COMMAND test "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}/${MacUpdater_NAME}.app" || /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY_UPDATER}" --deep --options runtime "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}/${MacUpdater_NAME}.app") - - add_custom_command(TARGET MacUpdater POST_BUILD - COMMAND test "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}/${MacUpdater_NAME}.app" || /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY_UPDATER}" --deep --options runtime "${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE}/${MacUpdater_NAME}.app") + COMMAND /usr/bin/codesign -f -s "${MACOS_CODE_SIGNING_IDENTITY_UPDATER}" --deep --options runtime $) endif() diff --git a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp index 80bbd7e5b5..be02034f67 100644 --- a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp @@ -26,8 +26,7 @@ CommandBufferManager::~CommandBufferManager() if (m_use_threaded_submission) { WaitForWorkerThreadIdle(); - m_submit_loop->Stop(); - m_submit_thread.join(); + m_submit_thread.Shutdown(); } DestroyCommandBuffers(); @@ -221,40 +220,11 @@ VkDescriptorSet CommandBufferManager::AllocateDescriptorSet(VkDescriptorSetLayou bool CommandBufferManager::CreateSubmitThread() { - m_submit_loop = std::make_unique(); - m_submit_thread = std::thread([this]() { - Common::SetCurrentThreadName("Vulkan CommandBufferManager SubmitThread"); - - m_submit_loop->Run([this]() { - PendingCommandBufferSubmit submit; - { - std::lock_guard guard(m_pending_submit_lock); - if (m_pending_submits.empty()) - { - m_submit_loop->AllowSleep(); - m_submit_worker_idle = true; - m_submit_worker_condvar.notify_all(); - return; - } - - submit = m_pending_submits.front(); - m_pending_submits.pop_front(); - } - - SubmitCommandBuffer(submit.command_buffer_index, submit.present_swap_chain, - submit.present_image_index); - CmdBufferResources& resources = m_command_buffers[submit.command_buffer_index]; - resources.waiting_for_submit.store(false, std::memory_order_release); - - { - std::lock_guard guard(m_pending_submit_lock); - if (m_pending_submits.empty()) - { - m_submit_worker_idle = true; - m_submit_worker_condvar.notify_all(); - } - } - }); + m_submit_thread.Reset("VK submission thread", [this](PendingCommandBufferSubmit submit) { + SubmitCommandBuffer(submit.command_buffer_index, submit.present_swap_chain, + submit.present_image_index); + CmdBufferResources& resources = m_command_buffers[submit.command_buffer_index]; + resources.waiting_for_submit.store(false, std::memory_order_release); }); return true; @@ -265,8 +235,7 @@ void CommandBufferManager::WaitForWorkerThreadIdle() if (!m_use_threaded_submission) return; - std::unique_lock lock{m_pending_submit_lock}; - m_submit_worker_condvar.wait(lock, [&] { return m_submit_worker_idle; }); + m_submit_thread.WaitForCompletion(); } void CommandBufferManager::WaitForFenceCounter(u64 fence_counter) @@ -352,14 +321,7 @@ void CommandBufferManager::SubmitCommandBuffer(bool submit_on_worker_thread, { resources.waiting_for_submit.store(true, std::memory_order_relaxed); // Push to the pending submit queue. - { - std::lock_guard guard(m_pending_submit_lock); - m_submit_worker_idle = false; - m_pending_submits.push_back({present_swap_chain, present_image_index, m_current_cmd_buffer}); - } - - // Wake up the worker thread for a single iteration. - m_submit_loop->Wakeup(); + m_submit_thread.Push({present_swap_chain, present_image_index, m_current_cmd_buffer}); } else { diff --git a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h index 7b4772760a..0249097423 100644 --- a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h +++ b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.h @@ -14,6 +14,7 @@ #include #include +#include #include "Common/BlockingLoop.h" #include "Common/Flag.h" #include "Common/Semaphore.h" @@ -146,19 +147,14 @@ private: u32 m_current_cmd_buffer = 0; // Threaded command buffer execution - std::thread m_submit_thread; - std::unique_ptr m_submit_loop; struct PendingCommandBufferSubmit { VkSwapchainKHR present_swap_chain; u32 present_image_index; u32 command_buffer_index; }; + Common::WorkQueueThread m_submit_thread; VkSemaphore m_present_semaphore = VK_NULL_HANDLE; - std::deque m_pending_submits; - std::mutex m_pending_submit_lock; - std::condition_variable m_submit_worker_condvar; - bool m_submit_worker_idle = true; Common::Flag m_last_present_failed; Common::Flag m_last_present_done; VkResult m_last_present_result = VK_SUCCESS; diff --git a/Source/VSProps/Base.Dolphin.props b/Source/VSProps/Base.Dolphin.props index 15e3b0f072..6a9d0192d2 100644 --- a/Source/VSProps/Base.Dolphin.props +++ b/Source/VSProps/Base.Dolphin.props @@ -45,6 +45,7 @@ AUTOUPDATE;%(PreprocessorDefinitions) HAVE_SDL2;%(PreprocessorDefinitions) STEAM;%(PreprocessorDefinitions) + USE_RETRO_ACHIEVEMENTS;%(PreprocessorDefinitions)