diff --git a/Core/GameEngine/Source/GameNetwork/IPEnumeration.cpp b/Core/GameEngine/Source/GameNetwork/IPEnumeration.cpp index a7a4844be..ad3e2a1dc 100644 --- a/Core/GameEngine/Source/GameNetwork/IPEnumeration.cpp +++ b/Core/GameEngine/Source/GameNetwork/IPEnumeration.cpp @@ -112,10 +112,25 @@ EnumeratedIP * IPEnumeration::getAddresses() continue; } + // GeneralsX @bugfix 07/07/2026 Skip point-to-point interfaces: cellular (pdp_ip* on iOS) and + // VPN tunnels (utun*) are not reachable by LAN peers, and their addresses sort numerically + // below the Wi-Fi/Ethernet address, so the LAN lobby would pick them as the default IP. + if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0) + { + continue; + } + const sockaddr_in *addr = reinterpret_cast(ifa->ifa_addr); // GeneralsX @bugfix BenderAI 31/03/2026 Use ntohl to convert from network byte order before extracting octets; // reading s_addr byte-by-byte on little-endian platforms reverses the IPv4 octets. const UnsignedInt hostAddr = ntohl(addr->sin_addr.s_addr); + + // GeneralsX @bugfix 07/07/2026 Skip 169.254.0.0/16 link-local addresses (awdl0/llw0 on Apple + // platforms, or any interface that failed DHCP); they cannot host a LAN game. + if ((hostAddr & 0xFFFF0000u) == 0xA9FE0000u) + { + continue; + } addNewIP( (UnsignedByte)((hostAddr >> 24) & 0xFF), (UnsignedByte)((hostAddr >> 16) & 0xFF), diff --git a/Core/Libraries/Source/WWVegas/WWLib/systimer.h b/Core/Libraries/Source/WWVegas/WWLib/systimer.h index 8313aa49d..624b9a39d 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/systimer.h +++ b/Core/Libraries/Source/WWVegas/WWLib/systimer.h @@ -46,13 +46,16 @@ #define TIMEGETTIME SystemTime.Get #define MS_TIMER_SECOND 1000 #else -#include +#include +// GeneralsX @bugfix 07/07/2026 Use the monotonic clock, not gettimeofday: wall time steps +// backward on NTP/carrier sync (frequent on iOS), and every elapsed-time gate in the engine +// (shell updates, animations, network resends) then stalls until the clock catches back up. inline unsigned long systimerGetMS() { - struct timeval tv; - gettimeofday(&tv, nullptr); - return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (unsigned long)((unsigned long long)ts.tv_sec * 1000ull + (unsigned long long)ts.tv_nsec / 1000000ull); } #define TIMEGETTIME systimerGetMS diff --git a/Generals/Code/CompatLib/Include/windows_compat.h b/Generals/Code/CompatLib/Include/windows_compat.h index 899529924..e39d34084 100644 --- a/Generals/Code/CompatLib/Include/windows_compat.h +++ b/Generals/Code/CompatLib/Include/windows_compat.h @@ -183,11 +183,14 @@ inline BOOL GetVersionEx(OSVERSIONINFO* lpVersionInfo) { // TheSuperHackers @build 10/02/2026 Bender // Timing functions: timeBeginPeriod(), timeEndPeriod() for Linux +// GeneralsX @bugfix 07/07/2026 Use the monotonic clock, not gettimeofday: wall time steps +// backward on NTP/carrier sync (frequent on iOS), and every elapsed-time gate in the engine +// (shell updates, animations, network resends) then stalls until the clock catches back up. static inline DWORD timeGetTime(void) { - struct timeval tv; - gettimeofday(&tv, nullptr); - return (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (DWORD)((unsigned long long)ts.tv_sec * 1000ull + (unsigned long long)ts.tv_nsec / 1000000ull); } static inline DWORD timeBeginPeriod(DWORD period) diff --git a/GeneralsMD/Code/CompatLib/Include/windows_compat.h b/GeneralsMD/Code/CompatLib/Include/windows_compat.h index 899529924..e39d34084 100644 --- a/GeneralsMD/Code/CompatLib/Include/windows_compat.h +++ b/GeneralsMD/Code/CompatLib/Include/windows_compat.h @@ -183,11 +183,14 @@ inline BOOL GetVersionEx(OSVERSIONINFO* lpVersionInfo) { // TheSuperHackers @build 10/02/2026 Bender // Timing functions: timeBeginPeriod(), timeEndPeriod() for Linux +// GeneralsX @bugfix 07/07/2026 Use the monotonic clock, not gettimeofday: wall time steps +// backward on NTP/carrier sync (frequent on iOS), and every elapsed-time gate in the engine +// (shell updates, animations, network resends) then stalls until the clock catches back up. static inline DWORD timeGetTime(void) { - struct timeval tv; - gettimeofday(&tv, nullptr); - return (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (DWORD)((unsigned long long)ts.tv_sec * 1000ull + (unsigned long long)ts.tv_nsec / 1000000ull); } static inline DWORD timeBeginPeriod(DWORD period) diff --git a/scripts/build/ios/package-ios-zh.sh b/scripts/build/ios/package-ios-zh.sh index 93d75dee0..871c70e2b 100755 --- a/scripts/build/ios/package-ios-zh.sh +++ b/scripts/build/ios/package-ios-zh.sh @@ -190,11 +190,9 @@ echo "==> App ready: ${APP}" if [[ "${DO_INSTALL}" == "1" ]]; then echo "==> Installing to connected device" - DEVICE_ID=$(xcrun devicectl list devices 2>/dev/null | awk '/connected/{print $(NF-2); exit}') - if [[ -z "${DEVICE_ID}" ]]; then - # fall back: parse the identifier column (3rd-from-last varies with model names) - DEVICE_ID=$(xcrun devicectl list devices 2>/dev/null | grep -i connected | grep -oE '[0-9A-F-]{36}' | head -1) - fi + # Extract the identifier by shape (UUID), not by column position — the column + # index shifts with multi-word device/model names (e.g. "iPhone 15 Pro Max"). + DEVICE_ID=$(xcrun devicectl list devices 2>/dev/null | grep -i connected | grep -oE '[0-9A-F]{8}(-[0-9A-F]{4}){3}-[0-9A-F]{12}' | head -1) if [[ -z "${DEVICE_ID}" ]]; then echo "ERROR: no connected device found (xcrun devicectl list devices)" exit 1