mirror of
https://github.com/Rosalie241/RMG.git
synced 2026-07-11 09:34:00 +02:00
Compare commits
23 Commits
windowsize
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| ff237ac4e2 | |||
| dbe1dc685f | |||
| feeb0a2e40 | |||
| b0c09d17c9 | |||
| 453f663973 | |||
| f76e7472fd | |||
| ff9b9a2040 | |||
| 99bb81d9b9 | |||
| fe67ba053e | |||
| 6ebbba6fc5 | |||
| 21d0b55a35 | |||
| 6ef6432a15 | |||
| 02e2518be2 | |||
| 2da7750640 | |||
| 4c50859481 | |||
| 2867fc627b | |||
| 47df34da6b | |||
| 7e4e402f27 | |||
| 8ee3410680 | |||
| e9167db9ff | |||
| 94f5fd9d82 | |||
| 969d63f182 | |||
| c7a4e6c47a |
@@ -20,7 +20,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: hendrikmuhs/ccache-action@v1.2
|
||||
- uses: hendrikmuhs/ccache-action@v1.2.23
|
||||
with:
|
||||
key: linux-${{ matrix.architecture }}-${{ matrix.features }}-${{ matrix.configuration }}
|
||||
- name: Install Packages
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
run: |
|
||||
export sdl_dir="$(pwd)/../SDL3"
|
||||
|
||||
git clone https://github.com/libsdl-org/SDL.git "$sdl_dir" -b release-3.2.28 --depth=1
|
||||
git clone https://github.com/libsdl-org/SDL.git "$sdl_dir" -b release-3.4.10 --depth=1
|
||||
|
||||
mkdir -p "$sdl_dir/build"
|
||||
cmake -S "$sdl_dir" -B "$sdl_dir/build" \
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
shell: bash
|
||||
- name: Upload RMG (AppImage)
|
||||
if: ${{ matrix.features == 'ON' && matrix.architecture == 'x86_64' && matrix.configuration == 'Release' }}
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: RMG-Portable-Linux64-${{ env.GIT_REVISION }}
|
||||
path: Bin/*.AppImage
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: hendrikmuhs/ccache-action@v1.2
|
||||
- uses: hendrikmuhs/ccache-action@v1.2.23
|
||||
with:
|
||||
key: windows-${{ matrix.features }}-${{ matrix.configuration }}
|
||||
- uses: msys2/setup-msys2@v2
|
||||
@@ -167,13 +167,13 @@ jobs:
|
||||
shell: msys2 {0}
|
||||
- name: Upload RMG (Portable)
|
||||
if: ${{ matrix.features == 'ON' && matrix.configuration == 'Release' }}
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: RMG-Portable-Windows64-${{ env.GIT_REVISION }}
|
||||
path: Bin/Release/*
|
||||
- name: Upload RMG (Installer)
|
||||
if: ${{ matrix.features == 'ON' && matrix.configuration == 'Release' }}
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: RMG-Setup-Windows64-${{ env.GIT_REVISION }}
|
||||
path: Bin/*.exe
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
[ -f "$APPIMAGE_QT_THEME" ] && set -- "$@" "-stylesheet" "$APPIMAGE_QT_THEME"
|
||||
cur_dir="$(readlink -f "$(dirname "$0")")"
|
||||
|
||||
# force pulseaudio to fix audio issues
|
||||
# else we get the following error:
|
||||
# Failed to initialize SDL audio subsystem: Failed loading libjack.so.0:
|
||||
# /tmp/.mount_RMG-PoJFjkog/shared/lib/libc.so.6: version `GLIBC_ABI_GNU2_TLS' not found
|
||||
# (required by /usr/lib64/pipewire-0.3/jack/libjack.so.0)
|
||||
# see https://github.com/Rosalie241/RMG/issues/494 for more details
|
||||
export SDL_AUDIODRIVER=pulseaudio
|
||||
|
||||
exec "$cur_dir/bin/RMG" \
|
||||
--lib-path="$cur_dir/shared/lib/RMG" \
|
||||
--core-path="$cur_dir/shared/lib/RMG/Core" \
|
||||
|
||||
@@ -64,6 +64,7 @@ $XVFB_RUN "$script_dir/lib4bin" --dst-dir "$bin_dir" \
|
||||
"$lib_dir"/libGL* \
|
||||
"$lib_dir"/libEGL* \
|
||||
"$lib_dir"/libvulkan* \
|
||||
"$lib_dir"/libpulse* \
|
||||
"$lib_dir"/dri/* \
|
||||
"$lib_dir"/libssl.so* \
|
||||
"$lib_dir"/qt6/plugins/iconengines/* \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Maintainer: Rosalie Wanders <rosalie@mailbox.org>
|
||||
pkgname=rmg
|
||||
pkgver=0.8.8
|
||||
pkgver=0.9.0
|
||||
pkgrel=1
|
||||
pkgdesc="Rosalie's Mupen GUI"
|
||||
arch=('x86_64' 'aarch64')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: RMG
|
||||
Version: 0.8.8
|
||||
Version: 0.9.0
|
||||
Release: %autorelease
|
||||
Summary: Rosalie's Mupen GUI
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Rosalie's Mupen GUI
|
||||
Comment=An easy to use & cross-platform mupen64plus front-end written in C++ & Qt
|
||||
Comment=An easy to use and cross-platform mupen64plus front-end written in C++ & Qt
|
||||
Exec=RMG %f
|
||||
TryExec=RMG
|
||||
Icon=com.github.Rosalie241.RMG
|
||||
|
||||
@@ -29,6 +29,32 @@
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="v0.9.0" date="2026-06-14" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix build issues with zlib v1.3.1</li>
|
||||
<li>Fix audio not working when using the AppImage (thank you Samueru-sama)</li>
|
||||
<li>Fix screenshots causing a crash on Linux</li>
|
||||
<li>Remove dispatcher server support</li>
|
||||
<li>Update mupen64plus-core and LZMA SDK</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.8.9" date="2026-01-23" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix AppImage icon not working since v0.7.1 (thank you Samueru-sama)</li>
|
||||
<li>Fix desktop file causing a crash on Budgie (thank you jpleatherland)</li>
|
||||
<li>Fix memory pak from player 2, 3 and 4 not saving correctly</li>
|
||||
<li>Fix Star Wars - Rogue Squadron having missing geometry when using GLideN64</li>
|
||||
<li>Remove translations from the configuration GUI of GLideN64</li>
|
||||
<li>Add plugin settings shortcuts to the toolbar</li>
|
||||
<li>Update mupen64plus-video-GLideN64, SDL_net and SDL_GameControllerDB</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.8.8" date="2025-11-16" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
@@ -1024,6 +1050,7 @@
|
||||
</releases>
|
||||
<url type="homepage">https://github.com/Rosalie241/RMG</url>
|
||||
<url type="bugtracker">https://github.com/Rosalie241/RMG/issues</url>
|
||||
<url type="vcs-browser">https://github.com/Rosalie241/RMG</url>
|
||||
<categories>
|
||||
<category>Game</category>
|
||||
<category>Emulator</category>
|
||||
|
||||
@@ -7,7 +7,7 @@ It offers a simple-to-use user interface.
|
||||
## Download
|
||||
|
||||
#### Windows
|
||||
You can download Rosalie's Mupen GUI on 
|
||||
You can download Rosalie's Mupen GUI on [Github Releases](https://github.com/Rosalie241/RMG/releases)
|
||||
|
||||
#### Linux
|
||||
You can download Rosalie's Mupen GUI on
|
||||
@@ -16,11 +16,43 @@ You can download Rosalie's Mupen GUI on
|
||||
* [Arch User Repository](https://aur.archlinux.org/packages/rmg)
|
||||
* [Fedora COPR](https://copr.fedorainfracloud.org/coprs/rosalie/RMG/)
|
||||
|
||||
## Netplay
|
||||
|
||||
You can use netplay with the following methods:
|
||||
|
||||
### Port Forwarding
|
||||
|
||||
1) Download [rmg-netplay-server](https://github.com/Rosalie241/rmg-netplay-server/releases/latest)
|
||||
2) Port forward the ports stated in the [rmg-netplay-server README](https://github.com/Rosalie241/rmg-netplay-server)
|
||||
3) Create a JSON file with something similar to the following contents, but using your public IP instead of a local one:
|
||||
```
|
||||
{
|
||||
"some-server-name": "127.0.0.1"
|
||||
}
|
||||
```
|
||||
If you want to add multiple servers instead:
|
||||
```
|
||||
{
|
||||
"some-server-name": "127.0.0.1",
|
||||
"some-server-name-2": "127.0.0.1"
|
||||
}
|
||||
```
|
||||
4) Store the JSON file or upload it somewhere
|
||||
5) Enter the JSON file path or URL in the "Server list URL" text box in the RMG settings dialog
|
||||
6) The specified servers in the JSON file should appear in the RMG GUI
|
||||
|
||||
|
||||
### Tunneling Software
|
||||
|
||||
1) Download [rmg-netplay-server](https://github.com/Rosalie241/rmg-netplay-server/releases/latest)
|
||||
2) Download [Radmin VPN](https://www.radmin-vpn.com/)
|
||||
3) Run and create or join a network in Radmin VPN
|
||||
4) The host should run [rmg-netplay-server](https://github.com/Rosalie241/rmg-netplay-server)
|
||||
5) The server should show up as `local-server` within the RMG GUI
|
||||
|
||||
## Support
|
||||
|
||||
You can ask for help or report issues on
|
||||
* [Github](https://github.com/Rosalie241/RMG/issues/new)
|
||||
* [Discord](https://discord.gg/k9GuyJ2PpF)
|
||||
You can ask for help or report issues on [Github](https://github.com/Rosalie241/RMG/issues/new)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Vendored
+3
-3
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = git@github.com:libsdl-org/SDL_net.git
|
||||
branch = main
|
||||
commit = 4dd85af45d8597f93796815fba0defa5d499be21
|
||||
parent = 02eef161e7f4ac7a4deebd0115574b7a27c5f58f
|
||||
commit = 4dd9d8418e9781d10481fd6177e3a1064ca201fe
|
||||
parent = b0c09d17c97848d0386a11b3b6fdd572a2b2228a
|
||||
method = merge
|
||||
cmdver = 0.4.9
|
||||
cmdver = 0.4.6
|
||||
|
||||
Vendored
+1
-1
@@ -18,7 +18,7 @@ LOCAL_SRC_FILES := \
|
||||
$(subst $(LOCAL_PATH)/,,) \
|
||||
$(wildcard $(LOCAL_PATH)/src/*.c) \
|
||||
|
||||
LOCAL_CFLAGS =
|
||||
LOCAL_CFLAGS = -DHAVE_GETIFADDRS
|
||||
|
||||
# Warnings we haven't fixed (yet)
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-sign-compare
|
||||
|
||||
+48
-7
@@ -8,7 +8,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||
|
||||
# See docs/release_checklist.md
|
||||
set(MAJOR_VERSION 3)
|
||||
set(MINOR_VERSION 0)
|
||||
set(MINOR_VERSION 3)
|
||||
set(MICRO_VERSION 0)
|
||||
set(SDL_REQUIRED_VERSION 3.0.0)
|
||||
|
||||
@@ -67,7 +67,7 @@ include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(PLATFORM_SUPPORTS_SHARED ON)
|
||||
if(EMSCRIPTEN OR VITA OR PSP OR PS2 OR N3DS OR RISCOS)
|
||||
if(EMSCRIPTEN OR VITA OR PSP OR PS2 OR N3DS OR RISCOS OR DOS)
|
||||
set(PLATFORM_SUPPORTS_SHARED OFF)
|
||||
endif()
|
||||
|
||||
@@ -104,9 +104,46 @@ endif()
|
||||
set(PC_LIBS)
|
||||
set(PC_REQUIRES)
|
||||
|
||||
add_library(${sdl3_net_target_name} src/SDL_net.c)
|
||||
if(HAIKU)
|
||||
set(HAVE_GETIFADDRS True) # Haiku always has it (but you have to -lnetwork, so check_c_source_compiles won't work as-is).
|
||||
set(EXTRA_SOURCES "src/SDL_net_haiku.cpp")
|
||||
enable_language(CXX)
|
||||
endif()
|
||||
|
||||
set(PLATFORM_UNSUPPORTED False)
|
||||
if (DOS OR EMSCRIPTEN) # These either don't have networking at all, or have needs we don't currently meet.
|
||||
set(PLATFORM_UNSUPPORTED True)
|
||||
endif()
|
||||
|
||||
option(SDLNET_STUB_ONLY "Build a stub library that does nothing" ${PLATFORM_UNSUPPORTED})
|
||||
if(SDLNET_STUB_ONLY)
|
||||
message(WARNING "Only building a stub library. The functions will be there but all of them will fail!")
|
||||
add_library(${sdl3_net_target_name} src/SDL_net_stub_only.c)
|
||||
else()
|
||||
add_library(${sdl3_net_target_name} src/SDL_net.c ${EXTRA_SOURCES})
|
||||
endif()
|
||||
|
||||
if(NOT (HAIKU OR WIN32 OR SDLNET_STUB_ONLY))
|
||||
check_c_source_compiles("
|
||||
#include <ifaddrs.h>
|
||||
int main(void) {
|
||||
struct ifaddrs* ifap;
|
||||
getifaddrs(&ifap);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_GETIFADDRS)
|
||||
endif()
|
||||
|
||||
if(HAVE_GETIFADDRS)
|
||||
target_compile_definitions(${sdl3_net_target_name} PRIVATE HAVE_GETIFADDRS)
|
||||
endif()
|
||||
|
||||
add_library(SDL3_net::${sdl3_net_target_name} ALIAS ${sdl3_net_target_name})
|
||||
set_property(TARGET ${sdl3_net_target_name} PROPERTY C_STANDARD 99)
|
||||
if("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES)
|
||||
target_compile_features(${sdl3_net_target_name} PRIVATE c_std_99)
|
||||
else()
|
||||
message(WARNING "target_compile_features does not know c_std_99 for C compiler")
|
||||
endif()
|
||||
if(NOT TARGET SDL3_net::SDL3_net)
|
||||
add_library(SDL3_net::SDL3_net ALIAS ${sdl3_net_target_name})
|
||||
endif()
|
||||
@@ -140,8 +177,8 @@ if(WIN32)
|
||||
target_link_libraries(${sdl3_net_target_name} PRIVATE iphlpapi ws2_32)
|
||||
list(APPEND PC_LIBS -liphlpapi -lws2_32)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Haiku.*")
|
||||
target_link_libraries(${sdl3_net_target_name} PRIVATE network)
|
||||
if(HAIKU)
|
||||
target_link_libraries(${sdl3_net_target_name} PRIVATE network be bnetapi)
|
||||
endif()
|
||||
set_target_properties(${sdl3_net_target_name} PROPERTIES
|
||||
OUTPUT_NAME "SDL3_net"
|
||||
@@ -306,7 +343,10 @@ if(SDLNET_SAMPLES)
|
||||
sdl_target_link_options_no_undefined(${TARGET})
|
||||
target_link_libraries(${TARGET} PRIVATE SDL3_net::${sdl3_net_target_name})
|
||||
target_link_libraries(${TARGET} PRIVATE ${sdl3_target_name})
|
||||
set_property(TARGET ${TARGET} PROPERTY C_STANDARD 99)
|
||||
|
||||
if("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES)
|
||||
target_compile_features(${TARGET} PRIVATE c_std_99)
|
||||
endif()
|
||||
set_property(TARGET ${TARGET} PROPERTY C_EXTENSIONS FALSE)
|
||||
|
||||
if(SDLNET_SAMPLES_INSTALL)
|
||||
@@ -320,6 +360,7 @@ if(SDLNET_SAMPLES)
|
||||
add_sdl_net_example_executable(resolve-hostnames examples/resolve-hostnames.c)
|
||||
add_sdl_net_example_executable(get-local-addrs examples/get-local-addrs.c)
|
||||
add_sdl_net_example_executable(echo-server examples/echo-server.c)
|
||||
add_sdl_net_example_executable(datagram examples/datagram.c)
|
||||
|
||||
# Build at least one example in C90
|
||||
set_property(TARGET get-local-addrs PROPERTY C_STANDARD 90)
|
||||
|
||||
Vendored
+47
@@ -0,0 +1,47 @@
|
||||
# To build and use SDL_net:
|
||||
|
||||
SDL_net supports a number of development environments:
|
||||
- [CMake](docs/INTRO-cmake.md)
|
||||
- [Visual Studio on Windows](docs/INTRO-visualstudio.md)
|
||||
- [Xcode on Apple platforms](docs/INTRO-xcode.md)
|
||||
|
||||
SDL_net is also usable in other environments. The basic steps are to use CMake to build the library and then use the headers and library that you built in your project. You can search online to see if anyone has specific steps for your setup.
|
||||
|
||||
# Documentation
|
||||
|
||||
An API reference and additional documentation is available at:
|
||||
|
||||
https://wiki.libsdl.org/SDL3_net
|
||||
|
||||
# Example code
|
||||
|
||||
There are simple example programs in the examples directory.
|
||||
|
||||
If you're using CMake, you can build them adding `-DSDLNET_SAMPLES=ON` to the CMake command line when building SDL_net.
|
||||
|
||||
If you're using Visual Studio there are separate projects in the VisualC directory.
|
||||
|
||||
If you're using Xcode there are separate projects in the Xcode directory.
|
||||
|
||||
# Discussions
|
||||
|
||||
## Discord
|
||||
|
||||
You can join the official Discord server at:
|
||||
|
||||
https://discord.com/invite/BwpFGBWsv8
|
||||
|
||||
## Forums/mailing lists
|
||||
|
||||
You can join SDL development discussions at:
|
||||
|
||||
https://discourse.libsdl.org/
|
||||
|
||||
Once you sign up, you can use the forum through the website or as a mailing list from your email client.
|
||||
|
||||
## Announcement list
|
||||
|
||||
You can sign up for the low traffic announcement list at:
|
||||
|
||||
https://www.libsdl.org/mailing-list.php
|
||||
|
||||
Vendored
+10
-11
@@ -1,19 +1,18 @@
|
||||
# SDL_net 3.0
|
||||
|
||||
The latest version of this library is available from GitHub:
|
||||
|
||||
https://github.com/libsdl-org/SDL_net/releases
|
||||
|
||||
This is a portable network library for use with SDL. It's goal is to
|
||||
simplify the use of the usual socket interfaces and use SDL infrastructure
|
||||
to handle some portability things (such as threading and reporting
|
||||
errors).
|
||||
simplify the use of the usual socket interfaces and use SDL to handle
|
||||
common portable functionality such as threading and reporting errors.
|
||||
|
||||
It is available under the zlib license, found in the file LICENSE.txt.
|
||||
The API can be found in the file SDL_net.h and online at https://wiki.libsdl.org/SDL3_net
|
||||
This library supports most platforms that offer both SDL3 and networking.
|
||||
|
||||
This is a work in progress!
|
||||
The latest version of this library is available from GitHub:
|
||||
https://github.com/libsdl-org/SDL_net/releases
|
||||
|
||||
Installation instructions and a quick introduction is available in
|
||||
[INSTALL.md](INSTALL.md)
|
||||
|
||||
This library is distributed under the terms of the zlib license,
|
||||
available in [LICENSE.txt](LICENSE.txt).
|
||||
|
||||
Enjoy!
|
||||
|
||||
|
||||
+1
-1
@@ -199,7 +199,7 @@ function(target_get_dynamic_library DEST TARGET)
|
||||
endif()
|
||||
if(result)
|
||||
string(TOLOWER "${result}" result_lower)
|
||||
if(WIN32 OR OS2)
|
||||
if(WIN32 OR OS2 OR CYGWIN)
|
||||
if(NOT result_lower MATCHES ".*dll")
|
||||
message(FATAL_ERROR "\"${result}\" is not a .dll library")
|
||||
endif()
|
||||
|
||||
+141
-11
@@ -27,7 +27,7 @@
|
||||
* SDL_net is a simple library to help with networking.
|
||||
*
|
||||
* In current times, it's a relatively thin layer over system-level APIs like
|
||||
* BSD Sockets or WinSock. It's primary strength is in making those interfaces
|
||||
* BSD Sockets or WinSock. Its primary strength is in making those interfaces
|
||||
* less complicated to use, and handling several unexpected corner cases, so
|
||||
* the app doesn't have to.
|
||||
*
|
||||
@@ -136,7 +136,7 @@ extern "C" {
|
||||
*
|
||||
* \since This macro is available since SDL_net 3.0.0.
|
||||
*/
|
||||
#define SDL_NET_MINOR_VERSION 0
|
||||
#define SDL_NET_MINOR_VERSION 3
|
||||
|
||||
/**
|
||||
* The current micro (or patchlevel) version of the SDL_net headers.
|
||||
@@ -415,6 +415,50 @@ extern SDL_DECLSPEC NET_Status SDLCALL NET_GetAddressStatus(NET_Address *address
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL NET_GetAddressString(NET_Address *address);
|
||||
|
||||
/**
|
||||
* Get the protocol-level bytes of a network address from a resolved address.
|
||||
*
|
||||
* This data is not human-readable, is protocol-specific, and might not even
|
||||
* be in a specific byte order.
|
||||
*
|
||||
* This is only useful for possibly hashing, to map a address to a specific
|
||||
* player in a game, or possibly for handing to a system-level networking API
|
||||
* (which is _not_ recommended; an app does this at their own risk).
|
||||
*
|
||||
* Do not store these bytes for future runs of the program; there is no
|
||||
* promise the format won't change.
|
||||
*
|
||||
* On return `*num_bytes` will hold the number of bytes provided with the
|
||||
* address. Since the data is not NULL-terminated, this is the only way to
|
||||
* determine its size; as such, this parameter must not be NULL.
|
||||
*
|
||||
* Do not free or modify the returned data; it belongs to the NET_Address that
|
||||
* was queried, and is valid as long as the object lives. Either make sure the
|
||||
* address has a reference as long as you need this or make a copy of the
|
||||
* bytes.
|
||||
*
|
||||
* This will return NULL if resolution is still in progress, or if resolution
|
||||
* failed. You can use NET_GetAddressStatus() or NET_WaitUntilResolved() to
|
||||
* make sure resolution has successfully completed before calling this.
|
||||
*
|
||||
* A human-readable version is available in NET_GetAddressString() and isn't
|
||||
* any less efficient to query than the raw bytes.
|
||||
*
|
||||
* \param address The NET_Address to query.
|
||||
* \param num_bytes on return, will be set to the number of bytes returned.
|
||||
* \returns a pointer to bytes, or NULL on error; call SDL_GetError() for
|
||||
* details.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL_net 3.0.0.
|
||||
*
|
||||
* \sa NET_GetAddressString
|
||||
* \sa NET_GetAddressStatus
|
||||
* \sa NET_WaitUntilResolved
|
||||
*/
|
||||
extern SDL_DECLSPEC const void * SDLCALL NET_GetAddressBytes(NET_Address *address, int *num_bytes);
|
||||
|
||||
/**
|
||||
* Add a reference to an NET_Address.
|
||||
*
|
||||
@@ -640,8 +684,13 @@ typedef struct NET_StreamSocket NET_StreamSocket;
|
||||
* you do not have to byteswap it into "network order," as the library will
|
||||
* handle that for you.
|
||||
*
|
||||
* There are currently no extra properties for creating a client, so `props`
|
||||
* should be zero. A future revision of SDL_net may add additional (optional)
|
||||
* properties.
|
||||
*
|
||||
* \param address the address of the remote server to connect to.
|
||||
* \param port the port on the remote server to connect to.
|
||||
* \param props properties of the new client. Specify zero for defaults.
|
||||
* \returns a new NET_StreamSocket, pending connection, or NULL on error; call
|
||||
* SDL_GetError() for details.
|
||||
*
|
||||
@@ -653,7 +702,7 @@ typedef struct NET_StreamSocket NET_StreamSocket;
|
||||
* \sa NET_GetConnectionStatus
|
||||
* \sa NET_DestroyStreamSocket
|
||||
*/
|
||||
extern SDL_DECLSPEC NET_StreamSocket * SDLCALL NET_CreateClient(NET_Address *address, Uint16 port);
|
||||
extern SDL_DECLSPEC NET_StreamSocket * SDLCALL NET_CreateClient(NET_Address *address, Uint16 port, SDL_PropertiesID props);
|
||||
|
||||
/**
|
||||
* Block until a stream socket has connected to a server.
|
||||
@@ -750,8 +799,24 @@ typedef struct NET_Server NET_Server;
|
||||
* you do not have to byteswap it into "network order," as the library will
|
||||
* handle that for you.
|
||||
*
|
||||
* The caller may supply properties to customize behavior. This is optional,
|
||||
* and a value of zero for `props` will request defaults for all properties.
|
||||
*
|
||||
* These are the supported properties:
|
||||
*
|
||||
* - `NET_PROP_SERVER_REUSEADDR_BOOLEAN`: true if the server should be created
|
||||
* even if a previous server has recently used this address. For various
|
||||
* reasons, networks prefer that there be some delay between apps reusing
|
||||
* the same address, but this can be problematic when iterating quickly, for
|
||||
* software development purposes or just restarting a crashed service. This
|
||||
* property defaults to true (although it should be noted that, at the
|
||||
* operating system level, this defaults to false!). If this property is
|
||||
* false and the OS feels that not enough time has elapsed, server creation
|
||||
* will fail and this function will report an error.
|
||||
*
|
||||
* \param addr the _local_ address to listen for connections on, or NULL.
|
||||
* \param port the port on the local address to listen for connections on.
|
||||
* \param props properties of the new server. Specify zero for defaults.
|
||||
* \returns a new NET_Server, or NULL on error; call SDL_GetError() for
|
||||
* details.
|
||||
*
|
||||
@@ -763,7 +828,10 @@ typedef struct NET_Server NET_Server;
|
||||
* \sa NET_AcceptClient
|
||||
* \sa NET_DestroyServer
|
||||
*/
|
||||
extern SDL_DECLSPEC NET_Server * SDLCALL NET_CreateServer(NET_Address *addr, Uint16 port);
|
||||
extern SDL_DECLSPEC NET_Server * SDLCALL NET_CreateServer(NET_Address *addr, Uint16 port, SDL_PropertiesID props);
|
||||
|
||||
#define NET_PROP_SERVER_REUSEADDR_BOOLEAN "NET.server.reuseaddr"
|
||||
|
||||
|
||||
/**
|
||||
* Create a stream socket for the next pending client connection.
|
||||
@@ -1029,7 +1097,7 @@ extern SDL_DECLSPEC int SDLCALL NET_WaitUntilStreamSocketDrained(NET_StreamSocke
|
||||
* on what is available at the time, and also the app isn't required to read
|
||||
* all available data at once.
|
||||
*
|
||||
* This call never blocks; if no new data isn't available at the time of the
|
||||
* This call never blocks; if no new data is available at the time of the
|
||||
* call, it returns 0 immediately. The caller can try again later.
|
||||
*
|
||||
* If the connection has failed (remote side dropped us, or one of a million
|
||||
@@ -1163,8 +1231,8 @@ typedef struct NET_DatagramSocket NET_DatagramSocket;
|
||||
*/
|
||||
typedef struct NET_Datagram
|
||||
{
|
||||
NET_Address *addr; /**< this is unref'd by NET_DestroyDatagram. You only need to ref it if you want to keep it. */
|
||||
Uint16 port; /**< these do not have to come from the same port the receiver is bound to. These are in host byte order, don't byteswap them! */
|
||||
NET_Address *addr; /**< Sender's address. This is unref'd by NET_DestroyDatagram. You only need to ref it if you want to keep it. */
|
||||
Uint16 port; /**< Sender's port. These do not have to come from the same port the receiver is bound to. These are in host byte order, don't byteswap them! */
|
||||
Uint8 *buf; /**< the payload of this datagram. */
|
||||
int buflen; /**< the number of bytes available at `buf`. */
|
||||
} NET_Datagram;
|
||||
@@ -1213,10 +1281,37 @@ typedef struct NET_Datagram
|
||||
* you do not have to byteswap it into "network order," as the library will
|
||||
* handle that for you.
|
||||
*
|
||||
* The caller may supply properties to customize behavior. This is optional,
|
||||
* and a value of zero for `props` will request defaults for all properties.
|
||||
*
|
||||
* These are the supported properties:
|
||||
*
|
||||
* - `NET_PROP_DATAGRAM_SOCKET_REUSEADDR_BOOLEAN`: true if the socket should
|
||||
* be created even if a previous socket has recently used this address. For
|
||||
* various reasons, networks prefer that there be some delay between apps
|
||||
* reusing the same address, but this can be problematic when iterating
|
||||
* quickly, for software development purposes or just restarting a crashed
|
||||
* service. This property defaults to true (although it should be noted
|
||||
* that, at the operating system level, this defaults to false!). If this
|
||||
* property is false and the OS feels that not enough time has elapsed,
|
||||
* socket creation will fail and this function will report an error.
|
||||
* - `NET_PROP_DATAGRAM_SOCKET_ALLOW_BROADCAST_BOOLEAN`: true if the socket
|
||||
* should allow broadcasting. At the lower level, this will set
|
||||
* `SO_BROADCAST` for IPv4 sockets, to allow sending to the subnet's
|
||||
* broadcast address at the OS level. For IPv6, it'll join the all-nodes
|
||||
* link-local multicast group, ff02::1, allowing sending and receiving
|
||||
* there, more or less simulating the usual IPv4 broadcast semantics. Other
|
||||
* protocols take similar approaches. If you do not intend to send or
|
||||
* receive broadcast packets on this socket, set this property to false, or
|
||||
* omit it, as it defaults to false. Note: IPv4 will still be able to
|
||||
* receive broadcast packets without this option, but IPv6 will not. Also
|
||||
* see notes about sending to a broadcast address in NET_SendDatagram().
|
||||
*
|
||||
* \param addr the local address to listen for connections on, or NULL to
|
||||
* listen on all available local addresses.
|
||||
* \param port the port on the local address to listen for connections on, or
|
||||
* zero for the system to decide.
|
||||
* \param props properties of the new socket. Specify zero for defaults.
|
||||
* \returns a new NET_DatagramSocket, or NULL on error; call SDL_GetError()
|
||||
* for details.
|
||||
*
|
||||
@@ -1227,7 +1322,11 @@ typedef struct NET_Datagram
|
||||
* \sa NET_GetLocalAddresses
|
||||
* \sa NET_DestroyDatagramSocket
|
||||
*/
|
||||
extern SDL_DECLSPEC NET_DatagramSocket * SDLCALL NET_CreateDatagramSocket(NET_Address *addr, Uint16 port);
|
||||
extern SDL_DECLSPEC NET_DatagramSocket * SDLCALL NET_CreateDatagramSocket(NET_Address *addr, Uint16 port, SDL_PropertiesID props);
|
||||
|
||||
#define NET_PROP_DATAGRAM_SOCKET_REUSEADDR_BOOLEAN "NET.datagram_socket.reuseaddr"
|
||||
#define NET_PROP_DATAGRAM_SOCKET_ALLOW_BROADCAST_BOOLEAN "NET.datagram_socket.allow_broadcast"
|
||||
|
||||
|
||||
/**
|
||||
* Send a new packet over a datagram socket to a remote system.
|
||||
@@ -1239,7 +1338,9 @@ extern SDL_DECLSPEC NET_DatagramSocket * SDLCALL NET_CreateDatagramSocket(NET_Ad
|
||||
*
|
||||
* Datagram packets might arrive in a different order than you sent them, or
|
||||
* they may just be lost while travelling across the network. You have to plan
|
||||
* for this.
|
||||
* for this. As an added confusion, since SDL_net might send the same packet
|
||||
* on multiple interfaces, you might get duplicate packets, possibly from
|
||||
* different network addresses. You have to plan for this, too.
|
||||
*
|
||||
* You can send to any address and port on the network, but there has to be a
|
||||
* datagram socket waiting for the data on the other side for the packet not
|
||||
@@ -1262,8 +1363,37 @@ extern SDL_DECLSPEC NET_DatagramSocket * SDLCALL NET_CreateDatagramSocket(NET_Ad
|
||||
* should assume it is no longer usable and should destroy it with
|
||||
* SDL_DestroyDatagramSocket().
|
||||
*
|
||||
* Sending to a NULL address is treated as a request to broadcast a packet.
|
||||
* Note that this will report failure immediately if the socket was not
|
||||
* created with broadcast permission. Broadcast packets are (more or less)
|
||||
* sent to every machine on the LAN, unconditionally.
|
||||
*
|
||||
* **WARNING**: It is possible to build a game where everyone is playing on
|
||||
* the same LAN, and every player is simply broadcasting packets. This is
|
||||
* absolutely the wrong thing to do, however. Broadcast packets go to every
|
||||
* device on the LAN, whether they want them or not. The game DOOM, in its
|
||||
* heyday, was capable of
|
||||
* [bringing entire networks to their knees](https://doomwiki.org/wiki/Doom_in_workplaces)
|
||||
* , as many players on the same network would all be broadcasting
|
||||
* relentlessly.
|
||||
*
|
||||
* In practice, broadcasting sparingly can be useful for certain
|
||||
* functionality: a LAN-only client broadcasting a few packets to ask for
|
||||
* available servers, and running servers replying directly to that client
|
||||
* without broadcasting at all, is reasonable and safe. Once clients and
|
||||
* servers have found each other, they can communicate directly without any
|
||||
* broadcasting at all. For peer-to-peer games, once connection is
|
||||
* established, it's better to either send unique packets to each known
|
||||
* player, or use a multicasting (which works like broadcast, but only routes
|
||||
* packets to devices that are explicitly listening for it).
|
||||
*
|
||||
* With IPv6, which doesn't support broadcasts, broadcasting is faked with
|
||||
* multicast to the all-nodes link-local multicast group, ff02::1, either on a
|
||||
* specific interface or letting the OS choose the default. Other protocols
|
||||
* might fake broadcast operations in similar ways in the future.
|
||||
*
|
||||
* \param sock the datagram socket to send data through.
|
||||
* \param address the NET_Address object address.
|
||||
* \param address the NET_Address object address. May be NULL to broadcast.
|
||||
* \param port the address port.
|
||||
* \param buf a pointer to the data to send as a single packet.
|
||||
* \param buflen the size of the data to send, in bytes.
|
||||
@@ -1287,7 +1417,7 @@ extern SDL_DECLSPEC bool SDLCALL NET_SendDatagram(NET_DatagramSocket *sock, NET_
|
||||
* Datagram sockets send packets of data. They either arrive as complete
|
||||
* packets or they don't arrive at all, so you'll never receive half a packet.
|
||||
*
|
||||
* This call never blocks; if no new data isn't available at the time of the
|
||||
* This call never blocks; if no new data is available at the time of the
|
||||
* call, it returns true immediately. The caller can try again later.
|
||||
*
|
||||
* On a successful call to this function, it returns true, even if no new
|
||||
|
||||
+476
-92
@@ -171,7 +171,9 @@ static int WindowsPoll(struct pollfd *fds, unsigned int nfds, int timeout)
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#ifndef SDL_PLATFORM_VITA
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
@@ -182,15 +184,18 @@ static int WindowsPoll(struct pollfd *fds, unsigned int nfds, int timeout)
|
||||
|
||||
#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)
|
||||
#define USE_NETLINK 1
|
||||
#endif
|
||||
|
||||
#ifdef USE_NETLINK
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETIFADDRS
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#ifdef SDL_PLATFORM_VITA
|
||||
#include <psp2/net/netctl.h>
|
||||
#endif
|
||||
|
||||
#define INVALID_SOCKET -1
|
||||
#define SOCKET_ERROR -1
|
||||
typedef int Socket;
|
||||
@@ -211,13 +216,7 @@ int NET_Version(void)
|
||||
return SDL_NET_VERSION;
|
||||
}
|
||||
|
||||
typedef enum NET_AddressType
|
||||
{
|
||||
NET_ADDRTYPE_UNKNOWN=-1,
|
||||
NET_ADDRTYPE_UNICAST,
|
||||
NET_ADDRTYPE_MULTICAST,
|
||||
NET_ADDRTYPE_BROADCAST
|
||||
} NET_AddressType;
|
||||
typedef struct NetworkInterface NetworkInterface;
|
||||
|
||||
struct NET_Address
|
||||
{
|
||||
@@ -226,18 +225,17 @@ struct NET_Address
|
||||
char *errstr;
|
||||
SDL_AtomicInt refcount;
|
||||
SDL_AtomicInt status; // This is actually a NET_Status.
|
||||
NET_AddressType type;
|
||||
struct addrinfo *ainfo;
|
||||
NET_Address *resolver_next; // a linked list for the resolution job queue.
|
||||
};
|
||||
|
||||
typedef struct NetworkInterfaces
|
||||
struct NetworkInterface
|
||||
{
|
||||
char *name;
|
||||
int index;
|
||||
Uint32 index;
|
||||
NET_Address *address;
|
||||
NET_Address *broadcast;
|
||||
} NetworkInterfaces;
|
||||
};
|
||||
|
||||
|
||||
#define MIN_RESOLVER_THREADS 2
|
||||
@@ -257,9 +255,13 @@ static SDL_AtomicInt resolver_percent_loss;
|
||||
static SDL_InitState interface_init;
|
||||
static SDL_RWLock *interface_rwlock = NULL;
|
||||
static int num_interfaces = 0;
|
||||
static NetworkInterfaces *interfaces = NULL;
|
||||
static NetworkInterface *interfaces = NULL;
|
||||
static SDL_AtomicInt interfaces_have_changed;
|
||||
|
||||
// Other stuff...
|
||||
static NET_Address *ipv6_broadcast_addr = NULL;
|
||||
|
||||
|
||||
// between lo and hi (inclusive; it can return lo or hi itself, too!).
|
||||
static int RandomNumberBetween(const int lo, const int hi)
|
||||
{
|
||||
@@ -381,7 +383,7 @@ static NET_Address *CreateSDLNetAddrFromSockAddr(const struct sockaddr *saddr, S
|
||||
|
||||
|
||||
/* Network interface enumeration... */
|
||||
static void FreeNetworkInterfaces(NetworkInterfaces *ifaces, int num_ifaces)
|
||||
static void FreeNetworkInterfaces(NetworkInterface *ifaces, int num_ifaces)
|
||||
{
|
||||
for (int i = 0; i < num_ifaces; i++) {
|
||||
NET_UnrefAddress(ifaces[i].address);
|
||||
@@ -447,7 +449,7 @@ static void RefreshInterfaces(void) // WINDOWS VERSION
|
||||
}
|
||||
}
|
||||
|
||||
NetworkInterfaces *new_interfaces = (NetworkInterfaces *) SDL_calloc(new_num_interfaces + 1, sizeof (*new_interfaces));
|
||||
NetworkInterface *new_interfaces = (NetworkInterface *) SDL_calloc(new_num_interfaces + 1, sizeof (*new_interfaces));
|
||||
if (!new_interfaces) {
|
||||
SDL_free(addrs);
|
||||
return;
|
||||
@@ -455,30 +457,32 @@ static void RefreshInterfaces(void) // WINDOWS VERSION
|
||||
|
||||
int count = 0;
|
||||
for (IP_ADAPTER_ADDRESSES *i = addrs; i != NULL; i = i->Next) {
|
||||
char *friendlyname = SDL_iconv_string("UTF-8", "UTF-16LE", (const char*)(i->FriendlyName), (SDL_wcslen(i->FriendlyName) + 1) * sizeof(WCHAR));
|
||||
for (IP_ADAPTER_UNICAST_ADDRESS *j = i->FirstUnicastAddress; j != NULL; j = j->Next) {
|
||||
NET_Address *addr = CreateSDLNetAddrFromSockAddr(j->Address.lpSockaddr, j->Address.iSockaddrLength);
|
||||
if (addr) {
|
||||
new_interfaces[count].name = friendlyname ? SDL_strdup(friendlyname) : NULL;
|
||||
new_interfaces[count].address = addr;
|
||||
if (j->Address.lpSockaddr->sa_family == AF_INET6) {
|
||||
new_interfaces[count].index = i->Ipv6IfIndex;
|
||||
new_interfaces[count].index = (Uint32) i->Ipv6IfIndex;
|
||||
} else if (j->Address.lpSockaddr->sa_family == AF_INET) { // if this is IPv4, calculate the broadcast address.
|
||||
SOCKADDR_IN bcast;
|
||||
SDL_assert(j->Address.iSockaddrLength == sizeof (bcast));
|
||||
SDL_memcpy(&bcast, (const SOCKADDR_IN *) j->Address.lpSockaddr, sizeof (SOCKADDR_IN));
|
||||
bcast.sin_addr.S_un.S_addr |= htonl(~((1 << (32 - j->OnLinkPrefixLength)) - 1));
|
||||
new_interfaces[count].broadcast = CreateSDLNetAddrFromSockAddr((const struct sockaddr *) &bcast, sizeof (bcast));
|
||||
new_interfaces[count].broadcast->type = NET_ADDRTYPE_BROADCAST;
|
||||
new_interfaces[count].index = i->IfIndex;
|
||||
bcast.sin_addr.S_un.S_addr |= htonl((1 << (32 - j->OnLinkPrefixLength)) - 1);
|
||||
new_interfaces[count].broadcast = CreateSDLNetAddrFromSockAddr((const struct sockaddr*)&bcast, sizeof(bcast));
|
||||
new_interfaces[count].index = (Uint32) i->IfIndex;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
SDL_free(friendlyname);
|
||||
}
|
||||
|
||||
new_num_interfaces = count; // in case we dropped one somewhere.
|
||||
|
||||
SDL_LockRWLockForWriting(interface_rwlock);
|
||||
NetworkInterfaces *old_interfaces = interfaces;
|
||||
NetworkInterface *old_interfaces = interfaces;
|
||||
const int old_num_interfaces = num_interfaces;
|
||||
interfaces = new_interfaces;
|
||||
num_interfaces = new_num_interfaces;
|
||||
@@ -488,11 +492,21 @@ static void RefreshInterfaces(void) // WINDOWS VERSION
|
||||
SDL_free(addrs);
|
||||
}
|
||||
|
||||
#elif defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_APPLE) || defined(SDL_PLATFORM_FREEBSD) || defined(SDL_PLATFORM_OPENBSD) || defined(SDL_PLATFORM_NETBSD)
|
||||
#elif defined(USE_NETLINK) || defined(HAVE_GETIFADDRS)
|
||||
|
||||
// AF_NETLINK covers Linux (and by extension Android). PF_ROUTE covers the BSDs (and by extension Apple platforms).
|
||||
// This doesn't cover all Unix platforms that ever existed, but this hits just about everything that is still being maintained seriously.
|
||||
|
||||
#if defined(SDL_PLATFORM_HAIKU) // haiku has its own thing for monitoring, but needs getifaddrs.
|
||||
extern bool NET_HAIKU_InitInterfaceChangeNotifications(SDL_AtomicInt *changed);
|
||||
extern void NET_HAIKU_QuitInterfaceChangeNotifications(void);
|
||||
#elif defined(USE_NETLINK) || defined(PF_ROUTE)
|
||||
#define USE_NETWORK_MONITOR 1
|
||||
#else
|
||||
#warning unknown network monitoring system for this platform - will not report network changes
|
||||
#endif
|
||||
|
||||
#if defined(USE_NETWORK_MONITOR)
|
||||
static SDL_Thread *interface_change_notifications_thread = NULL;
|
||||
static SDL_AtomicInt interface_change_notifications_flag; // !!! FIXME
|
||||
|
||||
@@ -514,7 +528,7 @@ static int SDLCALL LinuxInterfaceChangeNotificationThread(void *data)
|
||||
struct sockaddr_nl addr;
|
||||
SDL_zero(addr);
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pid = getpid();
|
||||
addr.nl_pid = 0; // zero==let the kernel choose a unique number. THIS IS THE SOCKET PORT ID, NOT THE PROCESS ID!
|
||||
addr.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR;
|
||||
if (bind(fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
|
||||
close(fd);
|
||||
@@ -552,7 +566,7 @@ static int SDLCALL LinuxInterfaceChangeNotificationThread(void *data)
|
||||
|
||||
// we don't currently bother parsing for specifics, we just use this as a signal to reenumerate interfaces.
|
||||
//for (struct nlmsghdr *i = buf; NLMSG_OK(i, br); i = NLMSG_NEXT(i, br)) {}
|
||||
SDL_Log("Network interfaces changed!");
|
||||
//SDL_Log("Network interfaces changed!");
|
||||
SDL_SetAtomicInt(&interfaces_have_changed, 1);
|
||||
}
|
||||
|
||||
@@ -560,21 +574,32 @@ static int SDLCALL LinuxInterfaceChangeNotificationThread(void *data)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool InitInterfaceChangeNotifications(void) // LINUX/BSD VERSION
|
||||
{
|
||||
#ifdef USE_NETWORK_MONITOR
|
||||
interface_change_notifications_thread = SDL_CreateThread(LinuxInterfaceChangeNotificationThread, "SDLNetIfaceEnum", NULL);
|
||||
return (interface_change_notifications_thread != NULL);
|
||||
#elif defined(SDL_PLATFORM_HAIKU)
|
||||
return NET_HAIKU_InitInterfaceChangeNotifications(&interfaces_have_changed);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void QuitInterfaceChangeNotifications(void) // LINUX/BSD VERSION
|
||||
{
|
||||
#ifdef USE_NETWORK_MONITOR
|
||||
if (interface_change_notifications_thread) {
|
||||
SDL_SetAtomicInt(&interface_change_notifications_flag, 1);
|
||||
SDL_WaitThread(interface_change_notifications_thread, NULL);
|
||||
SDL_SetAtomicInt(&interface_change_notifications_flag, 0);
|
||||
}
|
||||
interface_change_notifications_thread = NULL;
|
||||
#elif defined(SDL_PLATFORM_HAIKU)
|
||||
NET_HAIKU_QuitInterfaceChangeNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void RefreshInterfaces(void) // LINUX/BSD VERSION
|
||||
@@ -602,13 +627,13 @@ static void RefreshInterfaces(void) // LINUX/BSD VERSION
|
||||
req.header.nlmsg_len = NLMSG_LENGTH(sizeof (req.msg));
|
||||
req.msg.ifa_family = AF_UNSPEC;
|
||||
|
||||
if (send(sock, &req, req.header.nlmsg_len, 0) != req.header.nlmsg_len) {
|
||||
if (send(sock, &req, req.header.nlmsg_len, 0) != (Sint32)req.header.nlmsg_len) {
|
||||
close(sock);
|
||||
return; // oh well.
|
||||
}
|
||||
|
||||
int new_num_interfaces = 0;
|
||||
NetworkInterfaces *new_interfaces = NULL;
|
||||
NetworkInterface *new_interfaces = NULL;
|
||||
|
||||
Uint8 buffer[64 * 1024];
|
||||
ssize_t br;
|
||||
@@ -624,8 +649,8 @@ static void RefreshInterfaces(void) // LINUX/BSD VERSION
|
||||
if (!ptr) {
|
||||
goto failed;
|
||||
}
|
||||
new_interfaces = (NetworkInterfaces *) ptr;
|
||||
NetworkInterfaces *iface = &new_interfaces[new_num_interfaces];
|
||||
new_interfaces = (NetworkInterface *) ptr;
|
||||
NetworkInterface *iface = &new_interfaces[new_num_interfaces];
|
||||
SDL_zerop(iface);
|
||||
|
||||
const struct ifaddrmsg *msg = (const struct ifaddrmsg *) (NLMSG_DATA(header));
|
||||
@@ -657,10 +682,7 @@ static void RefreshInterfaces(void) // LINUX/BSD VERSION
|
||||
}
|
||||
|
||||
if (iface->address) {
|
||||
iface->index = msg->ifa_index;
|
||||
if (iface->broadcast) {
|
||||
iface->broadcast->type = NET_ADDRTYPE_BROADCAST;
|
||||
}
|
||||
iface->index = (Uint32) msg->ifa_index;
|
||||
|
||||
char interface_name[IF_NAMESIZE];
|
||||
if (if_indextoname((unsigned int) iface->index, interface_name) == NULL) { // miraculously, this function is in Android 21; nothing else is, though! We could have done this with netlink too, but this is the easy button.
|
||||
@@ -683,7 +705,7 @@ static void RefreshInterfaces(void) // LINUX/BSD VERSION
|
||||
succeeded:
|
||||
close(sock);
|
||||
SDL_LockRWLockForWriting(interface_rwlock);
|
||||
NetworkInterfaces *old_interfaces = interfaces;
|
||||
NetworkInterface *old_interfaces = interfaces;
|
||||
const int old_num_interfaces = num_interfaces;
|
||||
interfaces = new_interfaces;
|
||||
num_interfaces = new_num_interfaces;
|
||||
@@ -701,10 +723,10 @@ failed:
|
||||
return; // oh well.
|
||||
}
|
||||
|
||||
NetworkInterfaces *new_interfaces = NULL;
|
||||
NetworkInterface *new_interfaces = NULL;
|
||||
int new_num_interfaces = 0;
|
||||
for (struct ifaddrs *i = ifaddr; i != NULL; i = i->ifa_next) {
|
||||
if (i->ifa_name != NULL) {
|
||||
if (i->ifa_name && i->ifa_addr && (i->ifa_flags & IFF_UP)) {
|
||||
new_num_interfaces++;
|
||||
}
|
||||
}
|
||||
@@ -718,10 +740,10 @@ failed:
|
||||
goto failed;
|
||||
}
|
||||
|
||||
NetworkInterfaces *iface = &new_interfaces[0];
|
||||
for (struct ifaddrs *i = ifaddr; i != NULL; i = i->ifa_next, iface++) {
|
||||
if (i->ifa_name == NULL) {
|
||||
continue; // i guess.
|
||||
NetworkInterface *iface = &new_interfaces[0];
|
||||
for (struct ifaddrs *i = ifaddr; i != NULL; i = i->ifa_next) {
|
||||
if (!i->ifa_name || !i->ifa_addr || ((i->ifa_flags & IFF_UP) == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// !!! FIXME: getifaddrs doesn't return the sockaddr length, so we have to go with known protocols. :/
|
||||
@@ -734,16 +756,11 @@ failed:
|
||||
iface->address = CreateSDLNetAddrFromSockAddr(i->ifa_addr, sizeof (struct sockaddr_in6));
|
||||
} else {
|
||||
new_num_interfaces--;
|
||||
iface--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iface->address) {
|
||||
if (iface->broadcast) {
|
||||
iface->broadcast->type = NET_ADDRTYPE_BROADCAST;
|
||||
}
|
||||
|
||||
iface->index = (int) if_nametoindex(i->ifa_name);
|
||||
iface->index = (Uint32) if_nametoindex(i->ifa_name);
|
||||
iface->name = SDL_strdup(i->ifa_name);
|
||||
if (!iface->name) {
|
||||
goto failed;
|
||||
@@ -757,6 +774,8 @@ failed:
|
||||
NET_UnrefAddress(iface->broadcast); // just in case.
|
||||
goto failed;
|
||||
}
|
||||
|
||||
iface++;
|
||||
}
|
||||
|
||||
succeeded:
|
||||
@@ -765,7 +784,7 @@ succeeded:
|
||||
}
|
||||
|
||||
SDL_LockRWLockForWriting(interface_rwlock);
|
||||
NetworkInterfaces *old_interfaces = interfaces;
|
||||
NetworkInterface *old_interfaces = interfaces;
|
||||
const int old_num_interfaces = num_interfaces;
|
||||
interfaces = new_interfaces;
|
||||
num_interfaces = new_num_interfaces;
|
||||
@@ -782,18 +801,182 @@ failed:
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(SDL_PLATFORM_VITA)
|
||||
|
||||
static int interface_change_notifications_handle;
|
||||
static SDL_Thread *interface_change_notifications_thread = NULL;
|
||||
static SDL_AtomicInt interface_change_notifications_flag;
|
||||
|
||||
static int SDLCALL VitaInterfaceChangeNotificationThread(void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
while(SDL_GetAtomicInt(&interface_change_notifications_flag) == 0)
|
||||
{
|
||||
sceNetCtlCheckCallback();
|
||||
SDL_Delay(100);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void NetworkInterfaceChangedCallback(int event_type, void* arg)
|
||||
{
|
||||
SDL_SetAtomicInt(&interfaces_have_changed, 1);
|
||||
}
|
||||
|
||||
static bool InitInterfaceChangeNotifications(void)
|
||||
{
|
||||
if (sceNetCtlInetRegisterCallback(NetworkInterfaceChangedCallback, NULL, &interface_change_notifications_handle) != 0)
|
||||
return false;
|
||||
|
||||
interface_change_notifications_thread = SDL_CreateThread(VitaInterfaceChangeNotificationThread, "SDLNetIfaceEnum", NULL);
|
||||
return (interface_change_notifications_thread != NULL);
|
||||
}
|
||||
|
||||
static void QuitInterfaceChangeNotifications(void)
|
||||
{
|
||||
sceNetCtlInetUnregisterCallback(interface_change_notifications_handle);
|
||||
if (interface_change_notifications_thread) {
|
||||
SDL_SetAtomicInt(&interface_change_notifications_flag, 1);
|
||||
SDL_WaitThread(interface_change_notifications_thread, NULL);
|
||||
SDL_SetAtomicInt(&interface_change_notifications_flag, 0);
|
||||
}
|
||||
interface_change_notifications_thread = NULL;
|
||||
}
|
||||
|
||||
static NET_Address *CreateSDLNetAddrFromIp(char* hostbuf)
|
||||
{
|
||||
NET_Address *addr = (NET_Address *) SDL_calloc(1, sizeof (NET_Address));
|
||||
if (!addr) {
|
||||
return NULL;
|
||||
}
|
||||
SDL_SetAtomicInt(&addr->status, (int) NET_SUCCESS);
|
||||
|
||||
struct addrinfo hints;
|
||||
SDL_zero(hints);
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_protocol = 0;
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
|
||||
int gairc = getaddrinfo(hostbuf, NULL, &hints, &addr->ainfo);
|
||||
if (gairc != 0) {
|
||||
SDL_free(addr);
|
||||
SetGetAddrInfoError("Failed to determine address", gairc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addr->human_readable = SDL_strdup(hostbuf);
|
||||
if (!addr->human_readable) {
|
||||
freeaddrinfo(addr->ainfo);
|
||||
SDL_free(addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NET_RefAddress(addr);
|
||||
}
|
||||
|
||||
|
||||
static void RefreshInterfaces(void)
|
||||
{
|
||||
NetworkInterface *new_interfaces = NULL;
|
||||
int new_num_interfaces = 0;
|
||||
SceNetCtlInfo info;
|
||||
|
||||
int state;
|
||||
if (sceNetCtlInetGetState(&state) < 0 ) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (state != SCE_NETCTL_STATE_CONNECTED) {
|
||||
goto succeeded;
|
||||
}
|
||||
|
||||
if (state == SCE_NETCTL_STATE_CONNECTED) {
|
||||
new_num_interfaces = 1;
|
||||
|
||||
new_interfaces = SDL_calloc(new_num_interfaces, sizeof (*new_interfaces));
|
||||
if (!new_interfaces) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
NetworkInterface *iface = &new_interfaces[0];
|
||||
|
||||
if (sceNetCtlInetGetInfo(SCE_NETCTL_INFO_GET_IP_ADDRESS, &info) < 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
||||
iface->address = CreateSDLNetAddrFromIp(info.ip_address);
|
||||
|
||||
if (iface->address) {
|
||||
iface->index = 0;
|
||||
|
||||
if (sceNetCtlInetGetInfo(SCE_NETCTL_INFO_GET_DEVICE, &info) < 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
switch (info.device) {
|
||||
case 0:
|
||||
iface->name = SDL_strdup("wlan0");
|
||||
break;
|
||||
case 1:
|
||||
iface->name = SDL_strdup("eth0");
|
||||
break;
|
||||
case 2:
|
||||
iface->name = SDL_strdup("phone0");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!iface->name) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
char *ptr = SDL_strchr(iface->address->human_readable, '%'); // chop off interface name.
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
} else {
|
||||
NET_UnrefAddress(iface->broadcast); // just in case.
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
succeeded:
|
||||
SDL_LockRWLockForWriting(interface_rwlock);
|
||||
NetworkInterface *old_interfaces = interfaces;
|
||||
const int old_num_interfaces = num_interfaces;
|
||||
interfaces = new_interfaces;
|
||||
num_interfaces = new_num_interfaces;
|
||||
SDL_UnlockRWLock(interface_rwlock);
|
||||
FreeNetworkInterfaces(old_interfaces, old_num_interfaces);
|
||||
return;
|
||||
|
||||
failed:
|
||||
FreeNetworkInterfaces(new_interfaces, new_num_interfaces);
|
||||
}
|
||||
|
||||
#else
|
||||
#error implement me for your platform.
|
||||
#warning implement me for your platform.
|
||||
static bool InitInterfaceChangeNotifications(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void QuitInterfaceChangeNotifications(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void RefreshInterfaces(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static bool InterfacesReady(void)
|
||||
{
|
||||
if (SDL_ShouldInit(&interface_init)) {
|
||||
if (!interface_rwlock) {
|
||||
interface_rwlock = SDL_CreateRWLock();
|
||||
}
|
||||
if (!interface_rwlock || !InitInterfaceChangeNotifications()) {
|
||||
if (!InitInterfaceChangeNotifications()) {
|
||||
SDL_SetInitialized(&interface_init, false);
|
||||
return false;
|
||||
}
|
||||
@@ -806,14 +989,16 @@ static bool InterfacesReady(void)
|
||||
RefreshInterfaces();
|
||||
#if 0
|
||||
SDL_Log("NETWORK INTERFACE REFRESH");
|
||||
SDL_LockRWLockForReading(interface_rwlock);
|
||||
for (int i = 0; i < num_interfaces; i++) {
|
||||
const NetworkInterfaces *iface = &interfaces[i];
|
||||
SDL_Log("Interface %d ('%s')", iface->index, iface->name);
|
||||
const NetworkInterface *iface = &interfaces[i];
|
||||
SDL_Log("Interface %u ('%s')", (unsigned int) iface->index, iface->name);
|
||||
SDL_Log(" - address %s", iface->address->human_readable);
|
||||
if (iface->broadcast) {
|
||||
SDL_Log(" - broadcast %s", iface->broadcast->human_readable);
|
||||
}
|
||||
}
|
||||
SDL_UnlockRWLock(interface_rwlock);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -849,7 +1034,6 @@ static NET_Status ResolveAddress(NET_Address *addr)
|
||||
|
||||
addr->human_readable = SDL_strdup(buf);
|
||||
addr->ainfo = ainfo;
|
||||
addr->type = NET_ADDRTYPE_UNICAST;
|
||||
|
||||
return NET_SUCCESS; // success (zero means "still in progress").
|
||||
}
|
||||
@@ -976,8 +1160,6 @@ static NET_Address *CreateSDLNetAddrFromSockAddr(const struct sockaddr *saddr, S
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addr->type = NET_ADDRTYPE_UNICAST; // until told otherwise.
|
||||
|
||||
addr->human_readable = SDL_strdup(hostbuf);
|
||||
if (!addr->human_readable) {
|
||||
freeaddrinfo(addr->ainfo);
|
||||
@@ -1003,6 +1185,9 @@ bool NET_Init(void)
|
||||
if (WSAStartup(MAKEWORD(1, 1), &data) != 0) {
|
||||
return SetSocketErrorBool("WSAStartup() failed", LastSocketError());
|
||||
}
|
||||
#elif defined(SDL_PLATFORM_VITA)
|
||||
// trigger vita network stack startup
|
||||
gethostname(NULL,0);
|
||||
#else
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
@@ -1030,6 +1215,18 @@ bool NET_Init(void)
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_in6 sa_in6;
|
||||
SDL_zero(sa_in6);
|
||||
if (inet_pton(AF_INET6, "ff02::1", &sa_in6.sin6_addr) == 1) {
|
||||
sa_in6.sin6_family = AF_INET6;
|
||||
ipv6_broadcast_addr = CreateSDLNetAddrFromSockAddr((const struct sockaddr *) &sa_in6, sizeof (sa_in6));
|
||||
}
|
||||
|
||||
interface_rwlock = SDL_CreateRWLock();
|
||||
if (!interface_rwlock) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return true; // good to go.
|
||||
|
||||
failed:
|
||||
@@ -1093,20 +1290,23 @@ void NET_Quit(void)
|
||||
if (interfaces) {
|
||||
FreeNetworkInterfaces(interfaces, num_interfaces);
|
||||
}
|
||||
if (interface_rwlock) {
|
||||
SDL_DestroyRWLock(interface_rwlock);
|
||||
}
|
||||
interfaces = NULL;
|
||||
num_interfaces = 0;
|
||||
interface_rwlock = NULL;
|
||||
SDL_SetInitialized(&interface_init, false);
|
||||
}
|
||||
|
||||
// asserts to catch that these shouldn't have ever been set if we never initialized interface_init...
|
||||
SDL_assert(!interfaces);
|
||||
SDL_assert(!interface_rwlock);
|
||||
SDL_assert(num_interfaces == 0);
|
||||
|
||||
if (interface_rwlock) {
|
||||
SDL_DestroyRWLock(interface_rwlock);
|
||||
interface_rwlock = NULL;
|
||||
}
|
||||
|
||||
NET_UnrefAddress(ipv6_broadcast_addr);
|
||||
ipv6_broadcast_addr = NULL;
|
||||
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
WSACleanup();
|
||||
#endif
|
||||
@@ -1238,6 +1438,34 @@ const char *NET_GetAddressString(NET_Address *addr)
|
||||
return retval;
|
||||
}
|
||||
|
||||
const void * NET_GetAddressBytes(NET_Address *addr, int *num_bytes)
|
||||
{
|
||||
if (!num_bytes) {
|
||||
SDL_InvalidParamError("num_bytes");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*num_bytes = 0;
|
||||
|
||||
if (!addr) {
|
||||
SDL_InvalidParamError("address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const void *retval = NULL;
|
||||
const NET_Status rc = NET_GetAddressStatus(addr);
|
||||
if (rc == NET_SUCCESS) {
|
||||
const struct addrinfo *ainfo = addr->ainfo;
|
||||
SDL_assert(ainfo != NULL);
|
||||
retval = (const void *) ainfo->ai_addr;
|
||||
*num_bytes = (int) ainfo->ai_addrlen;
|
||||
} else if (rc != NET_FAILURE) { // if NET_FAILURE, it'll set the error message.
|
||||
SDL_SetError("Address not yet resolved");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int NET_CompareAddresses(const NET_Address *sdlneta, const NET_Address *sdlnetb)
|
||||
{
|
||||
if (sdlneta == sdlnetb) { // same pointer?
|
||||
@@ -1289,7 +1517,6 @@ void NET_SimulateAddressResolutionLoss(int percent_loss)
|
||||
SDL_SetAtomicInt(&resolver_percent_loss, SDL_clamp(percent_loss, 0, 100));
|
||||
}
|
||||
|
||||
|
||||
NET_Address **NET_GetLocalAddresses(int *num_addresses)
|
||||
{
|
||||
int dummy_addresses;
|
||||
@@ -1372,7 +1599,7 @@ struct NET_StreamSocket
|
||||
Uint64 simulated_failure_until;
|
||||
};
|
||||
|
||||
NET_StreamSocket *NET_CreateClient(NET_Address *addr, Uint16 port)
|
||||
NET_StreamSocket *NET_CreateClient(NET_Address *addr, Uint16 port, SDL_PropertiesID props)
|
||||
{
|
||||
if (addr == NULL) {
|
||||
SDL_InvalidParamError("address");
|
||||
@@ -1471,7 +1698,7 @@ struct NET_Server
|
||||
Socket handle_pool[4];
|
||||
};
|
||||
|
||||
NET_Server *NET_CreateServer(NET_Address *addr, Uint16 port)
|
||||
NET_Server *NET_CreateServer(NET_Address *addr, Uint16 port, SDL_PropertiesID props)
|
||||
{
|
||||
if (addr && (((NET_Status) SDL_GetAtomicInt(&addr->status)) != NET_SUCCESS)) {
|
||||
SDL_SetError("Address is not resolved"); // strictly speaking, this should be a local interface, but a resolved address can fail later.
|
||||
@@ -1515,6 +1742,8 @@ NET_Server *NET_CreateServer(NET_Address *addr, Uint16 port)
|
||||
}
|
||||
}
|
||||
|
||||
const int reuseaddr = SDL_GetBooleanProperty(props, NET_PROP_SERVER_REUSEADDR_BOOLEAN, true) ? 1 : 0;
|
||||
|
||||
// Make sockets for all desired interfaces; if addr!=NULL, this is one socket on one interface,
|
||||
// but if addr==NULL, it might be multiple sockets for IPv4, IPv6, etc, bound to their INADDR_ANY equivalent.
|
||||
struct addrinfo *ainfo = addrwithport;
|
||||
@@ -1538,7 +1767,7 @@ NET_Server *NET_CreateServer(NET_Address *addr, Uint16 port)
|
||||
setsockopt(handle, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &one, sizeof (one)); // if this fails, oh well.
|
||||
}
|
||||
|
||||
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (const char *) &one, sizeof (one));
|
||||
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuseaddr, sizeof (reuseaddr));
|
||||
|
||||
int rc = bind(handle, ainfo->ai_addr, (SockLen) ainfo->ai_addrlen);
|
||||
if (rc == SOCKET_ERROR) {
|
||||
@@ -1855,6 +2084,7 @@ typedef struct NET_DatagramSocketHandle
|
||||
Socket handle;
|
||||
int family;
|
||||
int protocol;
|
||||
NET_Address *broadcast;
|
||||
} NET_DatagramSocketHandle;
|
||||
|
||||
struct NET_DatagramSocket
|
||||
@@ -1872,10 +2102,57 @@ struct NET_DatagramSocket
|
||||
NET_Datagram **pending_output;
|
||||
int pending_output_len;
|
||||
int pending_output_allocation;
|
||||
bool allow_broadcast;
|
||||
};
|
||||
|
||||
static NET_Address *FindBroadcastAddress(struct addrinfo *ainfo, Uint32 *interface_index)
|
||||
{
|
||||
NET_Address *retval = NULL;
|
||||
|
||||
NET_DatagramSocket *NET_CreateDatagramSocket(NET_Address *addr, Uint16 port)
|
||||
NET_Address *iface = CreateSDLNetAddrFromSockAddr(ainfo->ai_addr, (SockLen) ainfo->ai_addrlen);
|
||||
if (!iface) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NetworkInterface *ni = NULL;
|
||||
if (!InterfacesReady()) {
|
||||
NET_UnrefAddress(iface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_LockRWLockForReading(interface_rwlock);
|
||||
|
||||
for (int i = 0; i < num_interfaces; i++) {
|
||||
if (NET_CompareAddresses(iface, interfaces[i].address) == 0) {
|
||||
ni = &interfaces[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ni) {
|
||||
SDL_SetError("Not a network interface address");
|
||||
} else {
|
||||
SDL_assert(ni->address != NULL);
|
||||
*interface_index = ni->index;
|
||||
if (ni->broadcast != NULL) {
|
||||
retval = NET_RefAddress(ni->broadcast); // we calculated the broadcast address when discovering this interface. It's probably IPv4. We're good to go.
|
||||
} else if (ainfo->ai_family == AF_INET6) { // we fake this for IPv6 on the all-nodes link-local multicast group.
|
||||
retval = NET_RefAddress(ipv6_broadcast_addr);
|
||||
} else {
|
||||
SDL_SetError("Can't determine broadcast address for this interface");
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockRWLock(interface_rwlock);
|
||||
|
||||
if (!retval && (ainfo->ai_family == AF_INET6)) { // we fake this for IPv6 on the all-nodes link-local multicast group.
|
||||
retval = NET_RefAddress(ipv6_broadcast_addr);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
NET_DatagramSocket *NET_CreateDatagramSocket(NET_Address *addr, Uint16 port, SDL_PropertiesID props)
|
||||
{
|
||||
if (addr && (((NET_Status) SDL_GetAtomicInt(&addr->status)) != NET_SUCCESS)) {
|
||||
SDL_SetError("Address is not resolved"); // strictly speaking, this should be a local interface, but a resolved address can fail later.
|
||||
@@ -1897,6 +2174,11 @@ NET_DatagramSocket *NET_CreateDatagramSocket(NET_Address *addr, Uint16 port)
|
||||
sock->addr = addr;
|
||||
sock->port = port;
|
||||
|
||||
const int reuseaddr = SDL_GetBooleanProperty(props, NET_PROP_DATAGRAM_SOCKET_REUSEADDR_BOOLEAN, true) ? 1 : 0;
|
||||
sock->allow_broadcast = SDL_GetBooleanProperty(props, NET_PROP_DATAGRAM_SOCKET_ALLOW_BROADCAST_BOOLEAN, false);
|
||||
|
||||
const int bcast = sock->allow_broadcast ? 1 : 0;
|
||||
|
||||
int num_handles = 0;
|
||||
NET_DatagramSocketHandle *allocated_handles = NULL;
|
||||
if (addr != NULL) {
|
||||
@@ -1942,24 +2224,26 @@ NET_DatagramSocket *NET_CreateDatagramSocket(NET_Address *addr, Uint16 port)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
sock->handles[sock->num_handles].handle = handle;
|
||||
sock->handles[sock->num_handles].family = ainfo->ai_family;
|
||||
sock->handles[sock->num_handles].protocol = ainfo->ai_protocol;
|
||||
sock->num_handles++;
|
||||
NET_DatagramSocketHandle *socket_handle = &sock->handles[sock->num_handles++];
|
||||
|
||||
SDL_zerop(socket_handle);
|
||||
socket_handle->handle = handle;
|
||||
socket_handle->family = ainfo->ai_family;
|
||||
socket_handle->protocol = ainfo->ai_protocol;
|
||||
|
||||
if (MakeSocketNonblocking(handle) < 0) {
|
||||
SDL_SetError("Failed to make new socket non-blocking");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
const int one = 1;
|
||||
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuseaddr, sizeof (reuseaddr));
|
||||
setsockopt(handle, SOL_SOCKET, SO_BROADCAST, (const char *) &bcast, sizeof (bcast));
|
||||
|
||||
if (ainfo->ai_family == AF_INET6) {
|
||||
const int one = 1;
|
||||
setsockopt(handle, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &one, sizeof (one)); // if this fails, oh well.
|
||||
}
|
||||
|
||||
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, (const char *) &one, sizeof (one));
|
||||
setsockopt(handle, SOL_SOCKET, SO_BROADCAST, (const char *) &one, sizeof (one));
|
||||
|
||||
const int rc = bind(handle, ainfo->ai_addr, (SockLen) ainfo->ai_addrlen);
|
||||
if (rc == SOCKET_ERROR) {
|
||||
const int err = LastSocketError();
|
||||
@@ -1967,6 +2251,39 @@ NET_DatagramSocket *NET_CreateDatagramSocket(NET_Address *addr, Uint16 port)
|
||||
SetSocketError("Failed to bind socket", err);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (sock->allow_broadcast) {
|
||||
Uint32 interface_index = 0; // this will stay zero for INADDR6_ANY, to pick a default interface.
|
||||
socket_handle->broadcast = FindBroadcastAddress(ainfo, &interface_index);
|
||||
// if failed but addr==NULL, this is IPv4 and we can't find an interface for INADDR_ANY. We'll broadcast to all interfaces when sending (because 255.255.255.255 doesn't work on Windows).
|
||||
// alternately, we're IPv6 and ipv6_broadcast_addr failed to init for some reason. Just panic and fail here if that happens, I guess.
|
||||
if (!socket_handle->broadcast && (addr || (ainfo->ai_family == AF_INET6))) {
|
||||
SDL_SetError("Failed to determine broadcast address for this interface");
|
||||
goto failed;
|
||||
} else if (ainfo->ai_family == AF_INET6) { // fake broadcast support via multicasting to all-nodes link-local group, ff02::1.
|
||||
#ifdef SDL_PLATFORM_VITA
|
||||
SDL_SetError("No IPv6 support");
|
||||
goto failed;
|
||||
#else
|
||||
SDL_assert(socket_handle->broadcast == ipv6_broadcast_addr);
|
||||
const struct addrinfo *bai = socket_handle->broadcast->ainfo;
|
||||
SDL_assert(bai != NULL);
|
||||
SDL_assert(bai->ai_addr != NULL);
|
||||
SDL_assert(bai->ai_addr->sa_family == AF_INET6);
|
||||
struct ipv6_mreq mreq6;
|
||||
SDL_zero(mreq6);
|
||||
SDL_copyp(&mreq6.ipv6mr_multiaddr, &((struct sockaddr_in6 *) bai->ai_addr)->sin6_addr);
|
||||
mreq6.ipv6mr_interface = interface_index;
|
||||
//SDL_Log("Add membership for %s, index=%d", socket_handle->broadcast->human_readable, (int) interface_index);
|
||||
if (setsockopt(handle, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char *) &mreq6, (SockLen) sizeof (mreq6)) < 0) {
|
||||
SDL_SetError("Failed to join all-nodes link-local multicast group for broadcasting");
|
||||
goto failed;
|
||||
}
|
||||
const int ifidx = (int) interface_index;
|
||||
setsockopt(handle, IPPROTO_IPV6, IPV6_MULTICAST_IF, (const char *) &ifidx, (SockLen) sizeof (ifidx)); // multicast sends go through the same interface.
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(addrwithport);
|
||||
@@ -1977,6 +2294,7 @@ NET_DatagramSocket *NET_CreateDatagramSocket(NET_Address *addr, Uint16 port)
|
||||
failed:
|
||||
for (int i = 0; i < sock->num_handles; i++) {
|
||||
CloseSocketHandle(sock->handles[i].handle);
|
||||
NET_UnrefAddress(sock->handles[i].broadcast);
|
||||
}
|
||||
freeaddrinfo(addrwithport);
|
||||
SDL_free(allocated_handles);
|
||||
@@ -1986,29 +2304,94 @@ failed:
|
||||
|
||||
static NET_Status SendOneDatagram(NET_DatagramSocket *sock, NET_Address *addr, Uint16 port, const void *buf, int buflen)
|
||||
{
|
||||
struct addrinfo *addrwithport = MakeAddrInfoWithPort(addr, SOCK_DGRAM, port);
|
||||
if (!addrwithport) {
|
||||
if (addr) { // unicast to a specific address.
|
||||
struct addrinfo *addrwithport = MakeAddrInfoWithPort(addr, SOCK_DGRAM, port);
|
||||
if (!addrwithport) {
|
||||
return NET_FAILURE;
|
||||
}
|
||||
|
||||
const int family = addrwithport->ai_family;
|
||||
const int protocol = addrwithport->ai_protocol;
|
||||
for (int i = 0; i < sock->num_handles; i++) {
|
||||
const NET_DatagramSocketHandle *handle = &sock->handles[i];
|
||||
if ((handle->family == family) && (handle->protocol == protocol)) { // !!! FIXME: strictly speaking, this _probably_ just needs to check `family`, right?
|
||||
const int rc = (int) sendto(handle->handle, buf, (size_t) buflen, 0, addrwithport->ai_addr, (SockLen) addrwithport->ai_addrlen);
|
||||
const int err = (rc == SOCKET_ERROR) ? LastSocketError() : 0;
|
||||
freeaddrinfo(addrwithport);
|
||||
if (err != 0) {
|
||||
return WouldBlock(err) ? NET_WAITING : SetSocketError("Failed to send from socket", err);
|
||||
}
|
||||
SDL_assert(rc == buflen);
|
||||
return NET_SUCCESS; // !!! FIXME: should we sent to _all_ interfaces in this family?
|
||||
}
|
||||
}
|
||||
SDL_SetError("Unsupported network family in destination address");
|
||||
return NET_FAILURE;
|
||||
|
||||
}
|
||||
|
||||
const int family = addrwithport->ai_family;
|
||||
const int protocol = addrwithport->ai_protocol;
|
||||
// broadcast (or fake with multicast) this packet.
|
||||
SDL_assert(sock->allow_broadcast); // we should have checked this in NET_SendDatagram!
|
||||
|
||||
bool all_wouldblock = false;
|
||||
NET_Status retval = NET_FAILURE;
|
||||
for (int i = 0; i < sock->num_handles; i++) {
|
||||
const NET_DatagramSocketHandle *handle = &sock->handles[i];
|
||||
if ((handle->family == family) && (handle->protocol == protocol)) { // !!! FIXME: strictly speaking, this _probably_ just needs to check `family`, right?
|
||||
const int rc = sendto(handle->handle, buf, (size_t) buflen, 0, addrwithport->ai_addr, (SockLen) addrwithport->ai_addrlen);
|
||||
|
||||
if (handle->broadcast) {
|
||||
struct addrinfo *addrwithport = MakeAddrInfoWithPort(handle->broadcast, SOCK_DGRAM, port);
|
||||
if (!addrwithport) {
|
||||
continue; // oh well, lost UDP packet, I guess.
|
||||
}
|
||||
|
||||
//SDL_Log("Broadcasting on %s ...", handle->broadcast->human_readable);
|
||||
const int rc = (int) sendto(handle->handle, buf, (size_t) buflen, 0, addrwithport->ai_addr, (SockLen) addrwithport->ai_addrlen);
|
||||
const int err = (rc == SOCKET_ERROR) ? LastSocketError() : 0;
|
||||
freeaddrinfo(addrwithport);
|
||||
if (err != 0) {
|
||||
return WouldBlock(err) ? NET_WAITING : SetSocketError("Failed to send from socket", err);
|
||||
if (!err) {
|
||||
retval = NET_SUCCESS; // it went to at least one interface's broadcast address, we'll call it success.
|
||||
} else {
|
||||
if (!WouldBlock(err)) {
|
||||
all_wouldblock = false;
|
||||
SetSocketError("Failed to send from socket", err); // so there's a clear error message, but keep going, maybe something else works out.
|
||||
}
|
||||
}
|
||||
SDL_assert(rc == buflen);
|
||||
return NET_SUCCESS;
|
||||
} else if (!addr && InterfacesReady()) { // iterate all interfaces for this broadcast.
|
||||
SDL_LockRWLockForReading(interface_rwlock);
|
||||
for (int i = 0; i < num_interfaces; i++) {
|
||||
const NET_Address *bc = interfaces[i].broadcast;
|
||||
if (!bc) { continue; }
|
||||
const struct addrinfo *ainfo = bc->ainfo;
|
||||
SDL_assert(ainfo != NULL);
|
||||
if (ainfo->ai_family != handle->family) { continue; }
|
||||
|
||||
struct addrinfo *addrwithport = MakeAddrInfoWithPort(bc, SOCK_DGRAM, port);
|
||||
if (!addrwithport) {
|
||||
continue; // oh well, lost UDP packet, I guess.
|
||||
}
|
||||
|
||||
//SDL_Log("Broadcasting on %s ...", bc->human_readable);
|
||||
const int rc = (int) sendto(handle->handle, buf, (size_t) buflen, 0, addrwithport->ai_addr, (SockLen) addrwithport->ai_addrlen);
|
||||
const int err = (rc == SOCKET_ERROR) ? LastSocketError() : 0;
|
||||
freeaddrinfo(addrwithport);
|
||||
if (!err) {
|
||||
retval = NET_SUCCESS; // it went to at least one interface's broadcast address, we'll call it success.
|
||||
} else {
|
||||
if (!WouldBlock(err)) {
|
||||
all_wouldblock = false;
|
||||
SetSocketError("Failed to send from socket", err); // so there's a clear error message, but keep going, maybe something else works out.
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_UnlockRWLock(interface_rwlock);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetError("Unsupported network family in destination address");
|
||||
return NET_FAILURE;
|
||||
if ((retval == NET_FAILURE) && all_wouldblock) {
|
||||
retval = NET_WAITING;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// see if any pending data can finally be sent, etc
|
||||
@@ -2043,8 +2426,8 @@ bool NET_SendDatagram(NET_DatagramSocket *sock, NET_Address *addr, Uint16 port,
|
||||
{
|
||||
if (!PumpDatagramSocket(sock)) { // try to flush any queued data to the socket now, before we handle more.
|
||||
return false;
|
||||
} else if (addr == NULL) {
|
||||
return SDL_InvalidParamError("address");
|
||||
} else if (!addr && !sock->allow_broadcast) {
|
||||
return SDL_SetError("Datagram socket was not created with broadcast support");
|
||||
} else if (buf == NULL) {
|
||||
return SDL_InvalidParamError("buf");
|
||||
} else if (buflen < 0) {
|
||||
@@ -2119,7 +2502,7 @@ bool NET_ReceiveDatagram(NET_DatagramSocket *sock, NET_Datagram **dgram)
|
||||
AddressStorage from;
|
||||
SockLen fromlen = sizeof (from);
|
||||
// WinSock's recvfrom wants a `char *` buffer instead of `void *`. The cast here is harmless on BSD Sockets.
|
||||
const int br = recvfrom(sock->handles[i].handle, (char *) sock->recv_buffer, sizeof (sock->recv_buffer), 0, (struct sockaddr *) &from, &fromlen);
|
||||
const int br = (int) recvfrom(sock->handles[i].handle, (char *) sock->recv_buffer, sizeof (sock->recv_buffer), 0, (struct sockaddr *) &from, &fromlen);
|
||||
if (br == SOCKET_ERROR) {
|
||||
const int err = LastSocketError();
|
||||
if (WouldBlock(err)) {
|
||||
@@ -2224,6 +2607,7 @@ void NET_DestroyDatagramSocket(NET_DatagramSocket *sock)
|
||||
|
||||
for (int i = 0; i < sock->num_handles; i++) {
|
||||
CloseSocketHandle(sock->handles[i].handle); // !!! FIXME: what does this do with non-blocking sockets? Release the descriptor but the kernel continues sending queued buffers behind the scenes?
|
||||
NET_UnrefAddress(sock->handles[i].broadcast);
|
||||
}
|
||||
for (int i = 0; i < ((int) SDL_arraysize(sock->latest_recv_addrs)); i++) {
|
||||
NET_UnrefAddress(sock->latest_recv_addrs[i]);
|
||||
|
||||
+1
@@ -32,4 +32,5 @@ _NET_WaitUntilInputAvailable
|
||||
_NET_WaitUntilResolved
|
||||
_NET_WaitUntilStreamSocketDrained
|
||||
_NET_WriteToStreamSocket
|
||||
_NET_GetAddressBytes
|
||||
# extra symbols go here (don't modify this line)
|
||||
|
||||
+1
@@ -33,6 +33,7 @@ SDL3_net_0.0.0 {
|
||||
NET_WaitUntilResolved;
|
||||
NET_WaitUntilStreamSocketDrained;
|
||||
NET_WriteToStreamSocket;
|
||||
NET_GetAddressBytes;
|
||||
# extra symbols go here (don't modify this line)
|
||||
local: *;
|
||||
};
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
SDL_net: A simple networking library for use with SDL
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
// we use a little bit of C++ for Haiku support, since the system frameworks
|
||||
// require it. Specifically, we need to get network interface change
|
||||
// notifications through BNetworkRoster.
|
||||
|
||||
#include <AppKit.h>
|
||||
#include <NetworkNotifications.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
extern "C" {
|
||||
extern bool NET_HAIKU_InitInterfaceChangeNotifications(SDL_AtomicInt *changed);
|
||||
extern void NET_HAIKU_QuitInterfaceChangeNotifications(void);
|
||||
}
|
||||
|
||||
class NET_InterfaceLooper : public BLooper
|
||||
{
|
||||
public:
|
||||
NET_InterfaceLooper(SDL_AtomicInt *_changed);
|
||||
virtual void MessageReceived(BMessage *message);
|
||||
virtual ~NET_InterfaceLooper() {}
|
||||
|
||||
private:
|
||||
SDL_AtomicInt *changed;
|
||||
};
|
||||
|
||||
|
||||
NET_InterfaceLooper::NET_InterfaceLooper(SDL_AtomicInt *_changed)
|
||||
: BLooper("NET_InterfaceLooper")
|
||||
, changed(_changed)
|
||||
{
|
||||
}
|
||||
|
||||
void NET_InterfaceLooper::MessageReceived(BMessage *message)
|
||||
{
|
||||
//SDL_Log("NET_InterfaceLooper::MessageReceived %d", (int) message->what);
|
||||
SDL_SetAtomicInt(changed, 1);
|
||||
BLooper::MessageReceived(message);
|
||||
}
|
||||
|
||||
|
||||
static NET_InterfaceLooper *looper = NULL;
|
||||
|
||||
bool NET_HAIKU_InitInterfaceChangeNotifications(SDL_AtomicInt *changed)
|
||||
{
|
||||
SDL_assert(!looper);
|
||||
looper = new NET_InterfaceLooper(changed);
|
||||
looper->Run();
|
||||
return start_watching_network(
|
||||
B_NETWORK_INTERFACE_ADDED | B_NETWORK_INTERFACE_REMOVED |
|
||||
B_NETWORK_INTERFACE_CHANGED | B_NETWORK_DEVICE_LINK_CHANGED, looper
|
||||
) == B_OK;
|
||||
}
|
||||
|
||||
void NET_HAIKU_QuitInterfaceChangeNotifications(void)
|
||||
{
|
||||
if (looper) {
|
||||
looper->PostMessage(B_QUIT_REQUESTED);
|
||||
looper = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
SDL_net: A simple networking library for use with SDL
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "SDL3_net/SDL_net.h"
|
||||
|
||||
// don't do anything. Sorry!
|
||||
int NET_Version(void) { return SDL_NET_VERSION; }
|
||||
bool NET_Init(void) { return SDL_Unsupported(); }
|
||||
void NET_Quit(void) {}
|
||||
NET_Address * NET_ResolveHostname(const char *host) { SDL_Unsupported(); return NULL; }
|
||||
NET_Status NET_WaitUntilResolved(NET_Address *address, Sint32 timeout) { SDL_Unsupported(); return NET_FAILURE; }
|
||||
NET_Status NET_GetAddressStatus(NET_Address *address) { SDL_Unsupported(); return NET_FAILURE; }
|
||||
const char * NET_GetAddressString(NET_Address *address) { SDL_Unsupported(); return NULL; }
|
||||
const void * NET_GetAddressBytes(NET_Address *address, int *num_bytes) { if (num_bytes) { *num_bytes = 0; } SDL_Unsupported(); return NULL; }
|
||||
NET_Address *NET_RefAddress(NET_Address *address) { SDL_Unsupported(); return NULL; }
|
||||
void NET_UnrefAddress(NET_Address *address) {}
|
||||
void NET_SimulateAddressResolutionLoss(int percent_loss) {}
|
||||
int NET_CompareAddresses(const NET_Address *a, const NET_Address *b) { return 0; }
|
||||
NET_Address **NET_GetLocalAddresses(int *num_addresses) { SDL_Unsupported(); return NULL; }
|
||||
void NET_FreeLocalAddresses(NET_Address **addresses) {}
|
||||
NET_StreamSocket * NET_CreateClient(NET_Address *address, Uint16 port, SDL_PropertiesID props) { SDL_Unsupported(); return NULL; }
|
||||
NET_Status NET_WaitUntilConnected(NET_StreamSocket *sock, Sint32 timeout) { SDL_Unsupported(); return NET_FAILURE; }
|
||||
NET_Server * NET_CreateServer(NET_Address *addr, Uint16 port, SDL_PropertiesID props) { SDL_Unsupported(); return NULL; }
|
||||
bool NET_AcceptClient(NET_Server *server, NET_StreamSocket **client_stream) { SDL_Unsupported(); return false; }
|
||||
void NET_DestroyServer(NET_Server *server) {}
|
||||
NET_Address * NET_GetStreamSocketAddress(NET_StreamSocket *sock) { SDL_Unsupported(); return NULL; }
|
||||
NET_Status NET_GetConnectionStatus(NET_StreamSocket *sock) { SDL_Unsupported(); return NET_FAILURE; }
|
||||
bool NET_WriteToStreamSocket(NET_StreamSocket *sock, const void *buf, int buflen) { SDL_Unsupported(); return false; }
|
||||
int NET_GetStreamSocketPendingWrites(NET_StreamSocket *sock) { SDL_Unsupported(); return -1; }
|
||||
int NET_WaitUntilStreamSocketDrained(NET_StreamSocket *sock, Sint32 timeout) { SDL_Unsupported(); return -1; }
|
||||
int NET_ReadFromStreamSocket(NET_StreamSocket *sock, void *buf, int buflen) { SDL_Unsupported(); return -1; }
|
||||
void NET_SimulateStreamPacketLoss(NET_StreamSocket *sock, int percent_loss) {}
|
||||
void NET_DestroyStreamSocket(NET_StreamSocket *sock) {}
|
||||
NET_DatagramSocket * NET_CreateDatagramSocket(NET_Address *addr, Uint16 port, SDL_PropertiesID props) { SDL_Unsupported(); return NULL; }
|
||||
bool NET_SendDatagram(NET_DatagramSocket *sock, NET_Address *address, Uint16 port, const void *buf, int buflen) { SDL_Unsupported(); return false; }
|
||||
bool NET_ReceiveDatagram(NET_DatagramSocket *sock, NET_Datagram **dgram) { SDL_Unsupported(); return false; }
|
||||
void NET_DestroyDatagram(NET_Datagram *dgram) {}
|
||||
void NET_SimulateDatagramPacketLoss(NET_DatagramSocket *sock, int percent_loss) {}
|
||||
void NET_DestroyDatagramSocket(NET_DatagramSocket *sock) {}
|
||||
int NET_WaitUntilInputAvailable(void **vsockets, int numsockets, Sint32 timeout) { SDL_Unsupported(); return -1; }
|
||||
|
||||
+4
-4
@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,0,0,0
|
||||
PRODUCTVERSION 3,0,0,0
|
||||
FILEVERSION 3,3,0,0
|
||||
PRODUCTVERSION 3,3,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS 0x40004L
|
||||
@@ -23,12 +23,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "\0"
|
||||
VALUE "FileDescription", "SDL_net\0"
|
||||
VALUE "FileVersion", "3, 0, 0, 0\0"
|
||||
VALUE "FileVersion", "3, 3, 0, 0\0"
|
||||
VALUE "InternalName", "SDL_net\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2026 Sam Lantinga\0"
|
||||
VALUE "OriginalFilename", "SDL3_net.dll\0"
|
||||
VALUE "ProductName", "Simple DirectMedia Layer\0"
|
||||
VALUE "ProductVersion", "3, 0, 0, 0\0"
|
||||
VALUE "ProductVersion", "3, 3, 0, 0\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
Vendored
+23
-29
@@ -1,5 +1,5 @@
|
||||
/* 7zArcIn.c -- 7z Input functions
|
||||
2023-09-07 : Igor Pavlov : Public domain */
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
@@ -289,9 +289,9 @@ static SRes WaitId(CSzData *sd, UInt32 id)
|
||||
}
|
||||
}
|
||||
|
||||
static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v)
|
||||
static SRes RememberBitVector(CSzData *sd, size_t numItems, const Byte **v)
|
||||
{
|
||||
const UInt32 numBytes = (numItems + 7) >> 3;
|
||||
const size_t numBytes = (numItems + 7) >> 3;
|
||||
if (numBytes > sd->Size)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
*v = sd->Data;
|
||||
@@ -317,11 +317,11 @@ static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems)
|
||||
return sum;
|
||||
}
|
||||
|
||||
static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc)
|
||||
static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, size_t numItems, Byte **v, ISzAllocPtr alloc)
|
||||
{
|
||||
Byte allAreDefined;
|
||||
Byte *v2;
|
||||
const UInt32 numBytes = (numItems + 7) >> 3;
|
||||
const size_t numBytes = (numItems + 7) >> 3;
|
||||
*v = NULL;
|
||||
SZ_READ_BYTE(allAreDefined)
|
||||
if (numBytes == 0)
|
||||
@@ -345,9 +345,9 @@ static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, I
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
|
||||
static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, size_t numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
|
||||
{
|
||||
UInt32 i;
|
||||
size_t i;
|
||||
CSzData sd;
|
||||
UInt32 *vals;
|
||||
const Byte *defs;
|
||||
@@ -366,7 +366,7 @@ static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *c
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
|
||||
static SRes ReadBitUi32s(CSzData *sd, size_t numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
|
||||
{
|
||||
SzBitUi32s_Free(crcs, alloc);
|
||||
RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc))
|
||||
@@ -1027,42 +1027,39 @@ static SRes SzReadAndDecodePackedStreams(
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
// (size & 1) == 0
|
||||
// (data) is aligned for 2-bytes
|
||||
static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets)
|
||||
{
|
||||
size_t pos = 0;
|
||||
const Byte *p, *lim;
|
||||
*offsets++ = 0;
|
||||
if (numFiles == 0)
|
||||
return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE;
|
||||
if (size < 2)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
if (data[size - 2] != 0 || data[size - 1] != 0)
|
||||
lim = data + size;
|
||||
if (*(const UInt16 *)(const void *)(lim - 2))
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
p = data;
|
||||
do
|
||||
{
|
||||
const Byte *p;
|
||||
if (pos == size)
|
||||
if (p >= lim)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
for (p = data + pos;
|
||||
#ifdef _WIN32
|
||||
*(const UInt16 *)(const void *)p != 0
|
||||
#else
|
||||
p[0] != 0 || p[1] != 0
|
||||
#endif
|
||||
; p += 2);
|
||||
pos = (size_t)(p - data) + 2;
|
||||
*offsets++ = (pos >> 1);
|
||||
for (; *(const UInt16 *)(const void *)p; p += 2);
|
||||
p += 2;
|
||||
*offsets++ = (size_t)(p - data) >> 1;
|
||||
}
|
||||
while (--numFiles);
|
||||
return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
|
||||
return (p == lim) ? SZ_OK : SZ_ERROR_ARCHIVE;
|
||||
}
|
||||
|
||||
static Z7_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num,
|
||||
static Z7_NO_INLINE SRes ReadTime(CSzBitUi64s *p, size_t num,
|
||||
CSzData *sd2,
|
||||
const CBuf *tempBufs, UInt32 numTempBufs,
|
||||
ISzAllocPtr alloc)
|
||||
{
|
||||
CSzData sd;
|
||||
UInt32 i;
|
||||
size_t i;
|
||||
CNtfsFileTime *vals;
|
||||
Byte *defs;
|
||||
Byte external;
|
||||
@@ -1215,6 +1212,7 @@ static SRes SzReadHeader2(
|
||||
{
|
||||
namesSize = (size_t)size - 1;
|
||||
namesData = sd->Data;
|
||||
SKIP_DATA(sd, namesSize)
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1226,15 +1224,11 @@ static SRes SzReadHeader2(
|
||||
namesSize = (tempBufs)[index].size;
|
||||
}
|
||||
|
||||
if ((namesSize & 1) != 0)
|
||||
if (namesSize & 1)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain)
|
||||
MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain)
|
||||
RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets))
|
||||
if (external == 0)
|
||||
{
|
||||
SKIP_DATA(sd, namesSize)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case k7zIdEmptyStream:
|
||||
|
||||
Vendored
+1
-2
@@ -1,12 +1,11 @@
|
||||
/* 7zFile.h -- File IO
|
||||
2023-03-05 : Igor Pavlov : Public domain */
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef ZIP7_INC_FILE_H
|
||||
#define ZIP7_INC_FILE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#define USE_WINDOWS_FILE
|
||||
// #include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
|
||||
Vendored
+4
-2
@@ -1,5 +1,5 @@
|
||||
/* 7zTypes.h -- Basic types
|
||||
2024-01-24 : Igor Pavlov : Public domain */
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef ZIP7_7Z_TYPES_H
|
||||
#define ZIP7_7Z_TYPES_H
|
||||
@@ -46,8 +46,9 @@ typedef int SRes;
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define MY_ALIGN_IN_STRUCT(n) __declspec(align(n))
|
||||
#if _MSC_VER > 1200
|
||||
#define MY_ALIGN(n) __declspec(align(n))
|
||||
#define MY_ALIGN(n) MY_ALIGN_IN_STRUCT(n)
|
||||
#else
|
||||
#define MY_ALIGN(n)
|
||||
#endif
|
||||
@@ -58,6 +59,7 @@ typedef int SRes;
|
||||
#define MY_ALIGN(n) alignas(n)
|
||||
*/
|
||||
#define MY_ALIGN(n) __attribute__ ((aligned(n)))
|
||||
#define MY_ALIGN_IN_STRUCT(n) MY_ALIGN(n)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
Vendored
+4
-4
@@ -1,7 +1,7 @@
|
||||
#define MY_VER_MAJOR 25
|
||||
#define MY_VER_MAJOR 26
|
||||
#define MY_VER_MINOR 1
|
||||
#define MY_VER_BUILD 0
|
||||
#define MY_VERSION_NUMBERS "25.01"
|
||||
#define MY_VERSION_NUMBERS "26.01"
|
||||
#define MY_VERSION MY_VERSION_NUMBERS
|
||||
|
||||
#ifdef MY_CPU_NAME
|
||||
@@ -10,12 +10,12 @@
|
||||
#define MY_VERSION_CPU MY_VERSION
|
||||
#endif
|
||||
|
||||
#define MY_DATE "2025-08-03"
|
||||
#define MY_DATE "2026-04-27"
|
||||
#undef MY_COPYRIGHT
|
||||
#undef MY_VERSION_COPYRIGHT_DATE
|
||||
#define MY_AUTHOR_NAME "Igor Pavlov"
|
||||
#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
|
||||
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2025 Igor Pavlov"
|
||||
#define MY_COPYRIGHT_CR "Copyright (c) 1999-2026 Igor Pavlov"
|
||||
|
||||
#ifdef USE_COPYRIGHT_CR
|
||||
#define MY_COPYRIGHT MY_COPYRIGHT_CR
|
||||
|
||||
Vendored
+8
-2
@@ -1,11 +1,17 @@
|
||||
/* 7zWindows.h -- StdAfx
|
||||
2023-04-02 : Igor Pavlov : Public domain */
|
||||
/* 7zWindows.h -- Windows.h and related code
|
||||
Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef ZIP7_INC_7Z_WINDOWS_H
|
||||
#define ZIP7_INC_7Z_WINDOWS_H
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1950 && !defined(__clang__) // VS2026
|
||||
// <Windows.h> and some another windows files need that option
|
||||
// VS2026: wtypesbase.h: warning C4865: 'tagCLSCTX': the underlying type will change from 'int' to 'unsigned int' when '/Zc:enumTypes' is specified on the command line
|
||||
#pragma warning(disable : 4865)
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
#endif
|
||||
|
||||
Vendored
+1
-1
@@ -106,7 +106,7 @@ DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
|
||||
endif
|
||||
|
||||
|
||||
LIB2 = -lOle32 -loleaut32 -luuid -ladvapi32 -lUser32 -lShell32
|
||||
LIB2 = -lole32 -loleaut32 -luuid -ladvapi32 -luser32 -lshell32
|
||||
|
||||
CFLAGS_EXTRA = -DUNICODE -D_UNICODE
|
||||
# -Wno-delete-non-virtual-dtor
|
||||
|
||||
Vendored
+208
-39
@@ -1,5 +1,5 @@
|
||||
/* Alloc.c -- Memory allocation functions
|
||||
2024-02-18 : Igor Pavlov : Public domain */
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
#endif
|
||||
|
||||
// #define SZ_ALLOC_DEBUG
|
||||
/* #define SZ_ALLOC_DEBUG */
|
||||
|
||||
/* use SZ_ALLOC_DEBUG to debug alloc/free operations */
|
||||
#ifdef SZ_ALLOC_DEBUG
|
||||
|
||||
@@ -34,9 +32,10 @@
|
||||
static int g_allocCount = 0;
|
||||
#ifdef _WIN32
|
||||
static int g_allocCountMid = 0;
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
static int g_allocCountBig = 0;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define CONVERT_INT_TO_STR(charType, tempSize) \
|
||||
char temp[tempSize]; unsigned i = 0; \
|
||||
@@ -140,8 +139,10 @@ static void PrintAddr(void *p)
|
||||
#else
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
#define PRINT_ALLOC(name, cnt, size, ptr)
|
||||
#endif
|
||||
#endif
|
||||
#define PRINT_FREE(name, cnt, ptr)
|
||||
#define Print(s)
|
||||
#define PrintLn()
|
||||
@@ -245,6 +246,7 @@ void MidFree(void *address)
|
||||
}
|
||||
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
// #pragma message("Z7_LARGE_PAGES")
|
||||
|
||||
#ifdef MEM_LARGE_PAGES
|
||||
#define MY_MEM_LARGE_PAGES MEM_LARGE_PAGES
|
||||
@@ -253,32 +255,14 @@ void MidFree(void *address)
|
||||
#endif
|
||||
|
||||
extern
|
||||
SIZE_T g_LargePageSize;
|
||||
SIZE_T g_LargePageSize = 0;
|
||||
typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID);
|
||||
|
||||
void SetLargePageSize(void)
|
||||
{
|
||||
SIZE_T size;
|
||||
#ifdef Z7_USE_DYN_GetLargePageMinimum
|
||||
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
|
||||
const
|
||||
Func_GetLargePageMinimum fn =
|
||||
(Func_GetLargePageMinimum) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetLargePageMinimum");
|
||||
if (!fn)
|
||||
return;
|
||||
size = fn();
|
||||
#else
|
||||
size = GetLargePageMinimum();
|
||||
#endif
|
||||
if (size == 0 || (size & (size - 1)) != 0)
|
||||
return;
|
||||
g_LargePageSize = size;
|
||||
}
|
||||
|
||||
#endif // Z7_LARGE_PAGES
|
||||
size_t g_LargePageSize;
|
||||
size_t g_LargePageSize = 0;
|
||||
extern
|
||||
size_t g_LargePageThresholdMin;
|
||||
size_t g_LargePageThresholdMin = 0;
|
||||
extern
|
||||
UInt32 g_LargePageFlags;
|
||||
UInt32 g_LargePageFlags = 0;
|
||||
|
||||
void *BigAlloc(size_t size)
|
||||
{
|
||||
@@ -289,12 +273,10 @@ void *BigAlloc(size_t size)
|
||||
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
{
|
||||
SIZE_T ps = g_LargePageSize;
|
||||
if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))
|
||||
const size_t ps = g_LargePageSize - 1;
|
||||
if (ps < (1u << 30) && size > g_LargePageThresholdMin)
|
||||
{
|
||||
size_t size2;
|
||||
ps--;
|
||||
size2 = (size + ps) & ~ps;
|
||||
const size_t size2 = (size + ps) & ~ps;
|
||||
if (size2 >= size)
|
||||
{
|
||||
void *p = VirtualAlloc(NULL, size2, MEM_COMMIT | MY_MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||
@@ -303,6 +285,8 @@ void *BigAlloc(size_t size)
|
||||
PRINT_ALLOC("Alloc-BM ", g_allocCountMid, size2, p)
|
||||
return p;
|
||||
}
|
||||
if (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_FAIL_STOP)
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,6 +301,7 @@ void BigFree(void *address)
|
||||
MidFree(address);
|
||||
}
|
||||
|
||||
#endif // Z7_LARGE_PAGES
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
@@ -327,9 +312,12 @@ const ISzAlloc g_Alloc = { SzAlloc, SzFree };
|
||||
#ifdef _WIN32
|
||||
static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MidAlloc(size); }
|
||||
static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MidFree(address); }
|
||||
const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
|
||||
#endif
|
||||
|
||||
#if defined(Z7_LARGE_PAGES)
|
||||
static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return BigAlloc(size); }
|
||||
static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) BigFree(address); }
|
||||
const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
|
||||
const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
|
||||
#endif
|
||||
|
||||
@@ -371,10 +359,16 @@ typedef
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) \
|
||||
&& (defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) \
|
||||
|| defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L))
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h> // for _POSIX_ADVISORY_INFO : for some linux
|
||||
#if (defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) \
|
||||
|| defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) \
|
||||
|| defined(_POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO >= 200112L) \
|
||||
|| defined(__APPLE__) \
|
||||
/* || defined(__linux__) */)
|
||||
#define USE_posix_memalign
|
||||
// #pragma message("USE_posix_memalign")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef USE_posix_memalign
|
||||
@@ -488,6 +482,181 @@ static void SzAlignedFree(ISzAllocPtr pp, void *address)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
|
||||
#if 0 // 1 for debug
|
||||
#include <stdio.h>
|
||||
#include <string.h> // for strerror()
|
||||
#define PRF(x) x
|
||||
#else
|
||||
#define PRF(x)
|
||||
#endif
|
||||
|
||||
#ifdef USE_posix_memalign
|
||||
/* madvise():
|
||||
glibc <= 2.19 : _BSD_SOURCE
|
||||
glibc > 2.19 : _DEFAULT_SOURCE
|
||||
*/
|
||||
/* && (defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)) */
|
||||
#if 1 && !defined(Z7_NO_MADVISE) && \
|
||||
(defined(__linux__) || defined(__unix__) || defined(__APPLE__))
|
||||
#include <sys/mman.h> // for madvise
|
||||
// #pragma message("sys/mman.h")
|
||||
#if (defined(MADV_HUGEPAGE) && defined(MADV_NOHUGEPAGE))
|
||||
#define Z7_USE_BIG_ALLOC_MADVISE
|
||||
// #pragma message("Z7_USE_BIG_ALLOC_MADVISE")
|
||||
#endif
|
||||
#endif
|
||||
#endif // USE_posix_memalign
|
||||
|
||||
#ifdef Z7_USE_BIG_ALLOC_MADVISE
|
||||
#define LARGE_PAGE_SIZE_DEFAULT (1 << 21)
|
||||
#else
|
||||
#define LARGE_PAGE_SIZE_DEFAULT 0
|
||||
#endif
|
||||
|
||||
extern
|
||||
size_t g_LargePageSize;
|
||||
size_t g_LargePageSize = LARGE_PAGE_SIZE_DEFAULT;
|
||||
extern
|
||||
size_t g_LargePageThresholdMin;
|
||||
size_t g_LargePageThresholdMin = LARGE_PAGE_SIZE_DEFAULT / 2;
|
||||
extern
|
||||
UInt32 g_LargePageFlags;
|
||||
UInt32 g_LargePageFlags = 0;
|
||||
|
||||
void *BigAlloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
#ifdef USE_posix_memalign
|
||||
{
|
||||
const size_t pageSize = g_LargePageSize;
|
||||
void *buf = NULL; // on Linux (and other systems), posix_memalign() does not modify memptr on failure (POSIX.1-2008 TC2).
|
||||
PRF(printf("\nBigAlloc 0x%08x=%5uMB", (unsigned)(size), (unsigned)(size >> 20));)
|
||||
if (pageSize && size > g_LargePageThresholdMin)
|
||||
{
|
||||
int res;
|
||||
const size_t mask = pageSize - 1;
|
||||
/* we can allocate aligned size, so data at the end of buffer also will use huge page
|
||||
if (size2 for madvise() is not aligned for huge page size)
|
||||
{ Last data block will use small pages. It reduces memory allocation,
|
||||
but last data block with small pages can work slower.
|
||||
It's useful, if we have very large HUGE_PAGE: 32MB or 512MB. }
|
||||
*/
|
||||
size_t size2 = (size + mask) & ~mask;
|
||||
if (size2 < size || (size & mask) <= g_LargePageThresholdMin)
|
||||
size2 = size;
|
||||
res = posix_memalign(&buf, pageSize, size2);
|
||||
PRF(printf(" posix_memalign size=0x%08x=%5uMB align=%u",
|
||||
(unsigned)(size2), (unsigned)(size2 >> 20), (unsigned)pageSize);)
|
||||
PRF(printf(" buf=%p", (void *)buf);)
|
||||
if (res == 0)
|
||||
{
|
||||
#ifdef Z7_USE_BIG_ALLOC_MADVISE
|
||||
if ((g_LargePageFlags & Z7_LARGE_PAGES_FLAG_NO_MADVISE) == 0)
|
||||
{
|
||||
// Advise the kernel to use huge pages for this memory range
|
||||
// MADV_HUGEPAGE / MADV_NOHUGEPAGE : since Linux 2.6.38
|
||||
// madvise() only operates on whole pages, therefore addr must be page-aligned (4KB/8KB/16KB/64KB).
|
||||
// The value of size is rounded up to a multiple of page size.
|
||||
PRF(printf(" madvise g_LargePageFlags=%x", (unsigned)g_LargePageFlags);)
|
||||
res = madvise(buf, size2, (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_NO_HUGEPAGE) ? MADV_NOHUGEPAGE : MADV_HUGEPAGE);
|
||||
if (res)
|
||||
{
|
||||
PRF(printf("\nERROR res=%d, errno=%d=%s\n", res, (int)errno, strerror(errno));)
|
||||
if (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_FAIL_STOP)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // Z7_USE_BIG_ALLOC_MADVISE
|
||||
PRF(printf("\n");)
|
||||
return buf;
|
||||
}
|
||||
PRF(printf("\nERROR res=%d=%s\n", res, strerror(res));)
|
||||
if (g_LargePageFlags & Z7_LARGE_PAGES_FLAG_FAIL_STOP)
|
||||
return NULL;
|
||||
// (res == ENOMEM) "Out of memory" is possible, if pageSize is too big.
|
||||
// so we do second attempt with smaller alignment
|
||||
}
|
||||
}
|
||||
#endif // !USE_posix_memalign
|
||||
PRF(printf(" z7_AlignedAlloc size=0x%08x=%5uMB\n", (unsigned)(size), (unsigned)(size >> 20));)
|
||||
return z7_AlignedAlloc(size);
|
||||
}
|
||||
|
||||
|
||||
void BigFree(void *address)
|
||||
{
|
||||
z7_AlignedFree(address);
|
||||
}
|
||||
#endif // Z7_LARGE_PAGES
|
||||
#endif // !_WIN32
|
||||
|
||||
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
void z7_LargePage_Set(UInt32 flags, size_t pageSize, size_t threshold)
|
||||
{
|
||||
g_LargePageFlags = flags;
|
||||
|
||||
#ifdef _WIN32
|
||||
if ((flags & Z7_LARGE_PAGES_FLAG_USE_HUGEPAGE) == 0)
|
||||
{
|
||||
g_LargePageSize = 0;
|
||||
g_LargePageThresholdMin = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_PAGE_SIZE) == 0)
|
||||
{
|
||||
#ifdef Z7_USE_DYN_GetLargePageMinimum
|
||||
Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
|
||||
typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID);
|
||||
const
|
||||
Func_GetLargePageMinimum fn =
|
||||
(Func_GetLargePageMinimum) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetLargePageMinimum");
|
||||
if (fn)
|
||||
pageSize = fn();
|
||||
else
|
||||
pageSize = 0;
|
||||
#else
|
||||
pageSize = GetLargePageMinimum();
|
||||
#endif
|
||||
if (pageSize & (pageSize - 1))
|
||||
pageSize = 0;
|
||||
}
|
||||
g_LargePageSize = pageSize;
|
||||
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_THRESHOLD) == 0)
|
||||
threshold = pageSize / 2;
|
||||
g_LargePageThresholdMin = threshold;
|
||||
}
|
||||
|
||||
#else // !_WIN32
|
||||
|
||||
if (flags & Z7_LARGE_PAGES_FLAG_NO_PAGECODE)
|
||||
{
|
||||
g_LargePageSize = 0;
|
||||
g_LargePageThresholdMin = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_PAGE_SIZE) == 0)
|
||||
pageSize = LARGE_PAGE_SIZE_DEFAULT;
|
||||
g_LargePageSize = pageSize;
|
||||
if ((flags & Z7_LARGE_PAGES_FLAG_DIRECT_THRESHOLD) == 0)
|
||||
threshold = pageSize / 2;
|
||||
g_LargePageThresholdMin = threshold;
|
||||
}
|
||||
// PRF(printf("\ng_LargePageSize=%x g_LargePageThresholdMin = %x g_LargePageFlags = %x", (unsigned)g_LargePageSize, (unsigned)g_LargePageThresholdMin, (unsigned)g_LargePageFlags);)
|
||||
#endif // !_WIN32
|
||||
}
|
||||
#endif // Z7_LARGE_PAGES
|
||||
|
||||
const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };
|
||||
|
||||
|
||||
Vendored
+27
-27
@@ -1,5 +1,5 @@
|
||||
/* Alloc.h -- Memory allocation functions
|
||||
2024-01-22 : Igor Pavlov : Public domain */
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef ZIP7_INC_ALLOC_H
|
||||
#define ZIP7_INC_ALLOC_H
|
||||
@@ -25,40 +25,40 @@ void *MyRealloc(void *address, size_t size);
|
||||
void *z7_AlignedAlloc(size_t size);
|
||||
void z7_AlignedFree(void *p);
|
||||
|
||||
extern const ISzAlloc g_Alloc;
|
||||
extern const ISzAlloc g_AlignedAlloc;
|
||||
|
||||
#ifdef _WIN32
|
||||
void *MidAlloc(size_t size);
|
||||
void MidFree(void *address);
|
||||
extern const ISzAlloc g_MidAlloc;
|
||||
#else
|
||||
#define MidAlloc(size) z7_AlignedAlloc(size)
|
||||
#define MidFree(address) z7_AlignedFree(address)
|
||||
#define g_MidAlloc g_AlignedAlloc
|
||||
#endif
|
||||
|
||||
#ifdef Z7_LARGE_PAGES
|
||||
void SetLargePageSize(void);
|
||||
#endif
|
||||
|
||||
void *MidAlloc(size_t size);
|
||||
void MidFree(void *address);
|
||||
void *BigAlloc(size_t size);
|
||||
void BigFree(void *address);
|
||||
|
||||
/* #define Z7_BIG_ALLOC_IS_ZERO_FILLED */
|
||||
#define Z7_LARGE_PAGES_FLAG_USE_HUGEPAGE (1 << 0) // PAGE_ALIGNED / MADV_HUGEPAGE
|
||||
#define Z7_LARGE_PAGES_FLAG_NO_PAGECODE (1 << 1) // no PAGE_ALIGNED / no madvise
|
||||
#define Z7_LARGE_PAGES_FLAG_NO_MADVISE (1 << 2) // PAGE_ALIGNED / no madvise : for THP=always
|
||||
#define Z7_LARGE_PAGES_FLAG_NO_HUGEPAGE (1 << 3) // PAGE_ALIGNED / MADV_NOHUGEPAGE
|
||||
#define Z7_LARGE_PAGES_FLAG_FAIL_STOP (1 << 15) // for benchmarks
|
||||
#define Z7_LARGE_PAGES_FLAG_DIRECT_PAGE_SIZE (1 << 16)
|
||||
#define Z7_LARGE_PAGES_FLAG_DIRECT_THRESHOLD (1 << 17)
|
||||
|
||||
void z7_LargePage_Set(UInt32 flags, size_t pageSize, size_t threshold);
|
||||
|
||||
void *BigAlloc(size_t size);
|
||||
void BigFree(void *address);
|
||||
extern const ISzAlloc g_BigAlloc;
|
||||
#else
|
||||
|
||||
#define MidAlloc(size) z7_AlignedAlloc(size)
|
||||
#define MidFree(address) z7_AlignedFree(address)
|
||||
#define BigAlloc(size) z7_AlignedAlloc(size)
|
||||
#define BigFree(address) z7_AlignedFree(address)
|
||||
|
||||
#define BigAlloc(size) MidAlloc(size)
|
||||
#define BigFree(address) MidFree(address)
|
||||
#define g_BigAlloc g_MidAlloc
|
||||
#endif
|
||||
|
||||
extern const ISzAlloc g_Alloc;
|
||||
|
||||
#ifdef _WIN32
|
||||
extern const ISzAlloc g_BigAlloc;
|
||||
extern const ISzAlloc g_MidAlloc;
|
||||
#else
|
||||
#define g_BigAlloc g_AlignedAlloc
|
||||
#define g_MidAlloc g_AlignedAlloc
|
||||
#endif
|
||||
|
||||
extern const ISzAlloc g_AlignedAlloc;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
Vendored
+7
-1
@@ -54,6 +54,12 @@
|
||||
#pragma GCC diagnostic ignored "-Wexcess-padding"
|
||||
#endif
|
||||
|
||||
#if defined(Z7_APPLE_CLANG_VERSION) && __clang_major__ >= 21
|
||||
// warning: function MyAlloc might be an allocator wrapper
|
||||
// clang in xcode: clang 21.0.0
|
||||
#pragma GCC diagnostic ignored "-Wallocator-wrappers"
|
||||
#endif
|
||||
|
||||
#if __clang_major__ >= 16
|
||||
#pragma GCC diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
#endif
|
||||
@@ -72,7 +78,7 @@
|
||||
|
||||
#endif // __clang__
|
||||
|
||||
#if defined(_WIN32) && defined(__clang__) && __clang_major__ >= 16
|
||||
#if defined(__clang__) && __clang_major__ >= 16
|
||||
// #pragma GCC diagnostic ignored "-Wcast-function-type-strict"
|
||||
#define Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION \
|
||||
_Pragma("GCC diagnostic ignored \"-Wcast-function-type-strict\"")
|
||||
|
||||
Vendored
+2
-2
@@ -859,7 +859,7 @@ BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
|
||||
|
||||
#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216)
|
||||
#define Z7_GETAUXV_AVAILABLE
|
||||
#else
|
||||
#elif !defined(__QNXNTO__)
|
||||
// #pragma message("=== is not NEW GLIBC === ")
|
||||
#if defined __has_include
|
||||
#if __has_include (<sys/auxv.h>)
|
||||
@@ -877,7 +877,7 @@ BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
|
||||
|
||||
#ifdef USE_HWCAP
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
static unsigned long MY_getauxval(int aux)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
Vendored
+20
-2
@@ -31,7 +31,12 @@ MY_CPU_64BIT means that processor can work with 64-bit registers.
|
||||
#define MY_CPU_NAME "x32"
|
||||
#define MY_CPU_SIZEOF_POINTER 4
|
||||
#else
|
||||
#define MY_CPU_NAME "x64"
|
||||
#if defined(__APX_EGPR__) || defined(__EGPR__)
|
||||
#define MY_CPU_NAME "x64-apx"
|
||||
#define MY_CPU_AMD64_APX
|
||||
#else
|
||||
#define MY_CPU_NAME "x64"
|
||||
#endif
|
||||
#define MY_CPU_SIZEOF_POINTER 8
|
||||
#endif
|
||||
#define MY_CPU_64BIT
|
||||
@@ -249,11 +254,12 @@ MY_CPU_64BIT means that processor can work with 64-bit registers.
|
||||
#endif
|
||||
|
||||
|
||||
// _LITTLE_ENDIAN macro can be defined for big-endian platform with some compilers
|
||||
|
||||
#if defined(MY_CPU_X86_OR_AMD64) \
|
||||
|| defined(MY_CPU_ARM_LE) \
|
||||
|| defined(MY_CPU_ARM64_LE) \
|
||||
|| defined(MY_CPU_IA64_LE) \
|
||||
|| defined(_LITTLE_ENDIAN) \
|
||||
|| defined(__LITTLE_ENDIAN__) \
|
||||
|| defined(__ARMEL__) \
|
||||
|| defined(__THUMBEL__) \
|
||||
@@ -596,8 +602,20 @@ problem-4 : performace:
|
||||
#define SetBe32a(p, v) { *(UInt32 *)(void *)(p) = (v); }
|
||||
#define SetBe16a(p, v) { *(UInt16 *)(void *)(p) = (v); }
|
||||
|
||||
// gcc and clang for powerpc can transform load byte access to load reverse word access.
|
||||
// sp we can use byte access instead of word access. Z7_BSWAP64 cab be slow
|
||||
#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_64BIT)
|
||||
#define GetUi64a(p) Z7_BSWAP64 (*(const UInt64 *)(const void *)(p))
|
||||
#else
|
||||
#define GetUi64a(p) GetUi64(p)
|
||||
#endif
|
||||
|
||||
#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED)
|
||||
#define GetUi32a(p) Z7_BSWAP32 (*(const UInt32 *)(const void *)(p))
|
||||
#else
|
||||
#define GetUi32a(p) GetUi32(p)
|
||||
#endif
|
||||
|
||||
#define GetUi16a(p) GetUi16(p)
|
||||
#define SetUi32a(p, v) SetUi32(p, v)
|
||||
#define SetUi16a(p, v) SetUi16(p, v)
|
||||
|
||||
Vendored
+2
-3
@@ -2351,10 +2351,9 @@ static void LzmaEnc_Construct(CLzmaEnc *p)
|
||||
|
||||
CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc)
|
||||
{
|
||||
void *p;
|
||||
p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc));
|
||||
CLzmaEncHandle p = (CLzmaEncHandle)ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc));
|
||||
if (p)
|
||||
LzmaEnc_Construct((CLzmaEnc *)p);
|
||||
LzmaEnc_Construct(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+7
-7
@@ -1,5 +1,5 @@
|
||||
/* Precomp.h -- precompilation file
|
||||
2024-01-25 : Igor Pavlov : Public domain */
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef ZIP7_INC_PRECOMP_H
|
||||
#define ZIP7_INC_PRECOMP_H
|
||||
@@ -40,18 +40,18 @@
|
||||
#endif
|
||||
*/
|
||||
|
||||
#ifndef Z7_LARGE_PAGES
|
||||
#if !defined(Z7_NO_LARGE_PAGES) && !defined(UNDER_CE)
|
||||
#define Z7_LARGE_PAGES 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
this "Precomp.h" file must be included before <windows.h>,
|
||||
if we want to define _WIN32_WINNT before <windows.h>.
|
||||
*/
|
||||
|
||||
#ifndef Z7_LARGE_PAGES
|
||||
#ifndef Z7_NO_LARGE_PAGES
|
||||
#define Z7_LARGE_PAGES 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef Z7_LONG_PATH
|
||||
#ifndef Z7_NO_LONG_PATH
|
||||
#define Z7_LONG_PATH 1
|
||||
|
||||
Vendored
+1
-1
@@ -1,2 +1,2 @@
|
||||
# LZMA SDK v25.01
|
||||
# LZMA SDK v26.01
|
||||
Downloaded from https://www.7-zip.org/sdk.html
|
||||
Vendored
+18
-4
@@ -153,6 +153,17 @@ static void PrintProcess_Info()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* if we send (stackSize=0) to CreateThread(), it will
|
||||
use default value PE::SizeOfStackReserve from exe file.
|
||||
PE::SizeOfStackReserve == 1 MiB in exe file with default linker options.
|
||||
Windows aligns specified value to the next 64 KB range. */
|
||||
static const unsigned k_StackSize_ReserveSize =
|
||||
#ifdef UNDER_CE
|
||||
1 << 17;
|
||||
#else
|
||||
1 << 20;
|
||||
#endif
|
||||
|
||||
WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
|
||||
{
|
||||
/* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
|
||||
@@ -160,12 +171,15 @@ WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
|
||||
#ifdef USE_THREADS_CreateThread
|
||||
|
||||
DWORD threadId;
|
||||
*p = CreateThread(NULL, 0, func, param, 0, &threadId);
|
||||
*p = CreateThread(NULL, k_StackSize_ReserveSize, func, param, STACK_SIZE_PARAM_IS_A_RESERVATION, &threadId);
|
||||
|
||||
#else
|
||||
|
||||
#define CALL_beginthreadex(func2, param2, flags, threadIdPtr) \
|
||||
((HANDLE)(_beginthreadex(NULL, k_StackSize_ReserveSize, func2, param2, (flags) | STACK_SIZE_PARAM_IS_A_RESERVATION, threadIdPtr)))
|
||||
|
||||
unsigned threadId;
|
||||
*p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId));
|
||||
*p = CALL_beginthreadex(func, param, 0, &threadId);
|
||||
|
||||
#if 0 // 1 : for debug
|
||||
{
|
||||
@@ -223,7 +237,7 @@ WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param
|
||||
HANDLE h;
|
||||
WRes wres;
|
||||
unsigned threadId;
|
||||
h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
|
||||
h = CALL_beginthreadex(func, param, CREATE_SUSPENDED, &threadId);
|
||||
*p = h;
|
||||
wres = HandleToWRes(h);
|
||||
if (h)
|
||||
@@ -272,7 +286,7 @@ WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, u
|
||||
HANDLE h;
|
||||
WRes wres;
|
||||
unsigned threadId;
|
||||
h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
|
||||
h = CALL_beginthreadex(func, param, CREATE_SUSPENDED, &threadId);
|
||||
*p = h;
|
||||
wres = HandleToWRes(h);
|
||||
if (h)
|
||||
|
||||
+345
-32
@@ -1,15 +1,16 @@
|
||||
/* 7zMain.c - Test application for 7z Decoder
|
||||
2024-02-28 : Igor Pavlov : Public domain */
|
||||
/* 7zMain.c - 7z archive decoding program
|
||||
: Igor Pavlov : Public domain */
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../../7zFile.h"
|
||||
|
||||
#ifndef USE_WINDOWS_FILE
|
||||
/* for mkdir */
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#include <direct.h> // for _mkdir()
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
@@ -23,7 +24,14 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "../../7zFile.h"
|
||||
#ifdef _WIN32
|
||||
// for _isatty()
|
||||
#include "../../7zWindows.h"
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h> // for isatty()
|
||||
#endif
|
||||
|
||||
#include "../../7z.h"
|
||||
#include "../../7zAlloc.h"
|
||||
#include "../../7zBuf.h"
|
||||
@@ -44,6 +52,25 @@ static void Print(const char *s)
|
||||
}
|
||||
|
||||
|
||||
static Z7_FORCE_INLINE BoolInt MY_IS_TERMINAL(FILE *x)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const int fd = _fileno(x);
|
||||
HANDLE h;
|
||||
DWORD st;
|
||||
if (fd < 0)
|
||||
return False;
|
||||
if (!_isatty(fd))
|
||||
return False;
|
||||
h = (HANDLE)(_get_osfhandle(fd));
|
||||
if (h == NULL || h == INVALID_HANDLE_VALUE)
|
||||
return False;
|
||||
return GetConsoleMode(h, &st) != 0;
|
||||
#else
|
||||
return isatty(fileno(x)) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int Buf_EnsureSize(CBuf *dest, size_t size)
|
||||
{
|
||||
if (dest->size >= size)
|
||||
@@ -196,6 +223,206 @@ static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static Z7_FORCE_INLINE unsigned MyCharLower_Ascii(unsigned c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return (unsigned)(c + 0x20);
|
||||
return c;
|
||||
}
|
||||
|
||||
static Z7_FORCE_INLINE
|
||||
BoolInt IsString1PrefixedByString2_NoCase_Ascii(const UInt16 *s1, const char *s2)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
wchar_t c1;
|
||||
const char c2 = *s2++; if (c2 == 0) return True;
|
||||
c1 = *s1++;
|
||||
if (c1 != (unsigned char)c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii((unsigned char)c2))
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const unsigned g_ReservedWithNum_Index = 4;
|
||||
static const char * const g_ReservedNames[] =
|
||||
{
|
||||
"CON", "PRN", "AUX", "NUL",
|
||||
"COM", "LPT"
|
||||
};
|
||||
|
||||
static Z7_FORCE_INLINE
|
||||
BoolInt IsReservedFsName(const UInt16 *name, size_t sLen)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < Z7_ARRAY_SIZE(g_ReservedNames); i++)
|
||||
{
|
||||
const char *reservedName = g_ReservedNames[i];
|
||||
size_t len = strlen(reservedName);
|
||||
if (sLen < len)
|
||||
continue;
|
||||
if (!IsString1PrefixedByString2_NoCase_Ascii(name, reservedName))
|
||||
continue;
|
||||
if (i >= g_ReservedWithNum_Index)
|
||||
{
|
||||
if ((unsigned)((unsigned)name[len] - (unsigned)'0') > 9)
|
||||
continue;
|
||||
len++;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
unsigned c;
|
||||
if (len >= sLen)
|
||||
return True;
|
||||
c = name[len++];
|
||||
if (c == 0 || c == '.')
|
||||
return True;
|
||||
if (c != ' ')
|
||||
break;
|
||||
}
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
static Z7_FORCE_INLINE
|
||||
void Correct_FileName_for_FS(UInt16 *s, size_t size)
|
||||
{
|
||||
while (size)
|
||||
{
|
||||
const unsigned c = s[--size];
|
||||
if (c != '.' && c != ' ')
|
||||
break;
|
||||
s[size] = '_';
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
// in: (s) uses WCHAR_PATH_SEPARATOR path separators
|
||||
static Z7_FORCE_INLINE
|
||||
void NormalizesPathParts_and_Dots(UInt16 *dest, const UInt16 *s, BoolInt isDir)
|
||||
{
|
||||
UInt16 * const destStart = dest;
|
||||
size_t len;
|
||||
|
||||
// remove absolute path prefixes
|
||||
for (; *s == WCHAR_PATH_SEPARATOR; s++)
|
||||
{}
|
||||
|
||||
len = 0;
|
||||
for (;;)
|
||||
{
|
||||
const unsigned c = s[len];
|
||||
if (c != 0 && c != WCHAR_PATH_SEPARATOR)
|
||||
{
|
||||
len++;
|
||||
continue;
|
||||
}
|
||||
{
|
||||
if (len == 0
|
||||
|| (len == 1 && s[len - 1] == '.')
|
||||
|| (len == 2 && s[len - 1] == '.' && s[len - 2] == '.'))
|
||||
{
|
||||
if (c == 0)
|
||||
{
|
||||
if (!isDir)
|
||||
{
|
||||
*dest++ = '_';
|
||||
// if (len == 2) *dest++ = '_'; // for ".." -> "__"
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (IsReservedFsName(s, len))
|
||||
*dest++ = '_';
|
||||
#endif
|
||||
memcpy(dest, s, sizeof(s[0]) * len);
|
||||
#ifdef _WIN32
|
||||
Correct_FileName_for_FS(dest, len);
|
||||
#endif
|
||||
dest += len;
|
||||
if (c == 0)
|
||||
break;
|
||||
*dest++ = WCHAR_PATH_SEPARATOR;
|
||||
}
|
||||
s += len + 1;
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dest != destStart && dest[-1] == WCHAR_PATH_SEPARATOR)
|
||||
{
|
||||
if (isDir)
|
||||
dest--;
|
||||
else
|
||||
*dest++ = '_';
|
||||
}
|
||||
|
||||
if (dest == destStart)
|
||||
*dest++ = '_';
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
|
||||
#if WCHAR_PATH_SEPARATOR != L'/'
|
||||
|
||||
#ifdef _WIN32
|
||||
// WSL scheme
|
||||
#define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT ((unsigned)((unsigned)(0xF000) + (unsigned)'\\'))
|
||||
#else
|
||||
#define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT '_'
|
||||
#endif
|
||||
|
||||
static Z7_FORCE_INLINE
|
||||
void Normalize_Path_from_7z_to_FS(UInt16 *s)
|
||||
{
|
||||
// Normalize_Path_from_7z_to_FS(s);
|
||||
for (;; s++)
|
||||
{
|
||||
unsigned c = *s;
|
||||
if (c == 0)
|
||||
break;
|
||||
if (c == '/') // separator inside 7z archive
|
||||
c = WCHAR_PATH_SEPARATOR;
|
||||
else if (c == WCHAR_PATH_SEPARATOR)
|
||||
c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT;
|
||||
#ifdef _WIN32
|
||||
else if (c < 0x20 || c == ':' || c == '*' || c == '?' || c == '<' || c == '>' || c == '|' || c == '"')
|
||||
c = '_';
|
||||
else
|
||||
continue;
|
||||
*s = (UInt16)c;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// this function changes both strings: (dest) and (s),
|
||||
// but length of (s) string will not changed.
|
||||
// dest[] must provide additional space: size(dest) >= len(len) * 2 + 2
|
||||
// in: (s) uses slash path separators (/)
|
||||
// out: (s) : temporary string
|
||||
// out: (dest) uses WCHAR_PATH_SEPARATOR path separator
|
||||
static Z7_FORCE_INLINE
|
||||
void NormalizePath_for_FS(UInt16 *dest, UInt16 *s, BoolInt isDir)
|
||||
{
|
||||
#if WCHAR_PATH_SEPARATOR != L'/'
|
||||
Normalize_Path_from_7z_to_FS(s);
|
||||
#endif
|
||||
NormalizesPathParts_and_Dots(dest, s , isDir);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef USE_WINDOWS_FILE
|
||||
static UINT g_FileCodePage = CP_ACP;
|
||||
@@ -205,6 +432,38 @@ static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s
|
||||
#define MY_FILE_CODE_PAGE_PARAM
|
||||
#endif
|
||||
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
|
||||
static WRes My_DeleteFileAlways(const UInt16 *path)
|
||||
{
|
||||
const DWORD attrib = GetFileAttributesW(path);
|
||||
if (// attrib != INVALID_FILE_ATTRIBUTES &&
|
||||
(attrib & FILE_ATTRIBUTE_DIRECTORY) == 0 &&
|
||||
(attrib & FILE_ATTRIBUTE_READONLY))
|
||||
{
|
||||
if (!SetFileAttributes(path, attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY))
|
||||
return GetLastError();
|
||||
}
|
||||
if (DeleteFileW(path))
|
||||
return 0;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static WRes My_DeleteFileAlways(const UInt16 *path)
|
||||
{
|
||||
CBuf buf;
|
||||
WRes res;
|
||||
Buf_Init(&buf);
|
||||
RINOK_WRes(Utf16_To_Char(&buf, path MY_FILE_CODE_PAGE_PARAM))
|
||||
res = remove((const char *)buf.data) == 0 ? 0 : errno;
|
||||
Buf_Free(&buf, &g_Alloc);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static WRes MyCreateDir(const UInt16 *name)
|
||||
{
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
@@ -216,7 +475,7 @@ static WRes MyCreateDir(const UInt16 *name)
|
||||
CBuf buf;
|
||||
WRes res;
|
||||
Buf_Init(&buf);
|
||||
RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM))
|
||||
RINOK_WRes(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM))
|
||||
|
||||
res =
|
||||
#ifdef _WIN32
|
||||
@@ -247,12 +506,51 @@ static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name)
|
||||
}
|
||||
|
||||
|
||||
static SRes PrintString(const UInt16 *s)
|
||||
static Z7_FORCE_INLINE BoolInt IsDangerousTerminalChar(wchar_t c)
|
||||
{
|
||||
// if (c < 0) return False; // it's not expected case
|
||||
if (c < 0x20) return True;
|
||||
if (c < 0x7F) return False;
|
||||
if (c < 0x9F + 1) return True;
|
||||
// Unicode Bidirectional (BiDi) control characters:
|
||||
if (c < 0x202A) return False;
|
||||
if (c < 0x202E + 1) return True;
|
||||
if (c < 0x2066) return False;
|
||||
if (c < 0x2069 + 1) return True;
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
// (size(dest) >= len(src) + 3), if (isDir == True)
|
||||
// s[] uses slash path separator (/)
|
||||
static SRes PrintPath(const UInt16 *s, UInt16 *dest, BoolInt isDir, BoolInt isTerminalMode)
|
||||
{
|
||||
CBuf buf;
|
||||
SRes res;
|
||||
size_t i;
|
||||
for (i = 0;; i++)
|
||||
{
|
||||
UInt16 c = s[i];
|
||||
if (c == 0)
|
||||
break;
|
||||
if (isTerminalMode ? IsDangerousTerminalChar(c) :
|
||||
(c == '\n'
|
||||
#ifdef _WIN32
|
||||
|| c == '\r'
|
||||
#endif
|
||||
))
|
||||
c = '_';
|
||||
dest[i] = c;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
dest[i++] = '_';
|
||||
if (isDir && dest[i - 1] != '/')
|
||||
dest[i++] = '/';
|
||||
dest[i] = 0;
|
||||
|
||||
Buf_Init(&buf);
|
||||
res = Utf16_To_Char(&buf, s
|
||||
res = Utf16_To_Char(&buf, dest
|
||||
#ifndef MY_USE_UTF8
|
||||
, CP_OEMCP
|
||||
#endif
|
||||
@@ -499,7 +797,7 @@ static void PrintError_WRes(const char *message, WRes wres)
|
||||
Print(s);
|
||||
}
|
||||
// sprintf(buffer + strlen(buffer), "\nSystem error code: %d", (unsigned)wres);
|
||||
#ifdef _WIN32
|
||||
#ifdef USE_WINDOWS_FILE // _WIN32
|
||||
{
|
||||
char *s = NULL;
|
||||
if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
@@ -540,8 +838,6 @@ static void GetAttribString(UInt32 wa, BoolInt isDir, char *s)
|
||||
}
|
||||
|
||||
|
||||
// #define NUM_PARENTS_MAX 128
|
||||
|
||||
int Z7_CDECL main(int numargs, char *args[])
|
||||
{
|
||||
ISzAlloc allocImp;
|
||||
@@ -552,8 +848,9 @@ int Z7_CDECL main(int numargs, char *args[])
|
||||
CSzArEx db;
|
||||
SRes res;
|
||||
UInt16 *temp = NULL;
|
||||
UInt16 *temp2 = NULL;
|
||||
size_t tempSize = 0;
|
||||
// UInt32 parents[NUM_PARENTS_MAX];
|
||||
const BoolInt isTerminalMode = MY_IS_TERMINAL(stdout);
|
||||
|
||||
Print("\n7z Decoder " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n");
|
||||
|
||||
@@ -669,12 +966,15 @@ int Z7_CDECL main(int numargs, char *args[])
|
||||
{
|
||||
SzFree(NULL, temp);
|
||||
tempSize = len;
|
||||
temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0]));
|
||||
// temp2 requires additional space for "_" additions for "COM1" and empty names,
|
||||
// and up to 2 additional characters for PrintPath().
|
||||
temp = (UInt16 *)SzAlloc(NULL, (tempSize * 3 + 16) * sizeof(temp[0]));
|
||||
if (!temp)
|
||||
{
|
||||
res = SZ_ERROR_MEM;
|
||||
break;
|
||||
}
|
||||
temp2 = temp + tempSize;
|
||||
}
|
||||
|
||||
SzArEx_GetFileNameUtf16(&db, i, temp);
|
||||
@@ -712,25 +1012,19 @@ int Z7_CDECL main(int numargs, char *args[])
|
||||
Print(" ");
|
||||
Print(s);
|
||||
Print(" ");
|
||||
res = PrintString(temp);
|
||||
res = PrintPath(temp, temp2, isDir, isTerminalMode);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
if (isDir)
|
||||
Print("/");
|
||||
PrintLF();
|
||||
continue;
|
||||
}
|
||||
|
||||
Print(testCommand ?
|
||||
"T ":
|
||||
"- ");
|
||||
res = PrintString(temp);
|
||||
Print(testCommand ? "T ": "- ");
|
||||
res = PrintPath(temp, temp2, isDir, isTerminalMode);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
|
||||
if (isDir)
|
||||
Print("/");
|
||||
else
|
||||
if (!isDir)
|
||||
{
|
||||
res = SzArEx_Extract(&db, &lookStream.vt, i,
|
||||
&blockIndex, &outBuffer, &outBufferSize,
|
||||
@@ -745,11 +1039,16 @@ int Z7_CDECL main(int numargs, char *args[])
|
||||
CSzFile outFile;
|
||||
size_t processedSize;
|
||||
size_t j;
|
||||
UInt16 *name = (UInt16 *)temp;
|
||||
|
||||
UInt16 *name = (UInt16 *)temp2;
|
||||
const UInt16 *destPath = (const UInt16 *)name;
|
||||
|
||||
|
||||
// memset(temp2, 0, (tempSize) * sizeof(temp[0])); // for debug
|
||||
NormalizePath_for_FS(temp2, temp, isDir);
|
||||
// PrintLF(); PrintPath(temp2, temp, isDir, isTerminalMode); // for debuf
|
||||
|
||||
for (j = 0; name[j] != 0; j++)
|
||||
if (name[j] == '/')
|
||||
if (name[j] == CHAR_PATH_SEPARATOR)
|
||||
{
|
||||
if (fullPaths)
|
||||
{
|
||||
@@ -769,12 +1068,26 @@ int Z7_CDECL main(int numargs, char *args[])
|
||||
}
|
||||
else
|
||||
{
|
||||
const WRes wres = OutFile_OpenUtf16(&outFile, destPath);
|
||||
if (wres != 0)
|
||||
{
|
||||
PrintError_WRes("cannot open output file", wres);
|
||||
res = SZ_ERROR_FAIL;
|
||||
break;
|
||||
// const WRes wres =
|
||||
My_DeleteFileAlways(destPath);
|
||||
/*
|
||||
if (wres && wres != ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
PrintError_WRes("cannot delete output file", wres);
|
||||
res = SZ_ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
{
|
||||
const WRes wres = OutFile_OpenUtf16(&outFile, destPath);
|
||||
if (wres)
|
||||
{
|
||||
PrintError_WRes("cannot open output file", wres);
|
||||
res = SZ_ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,7 +1159,7 @@ int Z7_CDECL main(int numargs, char *args[])
|
||||
UInt32 attrib = db.Attribs.Vals[i];
|
||||
/* p7zip stores posix attributes in high 16 bits and adds 0x8000 as marker.
|
||||
We remove posix bits, if we detect posix mode field */
|
||||
if ((attrib & 0xF0000000) != 0)
|
||||
if (attrib & 0xF0000000)
|
||||
attrib &= 0x7FFF;
|
||||
SetFileAttributesW((LPCWSTR)destPath, attrib);
|
||||
}
|
||||
|
||||
Vendored
+3
-3
@@ -279,7 +279,7 @@ SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id,
|
||||
decoder = (CXzBcFilterState *)ISzAlloc_Alloc(alloc, sizeof(CXzBcFilterState));
|
||||
if (!decoder)
|
||||
return SZ_ERROR_MEM;
|
||||
decoder->buf = ISzAlloc_Alloc(alloc, BRA_BUF_SIZE);
|
||||
decoder->buf = (Byte *)ISzAlloc_Alloc(alloc, BRA_BUF_SIZE);
|
||||
if (!decoder->buf)
|
||||
{
|
||||
ISzAlloc_Free(alloc, decoder);
|
||||
@@ -1243,7 +1243,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||
UInt32 digest32[XZ_CHECK_SIZE_MAX / 4];
|
||||
p->state = XZ_STATE_BLOCK_HEADER;
|
||||
p->pos = 0;
|
||||
if (XzCheck_Final(&p->check, (void *)digest32) && memcmp(digest32, p->buf, checkSize) != 0)
|
||||
if (XzCheck_Final(&p->check, (Byte *)(void *)digest32) && memcmp(digest32, p->buf, checkSize) != 0)
|
||||
return SZ_ERROR_CRC;
|
||||
if (p->decodeOnlyOneBlock)
|
||||
{
|
||||
@@ -1292,7 +1292,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||
p->state = XZ_STATE_STREAM_INDEX_CRC;
|
||||
p->indexSize += 4;
|
||||
p->pos = 0;
|
||||
Sha256_Final(&p->sha, (void *)digest32);
|
||||
Sha256_Final(&p->sha, (Byte *)(void *)digest32);
|
||||
if (memcmp(digest32, p->shaDigest32, SHA256_DIGEST_SIZE) != 0)
|
||||
return SZ_ERROR_CRC;
|
||||
}
|
||||
|
||||
+1
-1
@@ -313,7 +313,7 @@ LDLIBS += $(ZLIB_LDLIBS)
|
||||
|
||||
ifeq ($(origin MINIZIP_CFLAGS) $(origin MINIZIP_LDLIBS), undefined undefined)
|
||||
ifeq ($(shell $(PKG_CONFIG) --modversion minizip 2>/dev/null),)
|
||||
CFLAGS += -DNOCRYPT -DNOUNCRYPT -I$(SUBDIR)/minizip
|
||||
CFLAGS += -DNOCRYPT -DNOUNCRYPT -I$(SUBDIR)
|
||||
MINIZIP_SOURCE = \
|
||||
$(SUBDIR)/minizip/ioapi.c \
|
||||
$(SUBDIR)/minizip/zip.c \
|
||||
|
||||
+18
-18
@@ -372,22 +372,22 @@ static const struct r4300_idec r4300_op_table[] = {
|
||||
/* TLB opcodes table
|
||||
* 176-239
|
||||
*/
|
||||
RESERVED, TLBR, TLBWI, RESERVED,
|
||||
RESERVED, RESERVED, TLBWR, RESERVED,
|
||||
TLBP, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
ERET, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
RESERVED, RESERVED, RESERVED, RESERVED,
|
||||
NOP, TLBR, TLBWI, NOP,
|
||||
NOP, NOP, TLBWR, NOP,
|
||||
TLBP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
ERET, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
NOP, NOP, NOP, NOP,
|
||||
/* COP1 opcodes table
|
||||
* 240-247
|
||||
*/
|
||||
@@ -430,7 +430,7 @@ static const struct r4300_idec r4300_op_table[] = {
|
||||
/* Pseudo opcodes
|
||||
* 336
|
||||
*/
|
||||
NOP
|
||||
NOP
|
||||
};
|
||||
|
||||
#define E_INV { 0, 0, 0x00 }
|
||||
@@ -459,7 +459,7 @@ struct r4300_op_escape {
|
||||
static const struct r4300_op_escape r4300_escapes_table[] = {
|
||||
|
||||
/* 000000 - special */
|
||||
E_SPECIAL, E_SPECIAL, E_SPECIAL, E_SPECIAL,
|
||||
E_SPECIAL, E_SPECIAL, E_SPECIAL, E_SPECIAL,
|
||||
|
||||
/* 000001 - regimm */
|
||||
E_REGIMM, E_REGIMM, E_REGIMM, E_REGIMM,
|
||||
|
||||
@@ -1089,16 +1089,17 @@ DECLARE_INSTRUCTION(TLBR)
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
int index;
|
||||
index = cp0_regs[CP0_INDEX_REG] & UINT32_C(0x1F);
|
||||
cp0_regs[CP0_PAGEMASK_REG] = r4300->cp0.tlb.entries[index].mask << 13;
|
||||
cp0_regs[CP0_ENTRYHI_REG] = ((r4300->cp0.tlb.entries[index].vpn2 << 13) | r4300->cp0.tlb.entries[index].asid);
|
||||
cp0_regs[CP0_ENTRYLO0_REG] = (r4300->cp0.tlb.entries[index].pfn_even << 6) | (r4300->cp0.tlb.entries[index].c_even << 3)
|
||||
| (r4300->cp0.tlb.entries[index].d_even << 2) | (r4300->cp0.tlb.entries[index].v_even << 1)
|
||||
| r4300->cp0.tlb.entries[index].g;
|
||||
cp0_regs[CP0_ENTRYLO1_REG] = (r4300->cp0.tlb.entries[index].pfn_odd << 6) | (r4300->cp0.tlb.entries[index].c_odd << 3)
|
||||
| (r4300->cp0.tlb.entries[index].d_odd << 2) | (r4300->cp0.tlb.entries[index].v_odd << 1)
|
||||
| r4300->cp0.tlb.entries[index].g;
|
||||
int index = cp0_regs[CP0_INDEX_REG] & UINT32_C(0x3F);
|
||||
if (index < CP0_REGS_COUNT) {
|
||||
cp0_regs[CP0_PAGEMASK_REG] = r4300->cp0.tlb.entries[index].mask << 13;
|
||||
cp0_regs[CP0_ENTRYHI_REG] = ((r4300->cp0.tlb.entries[index].vpn2 << 13) | r4300->cp0.tlb.entries[index].asid);
|
||||
cp0_regs[CP0_ENTRYLO0_REG] = (r4300->cp0.tlb.entries[index].pfn_even << 6) | (r4300->cp0.tlb.entries[index].c_even << 3)
|
||||
| (r4300->cp0.tlb.entries[index].d_even << 2) | (r4300->cp0.tlb.entries[index].v_even << 1)
|
||||
| r4300->cp0.tlb.entries[index].g;
|
||||
cp0_regs[CP0_ENTRYLO1_REG] = (r4300->cp0.tlb.entries[index].pfn_odd << 6) | (r4300->cp0.tlb.entries[index].c_odd << 3)
|
||||
| (r4300->cp0.tlb.entries[index].d_odd << 2) | (r4300->cp0.tlb.entries[index].v_odd << 1)
|
||||
| r4300->cp0.tlb.entries[index].g;
|
||||
}
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -1220,8 +1221,12 @@ DECLARE_INSTRUCTION(TLBWR)
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
cp0_update_count(r4300);
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
if (cp0_regs[CP0_WIRED_REG] >= 32) {
|
||||
cp0_regs[CP0_RANDOM_REG] = cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % 64;
|
||||
} else {
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
+ cp0_regs[CP0_WIRED_REG];
|
||||
}
|
||||
TLBWrite(r4300, cp0_regs[CP0_RANDOM_REG]);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
@@ -1231,7 +1236,9 @@ DECLARE_INSTRUCTION(TLBWI)
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
TLBWrite(r4300, cp0_regs[CP0_INDEX_REG] & UINT32_C(0x3F));
|
||||
int index = cp0_regs[CP0_INDEX_REG] & UINT32_C(0x3F);
|
||||
if (index < CP0_REGS_COUNT)
|
||||
TLBWrite(r4300, index);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -1247,8 +1254,12 @@ DECLARE_INSTRUCTION(MFC0)
|
||||
{
|
||||
case CP0_RANDOM_REG:
|
||||
cp0_update_count(r4300);
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
+ cp0_regs[CP0_WIRED_REG];
|
||||
if (cp0_regs[CP0_WIRED_REG] >= 32) {
|
||||
cp0_regs[CP0_RANDOM_REG] = cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % 64;
|
||||
} else {
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
+ cp0_regs[CP0_WIRED_REG];
|
||||
}
|
||||
rrt = SE32(cp0_regs[rfs]);
|
||||
break;
|
||||
case CP0_COUNT_REG:
|
||||
@@ -1282,8 +1293,12 @@ DECLARE_INSTRUCTION(DMFC0)
|
||||
{
|
||||
case CP0_RANDOM_REG:
|
||||
cp0_update_count(r4300);
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
+ cp0_regs[CP0_WIRED_REG];
|
||||
if (cp0_regs[CP0_WIRED_REG] >= 32) {
|
||||
cp0_regs[CP0_RANDOM_REG] = cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % 64;
|
||||
} else {
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
+ cp0_regs[CP0_WIRED_REG];
|
||||
}
|
||||
rrt = cp0_regs[rfs];
|
||||
break;
|
||||
case CP0_COUNT_REG:
|
||||
@@ -1323,11 +1338,6 @@ DECLARE_INSTRUCTION(MTC0)
|
||||
{
|
||||
case CP0_INDEX_REG:
|
||||
cp0_regs[CP0_INDEX_REG] = rrt32 & UINT32_C(0x8000003F);
|
||||
if ((cp0_regs[CP0_INDEX_REG] & UINT32_C(0x3F)) > UINT32_C(31))
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "MTC0 instruction writing Index register with TLB index > 31");
|
||||
*r4300_stop(r4300)=1;
|
||||
}
|
||||
break;
|
||||
case CP0_RANDOM_REG:
|
||||
break;
|
||||
@@ -1399,7 +1409,7 @@ DECLARE_INSTRUCTION(MTC0)
|
||||
case CP0_PREVID_REG:
|
||||
break;
|
||||
case CP0_CONFIG_REG:
|
||||
cp0_regs[CP0_CONFIG_REG] = (rrt32 & UINT32_C(0x0000000F))
|
||||
cp0_regs[CP0_CONFIG_REG] = (rrt32 & UINT32_C(0x0000000F))
|
||||
| (cp0_regs[CP0_CONFIG_REG] & UINT32_C(0x00008000))
|
||||
| (cp0_regs[CP0_CONFIG_REG] & UINT32_C(0x7FFFFFFF));
|
||||
break;
|
||||
|
||||
@@ -446,23 +446,32 @@ void InterpretOpcode(struct r4300_core* r4300)
|
||||
case 5: /* Coprocessor 0 opcode 5: DMTC0 */
|
||||
MTC0(r4300, op);
|
||||
break;
|
||||
case 16: /* Coprocessor 0 opcode 16: TLB */
|
||||
case 2:
|
||||
case 3:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15: /* Coprocessor 0 opcodes 2..3, 6..15: Reserved Instructions */
|
||||
RESERVED(r4300, op);
|
||||
break;
|
||||
default: /* Coprocessor 0 opcode 16..31: TLB */
|
||||
switch (op & 0x3F) {
|
||||
case 1: TLBR(r4300, op); break;
|
||||
case 2: TLBWI(r4300, op); break;
|
||||
case 6: TLBWR(r4300, op); break;
|
||||
case 8: TLBP(r4300, op); break;
|
||||
case 24: ERET(r4300, op); break;
|
||||
default: /* TLB sub-opcodes 0, 3..5, 7, 9..23, 25..63:
|
||||
Reserved Instructions */
|
||||
RESERVED(r4300, op);
|
||||
default: /* TLB sub-opcodes 0, 3..5, 7, 9..23, 25..63: undefined */
|
||||
NOP(r4300, 0);
|
||||
break;
|
||||
} /* switch (op & 0x3F) for Coprocessor 0 TLB opcodes */
|
||||
break;
|
||||
default: /* Coprocessor 0 opcodes 2..3, 5..15, 17..31:
|
||||
Reserved Instructions */
|
||||
RESERVED(r4300, op);
|
||||
break;
|
||||
} /* switch ((op >> 21) & 0x1F) for the Coprocessor 0 prefix */
|
||||
break;
|
||||
case 17: /* Coprocessor 1 prefix */
|
||||
|
||||
@@ -110,7 +110,7 @@ static void dma_pi_write(struct pi_controller* pi)
|
||||
if (length >= 0x7f && (length & 1))
|
||||
length += 1;
|
||||
if (length <= 0x80)
|
||||
length -= dram_addr & 0x7;
|
||||
length = length >= (dram_addr & 0x7) ? length - (dram_addr & 0x7) : 0;
|
||||
unsigned int cycles = handler->dma_write(opaque, dram, dram_addr, cart_addr, length);
|
||||
|
||||
post_framebuffer_write(&pi->dp->fb, dram_addr, length);
|
||||
|
||||
+2
-2
@@ -263,7 +263,7 @@ m64p_error netplay_start(const char* host, int port)
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
l_udpSocket = NET_CreateDatagramSocket(NULL, 0);
|
||||
l_udpSocket = NET_CreateDatagramSocket(NULL, 0, 0);
|
||||
if (l_udpSocket == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Netplay: UDP socket creation failed: %s", SDL_GetError());
|
||||
@@ -272,7 +272,7 @@ m64p_error netplay_start(const char* host, int port)
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
l_tcpSocket = NET_CreateClient(l_resolvedAddress, port);
|
||||
l_tcpSocket = NET_CreateClient(l_resolvedAddress, port, 0);
|
||||
if (l_tcpSocket == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Netplay: TCP socket connection failed: %s", SDL_GetError());
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <zlib.h>
|
||||
#include <unzip.h>
|
||||
#include <zip.h>
|
||||
#include <minizip/unzip.h>
|
||||
#include <minizip/zip.h>
|
||||
|
||||
#define M64P_CORE_PROTOTYPES 1
|
||||
#include "api/callbacks.h"
|
||||
|
||||
@@ -1,38 +1,52 @@
|
||||
* text=auto
|
||||
#* text=auto
|
||||
|
||||
# normal text files
|
||||
*.6 text
|
||||
*.asm text
|
||||
AUTHORS text
|
||||
*.awk text
|
||||
*.c text
|
||||
*.cfg text
|
||||
*.cht text
|
||||
*.cmake text
|
||||
*.conf text
|
||||
COPYING text
|
||||
*.cpp text
|
||||
CREDITS text
|
||||
*.def text
|
||||
*-license text
|
||||
*.desktop text
|
||||
.gitattributes text
|
||||
.gitignore text
|
||||
*.h text
|
||||
*.hpp text
|
||||
*.html text
|
||||
*.ini text
|
||||
INSTALL text
|
||||
*-license text
|
||||
LICENSES text
|
||||
Makefile text
|
||||
*.md text
|
||||
*.mediawiki text
|
||||
*.py text
|
||||
README text
|
||||
RELEASE text
|
||||
*.S text
|
||||
*.sh text
|
||||
*.svg text
|
||||
*.txt text
|
||||
*.ver text
|
||||
*.yml text
|
||||
|
||||
# windows specific text files
|
||||
*.sln text eol=crlf
|
||||
*.vcproj text eol=crlf
|
||||
*.vcxproj text eol=crlf
|
||||
*.vcxproj.filters text eol=crlf
|
||||
#*.cmd text eol=crlf
|
||||
#*.sln text eol=crlf
|
||||
#*.vcproj text eol=crlf
|
||||
#*.vcxproj text eol=crlf
|
||||
#*.vcxproj.filters text eol=crlf
|
||||
|
||||
# binary files
|
||||
*.gz binary
|
||||
*.png binary
|
||||
*.ttf binary
|
||||
cursor.tex binary
|
||||
font.tex binary
|
||||
|
||||
+69
-159
@@ -3,16 +3,12 @@ name: CXD4 RSP
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '**/*.md'
|
||||
- '.{gitattributes,gitignore,travis.yml}'
|
||||
- 'appveyor.yml,README'
|
||||
- '*.md,appveyor.yml,README'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**/*.md'
|
||||
- '.{gitattributes,gitignore,travis.yml}'
|
||||
- 'appveyor.yml,README'
|
||||
schedule:
|
||||
- cron: '35 14 21 * *'
|
||||
- '*.md,appveyor.yml,README'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -23,65 +19,34 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- cc: GCC
|
||||
platform: x64
|
||||
bits: 64
|
||||
arch: x64
|
||||
- cc: GCC
|
||||
platform: x86
|
||||
bits: 32
|
||||
arch: x86
|
||||
- cc: Clang
|
||||
platform: x64
|
||||
bits: 64
|
||||
arch: x64
|
||||
- cc: Clang
|
||||
platform: x86
|
||||
bits: 32
|
||||
name: Linux / ${{ matrix.cc }} / ${{ matrix.platform }}
|
||||
runs-on: ubuntu-22.04
|
||||
if: (github.event_name == 'schedule' && github.repository == 'mupen64plus/mupen64plus-rsp-cxd4') || (github.event_name != 'schedule')
|
||||
arch: x86
|
||||
name: Linux / ${{ matrix.cc }} ${{ matrix.arch }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
- name: Get build dependencies and arrange the environment
|
||||
run: |
|
||||
echo "G_REV=$(git rev-parse --short HEAD)" >> "${GITHUB_ENV}"
|
||||
sudo apt-get update
|
||||
sudo apt-get --reinstall -y install gcc-multilib g++-multilib libc6 libc6-dev-i386
|
||||
sudo ldconfig
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
|
||||
./../mupen64plus-core/.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
if [[ ${{ matrix.bits }} -eq 32 ]]; then export PIC="1" CPU_TUNE="-mtune=pentium4"; else CPU_TUNE="-mtune=core2"; fi
|
||||
export OPTFLAGS="-O2 -flto ${CPU_TUNE}"
|
||||
ORIG="$(pwd)"
|
||||
CC="gcc"
|
||||
CXX="g++"
|
||||
if [[ "${{ matrix.cc }}" != "GCC" ]]; then
|
||||
CC="clang"
|
||||
CXX="clang++"
|
||||
fi
|
||||
${CC} --version
|
||||
echo ""
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
|
||||
mkdir pkg
|
||||
for SSE in none SSE2; do
|
||||
echo ""
|
||||
echo ":: ${{ matrix.cc }} ${{ matrix.platform }}${MSG} ::"
|
||||
echo ""
|
||||
make SSE="${SSE}" -C projects/unix clean
|
||||
echo ""
|
||||
make CC="${CC}" CXX="${CXX}" BITS="${{ matrix.bits }}" SSE="${SSE}" -C projects/unix all -j4
|
||||
echo ""
|
||||
make SSE="${SSE}" -C projects/unix install DESTDIR="${ORIG}/pkg/"
|
||||
echo ""
|
||||
ls -gG pkg/usr/local/lib/mupen64plus/mupen64plus-rsp-cxd4${LIB}.so
|
||||
echo ""
|
||||
ldd pkg/usr/local/lib/mupen64plus/mupen64plus-rsp-cxd4${LIB}.so
|
||||
LIB="-sse2"
|
||||
MSG=" / SSE2"
|
||||
done
|
||||
tar cvzf pkg/mupen64plus-rsp-cxd4-linux-${{ matrix.platform }}-g${{ env.G_REV }}.tar.gz -C pkg/ "usr"
|
||||
export PATH="$(pwd)/../mupen64plus-core/.github/workflows/scripts:${PATH}"
|
||||
export CONFIG_OVERRIDE="SSE="SSE2""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export OPTFLAGS="-O3 -flto"
|
||||
export CONFIG_OVERRIDE="SSE="none""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg
|
||||
- name: Upload artifact
|
||||
if: matrix.cc == 'GCC'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: mupen64plus-rsp-cxd4-linux-${{ matrix.platform }}-g${{ env.G_REV }}
|
||||
name: ${{ env.PKG_NAME }}
|
||||
path: pkg/*.tar.gz
|
||||
|
||||
MSYS2:
|
||||
@@ -90,63 +55,54 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- cc: GCC
|
||||
platform: x64
|
||||
arch: x64
|
||||
cross: x86_64
|
||||
bits: 64
|
||||
env: MINGW64
|
||||
- cc: GCC
|
||||
platform: x86
|
||||
arch: x86
|
||||
cross: i686
|
||||
bits: 32
|
||||
name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.platform }}
|
||||
runs-on: windows-2022
|
||||
if: (github.event_name == 'schedule' && github.repository == 'mupen64plus/mupen64plus-rsp-cxd4') || (github.event_name != 'schedule')
|
||||
env: MINGW32
|
||||
- cc: GCC
|
||||
arch: x64
|
||||
cross: ucrt-x86_64
|
||||
env: UCRT64
|
||||
- cc: Clang
|
||||
arch: x64
|
||||
cross: clang-x86_64
|
||||
env: CLANG64
|
||||
name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }}
|
||||
runs-on: windows-2025
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW${{ matrix.bits }}
|
||||
msystem: ${{ matrix.env }}
|
||||
update: true
|
||||
install: >-
|
||||
git
|
||||
libtool
|
||||
make
|
||||
mingw-w64-${{ matrix.cross }}-gcc
|
||||
mingw-w64-${{ matrix.cross }}-toolchain
|
||||
mingw-w64-${{ matrix.cross }}-ntldd
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
echo "G_REV=$(git rev-parse --short HEAD)" >> "${GITHUB_ENV}"
|
||||
if [[ ${{ matrix.bits }} -eq 32 ]]; then CPU_TUNE="-mtune=pentium4"; else CPU_TUNE="-mtune=core2"; fi
|
||||
export OPTFLAGS="-O2 -flto ${CPU_TUNE}"
|
||||
ORIG="$(pwd)"
|
||||
CC="gcc"
|
||||
CXX="g++"
|
||||
${CC} --version
|
||||
echo ""
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
|
||||
mkdir pkg
|
||||
for SSE in none SSE2; do
|
||||
echo ""
|
||||
echo ":: ${{ matrix.cc }} ${{ matrix.platform }}${MSG} ::"
|
||||
echo ""
|
||||
make SSE="${SSE}" -C projects/unix clean
|
||||
echo ""
|
||||
make CC="${CC}" CXX="${CXX}" BITS="${{ matrix.bits }}" SSE="${SSE}" -C projects/unix all -j4
|
||||
echo ""
|
||||
make SSE="${SSE}" -C projects/unix install PLUGINDIR="" SHAREDIR="" BINDIR="" MANDIR="" LIBDIR="" APPSDIR="" ICONSDIR="icons" INCDIR="api" LDCONFIG="true" DESTDIR="${ORIG}/pkg/"
|
||||
echo ""
|
||||
ls -gG pkg/mupen64plus-rsp-cxd4${LIB}.dll
|
||||
echo ""
|
||||
ldd pkg/mupen64plus-rsp-cxd4${LIB}.dll
|
||||
LIB="-sse2"
|
||||
MSG=" / SSE2"
|
||||
done
|
||||
export PATH="$(pwd)/../mupen64plus-core/.github/workflows/scripts:${PATH}"
|
||||
export CONFIG_OVERRIDE="SSE="SSE2""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export OPTFLAGS="-O3 -flto"
|
||||
export CONFIG_OVERRIDE="SSE="none""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
- name: Backup dependencies, etc...
|
||||
run: |
|
||||
./../mupen64plus-core/.github/workflows/scripts/ci_backup_mingw_deps.sh ${{ matrix.env }}
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: mupen64plus-rsp-cxd4-msys2-${{ matrix.platform }}-g${{ env.G_REV }}
|
||||
name: ${{ env.PKG_NAME }}
|
||||
path: pkg/*
|
||||
|
||||
MSVC:
|
||||
@@ -155,39 +111,33 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- toolset: v143
|
||||
platform: x64
|
||||
vs: 2022
|
||||
arch: x64
|
||||
- toolset: v141_xp
|
||||
platform: x86
|
||||
vs: 2019
|
||||
name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.platform }}
|
||||
runs-on: windows-${{ matrix.vs }}
|
||||
if: (github.event_name == 'schedule' && github.repository == 'mupen64plus/mupen64plus-rsp-cxd4') || (github.event_name != 'schedule')
|
||||
arch: x86
|
||||
name: Windows ${{ matrix.arch }} / MSVC with ${{ matrix.toolset }}
|
||||
runs-on: windows-2025
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: microsoft/setup-msbuild@v1
|
||||
- uses: actions/checkout@v6
|
||||
- uses: microsoft/setup-msbuild@v2
|
||||
- name: Pre-build arrangements for ${{ matrix.toolset }}
|
||||
if: matrix.toolset == 'v141_xp'
|
||||
run: |
|
||||
"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\setup.exe" modify --quiet --productId Microsoft.VisualStudio.Product.Enterprise --channelId VisualStudio.17.Release --add Microsoft.VisualStudio.Component.WinXP
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
for /f "tokens=1" %%R in ('git rev-parse --short HEAD') do echo G_REV=%%R>> "%GITHUB_ENV%"
|
||||
set "ARCH=${{ matrix.platform }}"
|
||||
if [%ARCH%] == [x86] set "ARCH=Win32"
|
||||
echo.
|
||||
msbuild --version
|
||||
echo.
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ..\mupen64plus-core
|
||||
md pkg
|
||||
echo.
|
||||
msbuild projects\msvc\mupen64plus-rsp-cxd4.vcxproj /p:Configuration=Release;Platform=%ARCH%;PlatformToolset=${{ matrix.toolset }}
|
||||
echo.
|
||||
copy "projects\msvc\%ARCH%\Release\mupen64plus-rsp-cxd4.dll" pkg\
|
||||
dir pkg\*.dll
|
||||
set TOOLSET=${{ matrix.toolset }}
|
||||
.\..\mupen64plus-core\.github\workflows\scripts\ci_msvc_build.cmd ${{ matrix.arch }}
|
||||
- name: Backup dependencies, etc...
|
||||
run: |
|
||||
.\..\mupen64plus-core\.github\workflows\scripts\ci_backup_msvc_deps.cmd ${{ matrix.arch }}
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: mupen64plus-rsp-cxd4-msvc-${{ matrix.platform }}-g${{ env.G_REV }}
|
||||
name: ${{ env.PKG_NAME }}
|
||||
path: pkg/*
|
||||
|
||||
Nightly-build:
|
||||
@@ -195,61 +145,21 @@ jobs:
|
||||
if: github.ref_name == 'master'
|
||||
needs: [Linux, MSYS2, MSVC]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
path: binaries
|
||||
- name: Get some tools
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install hashdeep
|
||||
- name: Creating new artifacts and update nightly-build
|
||||
run: |
|
||||
mkdir pkg
|
||||
cd binaries
|
||||
for BIN in *; do
|
||||
cd "${BIN}"
|
||||
if [[ "${BIN:21:4}" == "msys" ]]; then
|
||||
echo ":: Creating ${BIN}.zip"
|
||||
zip -r "../../pkg/${BIN}.zip" *
|
||||
elif [[ "${BIN:21:4}" == "msvc" ]]; then
|
||||
echo ":: Creating ${BIN}.zip"
|
||||
zip -r "../../pkg/${BIN}.zip" *
|
||||
else
|
||||
echo ":: Recovering ${BIN}.tar.gz"
|
||||
mv *.tar.gz ../../pkg/
|
||||
fi
|
||||
cd ..
|
||||
done
|
||||
cd ../pkg
|
||||
echo ""
|
||||
for BIN in *; do
|
||||
ls -gG ${BIN}
|
||||
tigerdeep -lz ${BIN} >> ../${BIN:0:20}.tiger.txt
|
||||
sha256sum ${BIN} >> ../${BIN:0:20}.sha256.txt
|
||||
sha512sum ${BIN} >> ../${BIN:0:20}.sha512.txt
|
||||
b2sum ${BIN} >> ../${BIN:0:20}.blake2.txt
|
||||
done
|
||||
mv ../*.tiger.txt .
|
||||
mv ../*.sha*.txt .
|
||||
mv ../*.blake2.txt .
|
||||
echo ""
|
||||
echo "TIGER:"
|
||||
cat *.tiger.txt
|
||||
echo ""
|
||||
echo "SHA256:"
|
||||
cat *.sha256.txt
|
||||
echo ""
|
||||
echo "SHA512:"
|
||||
cat *.sha512.txt
|
||||
echo ""
|
||||
echo "BLAKE2:"
|
||||
cat *.blake2.txt
|
||||
echo ""
|
||||
git tag -f nightly-build
|
||||
git push -f origin nightly-build
|
||||
./../mupen64plus-core/.github/workflows/scripts/ci_nightly_artifacts.sh
|
||||
- name: Nightly-build
|
||||
if: ${{ env.WORKFLOW_REV == env.CURRENT_REV }}
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
prerelease: true
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
name: CXD4 RSP - Scheduled
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '35 14 21 * *'
|
||||
|
||||
jobs:
|
||||
|
||||
Linux:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- cc: GCC
|
||||
arch: x64
|
||||
- cc: GCC
|
||||
arch: x86
|
||||
- cc: Clang
|
||||
arch: x64
|
||||
- cc: Clang
|
||||
arch: x86
|
||||
name: Linux / ${{ matrix.cc }} ${{ matrix.arch }}
|
||||
runs-on: ubuntu-24.04
|
||||
if: github.repository == 'mupen64plus/mupen64plus-rsp-cxd4'
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Get build dependencies and arrange the environment
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
|
||||
./../mupen64plus-core/.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
export PATH="$(pwd)/../mupen64plus-core/.github/workflows/scripts:${PATH}"
|
||||
export CONFIG_OVERRIDE="SSE="SSE2""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export OPTFLAGS="-O3 -flto"
|
||||
export CONFIG_OVERRIDE="SSE="none""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg
|
||||
- name: Upload artifact
|
||||
if: matrix.cc == 'GCC'
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ env.PKG_NAME }}
|
||||
path: pkg/*.tar.gz
|
||||
|
||||
MSYS2:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- cc: GCC
|
||||
arch: x64
|
||||
cross: x86_64
|
||||
env: MINGW64
|
||||
- cc: GCC
|
||||
arch: x86
|
||||
cross: i686
|
||||
env: MINGW32
|
||||
- cc: GCC
|
||||
arch: x64
|
||||
cross: ucrt-x86_64
|
||||
env: UCRT64
|
||||
- cc: Clang
|
||||
arch: x64
|
||||
cross: clang-x86_64
|
||||
env: CLANG64
|
||||
name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }}
|
||||
runs-on: windows-2025
|
||||
if: github.repository == 'mupen64plus/mupen64plus-rsp-cxd4'
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.env }}
|
||||
update: true
|
||||
install: >-
|
||||
git
|
||||
libtool
|
||||
make
|
||||
mingw-w64-${{ matrix.cross }}-toolchain
|
||||
mingw-w64-${{ matrix.cross }}-ntldd
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
|
||||
export PATH="$(pwd)/../mupen64plus-core/.github/workflows/scripts:${PATH}"
|
||||
export CONFIG_OVERRIDE="SSE="SSE2""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
export OPTFLAGS="-O3 -flto"
|
||||
export CONFIG_OVERRIDE="SSE="none""
|
||||
ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }}
|
||||
- name: Backup dependencies, etc...
|
||||
run: |
|
||||
./../mupen64plus-core/.github/workflows/scripts/ci_backup_mingw_deps.sh ${{ matrix.env }}
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ env.PKG_NAME }}
|
||||
path: pkg/*
|
||||
|
||||
MSVC:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: v143
|
||||
arch: x64
|
||||
- toolset: v141_xp
|
||||
arch: x86
|
||||
name: Windows ${{ matrix.arch }} / MSVC with ${{ matrix.toolset }}
|
||||
runs-on: windows-2025
|
||||
if: github.repository == 'mupen64plus/mupen64plus-rsp-cxd4'
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: microsoft/setup-msbuild@v2
|
||||
- name: Pre-build arrangements for ${{ matrix.toolset }}
|
||||
if: matrix.toolset == 'v141_xp'
|
||||
run: |
|
||||
"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\setup.exe" modify --quiet --productId Microsoft.VisualStudio.Product.Enterprise --channelId VisualStudio.17.Release --add Microsoft.VisualStudio.Component.WinXP
|
||||
- name: Build and related stuff, backup binaries
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ..\mupen64plus-core
|
||||
set TOOLSET=${{ matrix.toolset }}
|
||||
.\..\mupen64plus-core\.github\workflows\scripts\ci_msvc_build.cmd ${{ matrix.arch }}
|
||||
- name: Backup dependencies, etc...
|
||||
run: |
|
||||
.\..\mupen64plus-core\.github\workflows\scripts\ci_backup_msvc_deps.cmd ${{ matrix.arch }}
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ env.PKG_NAME }}
|
||||
path: pkg/*
|
||||
|
||||
Nightly-build:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref_name == 'master'
|
||||
needs: [Linux, MSYS2, MSVC]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
path: binaries
|
||||
- name: Get some tools
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install hashdeep
|
||||
- name: Creating new artifacts and update nightly-build
|
||||
run: |
|
||||
./../mupen64plus-core/.github/workflows/scripts/ci_nightly_artifacts.sh
|
||||
- name: Nightly-build
|
||||
if: ${{ env.WORKFLOW_REV == env.CURRENT_REV }}
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
prerelease: true
|
||||
allowUpdates: true
|
||||
removeArtifacts: true
|
||||
replacesArtifacts: false
|
||||
tag: nightly-build
|
||||
artifacts: pkg/*
|
||||
@@ -1,10 +1,5 @@
|
||||
*.asm
|
||||
*.s
|
||||
|
||||
*.o
|
||||
*.so
|
||||
obj
|
||||
|
||||
*.obj
|
||||
*.dll
|
||||
*.exe
|
||||
/projects/unix/_obj*/
|
||||
/projects/unix/mupen64plus-rsp-cxd4*.so
|
||||
/projects/unix/mupen64plus-rsp-cxd4*.dll
|
||||
/projects/msvc/Win32/
|
||||
/projects/msvc/x64/
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = git@github.com:/mupen64plus/mupen64plus-rsp-cxd4.git
|
||||
branch = master
|
||||
commit = 0a4e30f56033396e3ba47ec0fdd7acea3522362a
|
||||
parent = bf0d24d967baf1fcb6365aa4eca6609d2f5a9e6d
|
||||
commit = 821d553fc8ab264fb04862edeff9e7bedc366946
|
||||
parent = e31d8f24f5b914ec8b8341971197e3d3d2f07c18
|
||||
method = merge
|
||||
cmdver = 0.4.6
|
||||
|
||||
+9
-9
@@ -13,6 +13,8 @@
|
||||
* If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. *
|
||||
\******************************************************************************/
|
||||
|
||||
#define _POSIX_SOURCE 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -43,10 +45,10 @@
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
static jmp_buf CPU_state;
|
||||
static sigjmp_buf CPU_state;
|
||||
static void seg_av_handler(int signal_code)
|
||||
{
|
||||
longjmp(CPU_state, signal_code);
|
||||
siglongjmp(CPU_state, signal_code);
|
||||
}
|
||||
#endif
|
||||
static void ISA_op_illegal(int signal_code)
|
||||
@@ -414,7 +416,6 @@ EXPORT unsigned int CALL DoRspCycles(unsigned int cycles)
|
||||
GET_RCP_REG(MI_INTR_REG) |= 0x00000001;
|
||||
GET_RSP_INFO(CheckInterrupts)();
|
||||
}
|
||||
GET_RCP_REG(DPC_STATUS_REG) &= ~0x00000002ul; /* DPC_STATUS_FREEZE */
|
||||
return 0;
|
||||
case M_AUDTASK:
|
||||
if (CFG_HLE_AUD == 0)
|
||||
@@ -523,10 +524,6 @@ void no_LLE(void)
|
||||
}
|
||||
EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, pu32 CycleCount)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
int recovered_from_exception;
|
||||
#endif
|
||||
|
||||
if (CycleCount != NULL) /* cycle-accuracy not doable with today's hosts */
|
||||
*CycleCount = 0;
|
||||
update_conf(CFG_FILE);
|
||||
@@ -567,13 +564,16 @@ EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, pu32 CycleCount)
|
||||
|
||||
signal(SIGILL, ISA_op_illegal);
|
||||
#ifndef _WIN32
|
||||
signal(SIGSEGV, seg_av_handler);
|
||||
struct sigaction sa = {.sa_handler = seg_av_handler};
|
||||
struct sigaction prev_sa;
|
||||
sigaction(SIGSEGV, &sa, &prev_sa);
|
||||
for (SR[ra] = 0; SR[ra] < 0x80000000ul; SR[ra] += 0x200000) {
|
||||
recovered_from_exception = setjmp(CPU_state);
|
||||
int recovered_from_exception = sigsetjmp(CPU_state, 1);
|
||||
if (recovered_from_exception)
|
||||
break;
|
||||
SR[at] += DRAM[SR[ra]];
|
||||
}
|
||||
sigaction(SIGSEGV, &prev_sa, NULL);
|
||||
for (SR[at] = 0; SR[at] < 31; SR[at]++) {
|
||||
SR[ra] = (SR[ra] & ~1) >> 1;
|
||||
if (SR[ra] == 0)
|
||||
|
||||
@@ -36,7 +36,7 @@ m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibra
|
||||
if (*pLibHandle == NULL)
|
||||
{
|
||||
char *pchErrMsg;
|
||||
DWORD dwErr = GetLastError();
|
||||
DWORD dwErr = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL);
|
||||
fprintf(stderr, "LoadLibrary('%s') error: %s\n", pccLibraryPath, pchErrMsg);
|
||||
@@ -62,7 +62,7 @@ m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle)
|
||||
if (rval == 0)
|
||||
{
|
||||
char *pchErrMsg;
|
||||
DWORD dwErr = GetLastError();
|
||||
DWORD dwErr = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL);
|
||||
fprintf(stderr, "FreeLibrary() error: %s\n", pchErrMsg);
|
||||
|
||||
+11
-11
@@ -121,16 +121,9 @@ ifeq ("$(CPU)","NONE")
|
||||
$(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'https://github.com/mupen64plus/mupen64plus-core/issues')
|
||||
endif
|
||||
|
||||
# base CFLAGS, LDLIBS, and LDFLAGS
|
||||
OPTFLAGS ?= -O3 -flto
|
||||
WARNFLAGS ?= -Wall
|
||||
CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -fvisibility=hidden -I$(SRCDIR)
|
||||
CPPFLAGS += -DM64P_PLUGIN_API
|
||||
LDFLAGS += $(SHARED)
|
||||
|
||||
ifeq ($(CPU), X86)
|
||||
SSE ?= SSE2
|
||||
ifeq ($(SSE), SSE2)
|
||||
ifeq ("$(SSE)", "SSE2")
|
||||
CFLAGS += -msse2
|
||||
CPPFLAGS += -DARCH_MIN_SSE2
|
||||
POSTFIX = -sse2
|
||||
@@ -138,6 +131,16 @@ ifeq ($(CPU), X86)
|
||||
CFLAGS += -mstackrealign
|
||||
endif
|
||||
|
||||
SRCDIR = ../../
|
||||
OBJDIR = _obj$(POSTFIX)
|
||||
|
||||
# base CFLAGS, LDLIBS, and LDFLAGS
|
||||
OPTFLAGS ?= -O3 -flto
|
||||
WARNFLAGS ?= -Wall
|
||||
CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -fvisibility=hidden -I$(SRCDIR)
|
||||
CPPFLAGS += -DM64P_PLUGIN_API
|
||||
LDFLAGS += $(SHARED)
|
||||
|
||||
ifeq ($(NEON), 1)
|
||||
CFLAGS += -mfpu=neon
|
||||
CPPFLAGS += -DUSE_SSE2NEON
|
||||
@@ -265,9 +268,6 @@ ifeq ($(PLUGINDIR),)
|
||||
PLUGINDIR := $(LIBDIR)/mupen64plus
|
||||
endif
|
||||
|
||||
SRCDIR = ../../
|
||||
OBJDIR = _obj$(POSTFIX)
|
||||
|
||||
# list of source files to compile
|
||||
SOURCE = \
|
||||
$(SRCDIR)/su.c \
|
||||
|
||||
+4
-6
@@ -234,7 +234,8 @@ void SP_DMA_READ(void)
|
||||
i = 0;
|
||||
--count;
|
||||
do {
|
||||
offC = (count*length + *CR[0x0] + i) & 0x00001FF8ul;
|
||||
offC = ((count*length + *CR[0x0] + i) & 0x00000FF8ul)
|
||||
| (*CR[0x0] & 0x00001000ul);
|
||||
offD = (count*skip + *CR[0x1] + i) & 0x00FFFFF8ul;
|
||||
i += 0x008;
|
||||
if (offD > su_max_address) {
|
||||
@@ -245,8 +246,6 @@ void SP_DMA_READ(void)
|
||||
} while (i < length);
|
||||
} while (count);
|
||||
|
||||
if ((*CR[0x0] ^ offC) & 0x1000)
|
||||
message("DMA over the DMEM-to-IMEM gap.");
|
||||
GET_RCP_REG(SP_DMA_BUSY_REG) = 0x00000000;
|
||||
GET_RCP_REG(SP_STATUS_REG) &= ~SP_STATUS_DMA_BUSY;
|
||||
return;
|
||||
@@ -274,7 +273,8 @@ void SP_DMA_WRITE(void)
|
||||
i = 0;
|
||||
--count;
|
||||
do {
|
||||
offC = (count*length + *CR[0x0] + i) & 0x00001FF8ul;
|
||||
offC = ((count*length + *CR[0x0] + i) & 0x00000FF8ul)
|
||||
| (*CR[0x0] & 0x00001000ul);
|
||||
offD = (count*skip + *CR[0x1] + i) & 0x00FFFFF8ul;
|
||||
i += 0x000008;
|
||||
if (offD > su_max_address)
|
||||
@@ -283,8 +283,6 @@ void SP_DMA_WRITE(void)
|
||||
} while (i < length);
|
||||
} while (count);
|
||||
|
||||
if ((*CR[0x0] ^ offC) & 0x1000)
|
||||
message("DMA over the DMEM-to-IMEM gap.");
|
||||
GET_RCP_REG(SP_DMA_BUSY_REG) = 0x00000000;
|
||||
GET_RCP_REG(SP_STATUS_REG) &= ~SP_STATUS_DMA_BUSY;
|
||||
return;
|
||||
|
||||
@@ -110,11 +110,6 @@ void DisplayWindow::closeWindow()
|
||||
m_bToggleFullscreen = false;
|
||||
}
|
||||
|
||||
void DisplayWindow::setInitialWindowSize(u32 width, u32 height)
|
||||
{
|
||||
m_initialWidth = width;
|
||||
m_initialHeight = height;
|
||||
}
|
||||
|
||||
void DisplayWindow::setWindowSize(u32 _width, u32 _height)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,6 @@ public:
|
||||
bool changeWindow();
|
||||
bool resizeWindow();
|
||||
void closeWindow();
|
||||
void setInitialWindowSize(u32 width, u32 height);
|
||||
void setWindowSize(u32 _width, u32 _height);
|
||||
void setCaptureScreen(const char * const _strDirectory);
|
||||
void setToggleFullscreen() { m_bToggleFullscreen = true; }
|
||||
@@ -56,8 +55,6 @@ protected:
|
||||
bool m_bAdjustScreen = false;
|
||||
|
||||
u32 m_buffersSwapCount = 0;
|
||||
u32 m_initialWidth = 0;
|
||||
u32 m_initialHeight = 0;
|
||||
u32 m_width = 0;
|
||||
u32 m_height = 0;
|
||||
u32 m_heightOffset = 0;
|
||||
|
||||
+9
-8
@@ -90,8 +90,8 @@ bool DisplayWindowMupen64plus::_start()
|
||||
_setAttributes();
|
||||
|
||||
m_bFullscreen = config.video.fullscreen > 0;
|
||||
m_screenWidth = m_initialWidth > 0 ? m_initialWidth : config.video.windowedWidth;
|
||||
m_screenHeight = m_initialHeight > 0 ? m_initialHeight : config.video.windowedHeight;
|
||||
m_screenWidth = config.video.windowedWidth;
|
||||
m_screenHeight = config.video.windowedHeight;
|
||||
m_screenRefresh = config.video.fullscreenRefresh;
|
||||
|
||||
_getDisplaySize();
|
||||
@@ -252,6 +252,11 @@ void DisplayWindowMupen64plus::_readScreen2(void * _dest, int * _width, int * _h
|
||||
if (_dest == nullptr)
|
||||
return;
|
||||
|
||||
u8 *pBufferData = (u8*)malloc((*_width)*(*_height) * 4);
|
||||
if (pBufferData == nullptr)
|
||||
return;
|
||||
u8 *pDest = (u8*)_dest;
|
||||
|
||||
#if !defined(OS_ANDROID) && !defined(OS_IOS)
|
||||
GLint oldMode;
|
||||
glGetIntegerv(GL_READ_BUFFER, &oldMode);
|
||||
@@ -260,7 +265,7 @@ void DisplayWindowMupen64plus::_readScreen2(void * _dest, int * _width, int * _h
|
||||
glReadBuffer(GL_FRONT);
|
||||
else
|
||||
glReadBuffer(GL_BACK);
|
||||
glReadPixels(0, m_heightOffset, m_screenWidth, m_screenHeight, GL_RGB, GL_UNSIGNED_BYTE, _dest);
|
||||
glReadPixels(0, m_heightOffset, m_screenWidth, m_screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, pBufferData);
|
||||
if (graphics::BufferAttachmentParam(oldMode) == graphics::bufferAttachment::COLOR_ATTACHMENT0) {
|
||||
FrameBuffer * pBuffer = frameBufferList().getCurrent();
|
||||
if (pBuffer != nullptr)
|
||||
@@ -268,11 +273,8 @@ void DisplayWindowMupen64plus::_readScreen2(void * _dest, int * _width, int * _h
|
||||
}
|
||||
glReadBuffer(oldMode);
|
||||
#else
|
||||
u8 *pBufferData = (u8*)malloc((*_width)*(*_height) * 4);
|
||||
if (pBufferData == nullptr)
|
||||
return;
|
||||
u8 *pDest = (u8*)_dest;
|
||||
glReadPixels(0, m_heightOffset, m_screenWidth, m_screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, pBufferData);
|
||||
#endif
|
||||
|
||||
//Convert RGBA to RGB
|
||||
for (s32 y = 0; y < *_height; ++y) {
|
||||
@@ -287,7 +289,6 @@ void DisplayWindowMupen64plus::_readScreen2(void * _dest, int * _width, int * _h
|
||||
}
|
||||
|
||||
free(pBufferData);
|
||||
#endif
|
||||
}
|
||||
|
||||
graphics::ObjectHandle DisplayWindowMupen64plus::_getDefaultFramebuffer()
|
||||
|
||||
@@ -57,11 +57,6 @@ EXPORT void CALL SetRenderingCallback(void (*callback)(int))
|
||||
api().SetRenderingCallback(callback);
|
||||
}
|
||||
|
||||
EXPORT void CALL SetInitialVideoSize(int width, int height)
|
||||
{
|
||||
api().SetInitialVideoSize(width, height);
|
||||
}
|
||||
|
||||
EXPORT void CALL ResizeVideoOutput(int width, int height)
|
||||
{
|
||||
api().ResizeVideoOutput(width, height);
|
||||
|
||||
@@ -80,9 +80,6 @@ public:
|
||||
void FBGetFrameBufferInfo(void *pinfo);
|
||||
#else
|
||||
// MupenPlus
|
||||
#ifdef M64P_GLIDENUI
|
||||
void SetInitialVideoSize(int width, int height);
|
||||
#endif
|
||||
void ResizeVideoOutput(int _Width, int _Height);
|
||||
void ReadScreen2(void * _dest, int * _width, int * _height, int _front);
|
||||
|
||||
|
||||
@@ -166,13 +166,6 @@ void PluginAPI::SetRenderingCallback(void (*callback)(int))
|
||||
renderCallback = callback;
|
||||
}
|
||||
|
||||
#ifdef M64P_GLIDENUI
|
||||
void PluginAPI::SetInitialVideoSize(int width, int height)
|
||||
{
|
||||
dwnd().setInitialWindowSize(width, height);
|
||||
}
|
||||
#endif
|
||||
|
||||
void PluginAPI::ResizeVideoOutput(int _Width, int _Height)
|
||||
{
|
||||
dwnd().setWindowSize(_Width, _Height);
|
||||
|
||||
@@ -16,7 +16,6 @@ ViStatusChanged;
|
||||
ViWidthChanged;
|
||||
ReadScreen2;
|
||||
SetRenderingCallback;
|
||||
SetInitialVideoSize;
|
||||
ResizeVideoOutput;
|
||||
FBRead;
|
||||
FBWrite;
|
||||
|
||||
-9
@@ -68,9 +68,6 @@ extern int32_t win_width;
|
||||
extern int32_t win_height;
|
||||
extern int32_t win_fullscreen;
|
||||
|
||||
extern int32_t init_win_width;
|
||||
extern int32_t init_win_height;
|
||||
|
||||
EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle _CoreLibHandle, void *Context,
|
||||
void (*DebugCallback)(void *, int, const char *))
|
||||
{
|
||||
@@ -172,12 +169,6 @@ extern "C"
|
||||
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
EXPORT void CALL SetInitialVideoSize(int width, int height)
|
||||
{
|
||||
init_win_width = width;
|
||||
init_win_height = height;
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT int CALL InitiateGFX (GFX_INFO Gfx_Info)
|
||||
|
||||
-5
@@ -23,8 +23,6 @@ static ptr_VidExt_GL_GetAttribute CoreVideo_GL_GetAttribute = NULL;
|
||||
static ptr_VidExt_GL_SwapBuffers CoreVideo_GL_SwapBuffers = NULL;
|
||||
|
||||
// framebuffer texture states
|
||||
int32_t init_win_width = 0;
|
||||
int32_t init_win_height = 0;
|
||||
int32_t win_width;
|
||||
int32_t win_height;
|
||||
int32_t win_fullscreen;
|
||||
@@ -64,9 +62,6 @@ void screen_init(struct n64video_config* config)
|
||||
|
||||
CoreVideo_GL_SetAttribute(M64P_GL_SWAP_CONTROL, config->vi.vsync);
|
||||
|
||||
win_width = init_win_width > 0 ? init_win_width : win_width;
|
||||
win_height = init_win_height > 0 ? init_win_height : win_height;
|
||||
|
||||
CoreVideo_SetVideoMode(win_width, win_height, 0, win_fullscreen ? M64VIDEO_FULLSCREEN : M64VIDEO_WINDOWED, M64VIDEOFLAG_SUPPORT_RESIZING);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,10 +71,6 @@ m64p_handle configVideoParallel = NULL;
|
||||
uint32_t rdram_size;
|
||||
static ptr_PluginGetVersion CoreGetVersion = NULL;
|
||||
|
||||
static int initialWidth = 0;
|
||||
static int initialHeight = 0;
|
||||
static bool initialSizeSet = false;
|
||||
|
||||
void plugin_init(void)
|
||||
{
|
||||
CoreGetVersion = (ptr_PluginGetVersion)DLSYM(CoreLibHandle, "PluginGetVersion");
|
||||
@@ -272,13 +268,6 @@ extern "C"
|
||||
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
EXPORT void CALL SetInitialVideoSize(int width, int height)
|
||||
{
|
||||
initialWidth = width;
|
||||
initialHeight = height;
|
||||
initialSizeSet = true;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_GUI
|
||||
|
||||
@@ -337,12 +326,6 @@ EXPORT int CALL RomOpen(void)
|
||||
vk_ssreadbacks = 0; // can cause desyncs
|
||||
}
|
||||
|
||||
if (initialSizeSet)
|
||||
{
|
||||
window_width = initialWidth;
|
||||
window_height = initialHeight;
|
||||
}
|
||||
|
||||
plugin_init();
|
||||
|
||||
if (vk_init())
|
||||
@@ -364,8 +347,6 @@ EXPORT void CALL RomClosed(void)
|
||||
{
|
||||
vk_destroy();
|
||||
}
|
||||
|
||||
initialSizeSet = false;
|
||||
}
|
||||
|
||||
EXPORT void CALL ShowCFB(void)
|
||||
|
||||
@@ -88,7 +88,7 @@ static void sdl_init_audio_device(struct sdl_backend* sdl_backend)
|
||||
{
|
||||
if (!SDL_Init(SDL_INIT_AUDIO))
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to initialize SDL audio subsystem.");
|
||||
DebugMessage(M64MSG_ERROR, "Failed to initialize SDL audio subsystem: %s", SDL_GetError());
|
||||
sdl_backend->error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <3rdParty/lzma/7z.h>
|
||||
|
||||
// minizip includes
|
||||
#include <unzip.h>
|
||||
#include <minizip/unzip.h>
|
||||
#ifndef ZNGLIB_H_
|
||||
/* sadly older minizip-ng versions didn't include zlib.h automatically,
|
||||
* so i.e voidpf would be undefined, in newer minizip-ng versions,
|
||||
|
||||
@@ -511,17 +511,6 @@ CORE_EXPORT bool CorePluginsOpenROMConfig(CorePluginType type, void* parent, std
|
||||
return open_plugin_config(type, parent, true, file);
|
||||
}
|
||||
|
||||
CORE_EXPORT void CoreSetInitialVideoSize(int width, int height)
|
||||
{
|
||||
m64p::PluginApi& plugin = get_plugin(CorePluginType::Gfx);
|
||||
if (!plugin.IsHooked() || plugin.SetInitialVideoSize == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.SetInitialVideoSize(width, height);
|
||||
}
|
||||
|
||||
CORE_EXPORT bool CoreAttachPlugins(void)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
@@ -62,9 +62,6 @@ bool CorePluginsHasROMConfig(CorePluginType type);
|
||||
// used plugin of given type
|
||||
bool CorePluginsOpenROMConfig(CorePluginType type, void* parent = nullptr, std::filesystem::path file = "");
|
||||
|
||||
// sets initial video size for the video plugin
|
||||
void CoreSetInitialVideoSize(int width, int height);
|
||||
|
||||
// attaches all used plugins
|
||||
bool CoreAttachPlugins(void);
|
||||
|
||||
|
||||
@@ -170,9 +170,6 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::Netplay_ServerJsonUrl:
|
||||
setting = {SETTING_SECTION_NETPLAY, "ServerJsonUrl", std::string("")};
|
||||
break;
|
||||
case SettingsID::Netplay_DispatcherUrl:
|
||||
setting = {SETTING_SECTION_NETPLAY, "DispatcherUrl", std::string("https://dispatch.gopher64.com")};
|
||||
break;
|
||||
case SettingsID::Netplay_SelectedServer:
|
||||
setting = {SETTING_SECTION_NETPLAY, "SelectedServer", std::string("")};
|
||||
break;
|
||||
|
||||
@@ -45,7 +45,6 @@ enum class SettingsID
|
||||
// Netplay Settings
|
||||
Netplay_Nickname,
|
||||
Netplay_ServerJsonUrl,
|
||||
Netplay_DispatcherUrl,
|
||||
Netplay_SelectedServer,
|
||||
|
||||
// Core Plugin Settings
|
||||
|
||||
@@ -29,7 +29,6 @@ bool PluginApi::Hook(m64p_dynlib_handle handle)
|
||||
HOOK_FUNC(handle, Plugin, Shutdown);
|
||||
HOOK_FUNC_OPT(handle, Plugin, Config);
|
||||
HOOK_FUNC_OPT(handle, Plugin, ConfigWithRomConfig);
|
||||
HOOK_FUNC_OPT(handle, , SetInitialVideoSize);
|
||||
HOOK_FUNC(handle, Plugin, GetVersion);
|
||||
|
||||
this->handle = handle;
|
||||
@@ -43,7 +42,6 @@ bool PluginApi::Unhook(void)
|
||||
UNHOOK_FUNC(Plugin, Shutdown);
|
||||
UNHOOK_FUNC(Plugin, Config);
|
||||
UNHOOK_FUNC(Plugin, ConfigWithRomConfig);
|
||||
UNHOOK_FUNC(Plugin, SetInitialVideoSize);
|
||||
UNHOOK_FUNC(Plugin, GetVersion);
|
||||
|
||||
this->handle = nullptr;
|
||||
|
||||
@@ -37,7 +37,6 @@ class PluginApi
|
||||
ptr_PluginShutdown Shutdown;
|
||||
ptr_PluginConfig Config;
|
||||
ptr_PluginConfigWithRomConfig ConfigWithRomConfig;
|
||||
ptr_SetInitialVideoSize SetInitialVideoSize;
|
||||
ptr_PluginGetVersion GetVersion;
|
||||
|
||||
private:
|
||||
|
||||
@@ -39,17 +39,6 @@ typedef m64p_error (*ptr_PluginConfigWithRomConfig)(void*, int, CoreRomHeader*,
|
||||
EXPORT m64p_error CALL PluginConfigWithRomConfig(void*, int, CoreRomHeader*, CoreRomSettings*);
|
||||
#endif
|
||||
|
||||
/* SetInitialVideoSize(int width, int height)
|
||||
*
|
||||
* This optional function allows a front-end to set the initial video
|
||||
* size for a video plugin.
|
||||
*
|
||||
*/
|
||||
typedef void (*ptr_SetInitialVideoSize)(int width, int height);
|
||||
#if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES)
|
||||
EXPORT void CALL SetInitialVideoSize(int width, int height);
|
||||
#endif
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "EmulationThread.hpp"
|
||||
|
||||
#include <RMG-Core/Emulation.hpp>
|
||||
#include <RMG-Core/Plugins.hpp>
|
||||
#include <RMG-Core/Error.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -55,19 +54,12 @@ void EmulationThread::SetNetplay(QString address, int port, int player)
|
||||
this->player = player;
|
||||
}
|
||||
|
||||
void EmulationThread::SetVideoSize(int width, int height)
|
||||
{
|
||||
this->videoSize = QSize(width, height);
|
||||
}
|
||||
|
||||
void EmulationThread::run(void)
|
||||
{
|
||||
this->inhibitScreensaver();
|
||||
|
||||
emit this->on_Emulation_Started();
|
||||
|
||||
CoreSetInitialVideoSize(this->videoSize.width(), this->videoSize.height());
|
||||
|
||||
bool ret = CoreStartEmulation(this->rom.toStdU32String(), this->disk.toStdU32String(),
|
||||
this->address.toStdString(), this->port, this->player);
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <QSurfaceFormat>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QSize>
|
||||
|
||||
enum class VidExtRenderMode
|
||||
{
|
||||
@@ -38,7 +37,6 @@ class EmulationThread : public QThread
|
||||
void SetRomFile(QString);
|
||||
void SetDiskFile(QString);
|
||||
void SetNetplay(QString address, int port, int player);
|
||||
void SetVideoSize(int width, int height);
|
||||
|
||||
void run(void) override;
|
||||
|
||||
@@ -48,7 +46,6 @@ class EmulationThread : public QThread
|
||||
QString address;
|
||||
int port = -1;
|
||||
int player = -1;
|
||||
QSize videoSize;
|
||||
#ifndef _WIN32
|
||||
uint32_t dbusCookieId = 0;
|
||||
QDBusInterface* dbusInterface = nullptr;
|
||||
|
||||
@@ -41,7 +41,6 @@ CreateNetplaySessionDialog::CreateNetplaySessionDialog(QWidget *parent, QWebSock
|
||||
this->webSocket = webSocket;
|
||||
connect(this->webSocket, &QWebSocket::textMessageReceived, this, &CreateNetplaySessionDialog::on_webSocket_textMessageReceived);
|
||||
connect(this->webSocket, &QWebSocket::pong, this, &CreateNetplaySessionDialog::on_webSocket_pong);
|
||||
connect(this->webSocket, &QWebSocket::connected, this, &CreateNetplaySessionDialog::on_webSocket_connected);
|
||||
|
||||
// prepare broadcast
|
||||
broadcastSocket.bind(QHostAddress(QHostAddress::AnyIPv4), 0);
|
||||
@@ -104,18 +103,6 @@ CreateNetplaySessionDialog::CreateNetplaySessionDialog(QWidget *parent, QWebSock
|
||||
networkAccessManager->get(QNetworkRequest(QUrl(serverUrl)));
|
||||
}
|
||||
}
|
||||
|
||||
QString dispatcherUrl = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_DispatcherUrl));
|
||||
if (!dispatcherUrl.isEmpty() && QUrl(dispatcherUrl).isValid())
|
||||
{
|
||||
this->dispatcherUrl = dispatcherUrl;
|
||||
|
||||
QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
|
||||
connect(networkAccessManager, &QNetworkAccessManager::finished, this, &CreateNetplaySessionDialog::on_dispatcherRegionListDownload_Finished);
|
||||
networkAccessManager->setTransferTimeout(15000);
|
||||
|
||||
networkAccessManager->get(NetplayCommon::GetNetworkRequest(this->dispatcherUrl + "/getRegions"));
|
||||
}
|
||||
}
|
||||
|
||||
CreateNetplaySessionDialog::~CreateNetplaySessionDialog(void)
|
||||
@@ -254,18 +241,7 @@ void CreateNetplaySessionDialog::on_webSocket_textMessageReceived(QString messag
|
||||
|
||||
void CreateNetplaySessionDialog::on_webSocket_pong(quint64 elapsedTime, const QByteArray&)
|
||||
{
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->pingLineEdit->setText(QString::number(elapsedTime) + " ms");
|
||||
}
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_webSocket_connected()
|
||||
{
|
||||
if (NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->createSession();
|
||||
}
|
||||
this->pingLineEdit->setText(QString::number(elapsedTime) + " ms");
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_broadcastSocket_readyRead()
|
||||
@@ -296,49 +272,6 @@ void CreateNetplaySessionDialog::on_jsonServerListDownload_Finished(QNetworkRepl
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_dispatcherRegionListDownload_Finished(QNetworkReply* reply)
|
||||
{
|
||||
if (reply->error())
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", "Failed to retrieve region list: " + reply->errorString());
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
NetplayCommon::AddServers(this->serverComboBox,
|
||||
QJsonDocument::fromJson(reply->readAll()), true);
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_dispatcherServerCreate_Finished(QNetworkReply* reply)
|
||||
{
|
||||
if (reply->error())
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", "Failed to create server: " + reply->errorString());
|
||||
reply->deleteLater();
|
||||
this->toggleUI(true, this->validate());
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(reply->readAll());
|
||||
QJsonObject jsonObject = jsonDocument.object();
|
||||
|
||||
if (jsonObject.empty() || jsonObject.keys().empty())
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", "Failed to create server: " + jsonDocument.toJson());
|
||||
reply->deleteLater();
|
||||
this->toggleUI(true, this->validate());
|
||||
return;
|
||||
}
|
||||
|
||||
// first item should be an address
|
||||
QString address = jsonObject[jsonObject.keys().at(0)].toString();
|
||||
this->webSocket->open(QUrl(address));
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_serverComboBox_currentIndexChanged(int index)
|
||||
{
|
||||
if (index == -1)
|
||||
@@ -346,23 +279,18 @@ void CreateNetplaySessionDialog::on_serverComboBox_currentIndexChanged(int index
|
||||
return;
|
||||
}
|
||||
|
||||
bool dispatcher = NetplayCommon::IsServerDispatcher(this->serverComboBox, index);
|
||||
|
||||
if (this->pingTimerId != -1)
|
||||
{
|
||||
this->killTimer(this->pingTimerId);
|
||||
this->pingTimerId = -1;
|
||||
}
|
||||
|
||||
this->pingLineEdit->setText(dispatcher ? "N/A" : "Calculating...");
|
||||
this->pingLineEdit->setText("Calculating...");
|
||||
|
||||
if (!dispatcher)
|
||||
{
|
||||
this->pingTimerId = this->startTimer(2000);
|
||||
this->pingTimerId = this->startTimer(2000);
|
||||
|
||||
QString address = NetplayCommon::GetServerData(this->serverComboBox, index);
|
||||
this->webSocket->open(QUrl(address));
|
||||
}
|
||||
QString address = NetplayCommon::GetServerData(this->serverComboBox, index);
|
||||
this->webSocket->open(QUrl(address));
|
||||
}
|
||||
|
||||
void CreateNetplaySessionDialog::on_nickNameLineEdit_textChanged(void)
|
||||
@@ -387,7 +315,7 @@ void CreateNetplaySessionDialog::on_romListWidget_OnRomChanged(bool valid)
|
||||
|
||||
void CreateNetplaySessionDialog::accept()
|
||||
{
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox) && !this->webSocket->isValid())
|
||||
if (!this->webSocket->isValid())
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", "Connection Failed");
|
||||
return;
|
||||
@@ -407,26 +335,5 @@ void CreateNetplaySessionDialog::accept()
|
||||
// disable create button while we're processing the request
|
||||
this->toggleUI(false, false);
|
||||
|
||||
if (NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
|
||||
connect(networkAccessManager, &QNetworkAccessManager::finished, this, &CreateNetplaySessionDialog::on_dispatcherServerCreate_Finished);
|
||||
networkAccessManager->setTransferTimeout(120000);
|
||||
|
||||
QUrl url(this->dispatcherUrl + "/createServer");
|
||||
|
||||
QUrlQuery urlQuery;
|
||||
urlQuery.addQueryItem("region", NetplayCommon::GetServerData(this->serverComboBox));
|
||||
url.setQuery(urlQuery);
|
||||
|
||||
networkAccessManager->get(NetplayCommon::GetNetworkRequest(url));
|
||||
|
||||
// creating a server can take a while,
|
||||
// so show a loading screen
|
||||
this->romListWidget->ShowLoading();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->createSession();
|
||||
}
|
||||
this->createSession();
|
||||
}
|
||||
|
||||
@@ -48,8 +48,6 @@ class CreateNetplaySessionDialog : public QDialog, private Ui::CreateNetplaySess
|
||||
QString sessionMD5;
|
||||
QString sessionGoodName;
|
||||
|
||||
QString dispatcherUrl;
|
||||
|
||||
QString getGameName(QString goodName, QString file);
|
||||
|
||||
bool validate(void);
|
||||
@@ -65,12 +63,9 @@ class CreateNetplaySessionDialog : public QDialog, private Ui::CreateNetplaySess
|
||||
private slots:
|
||||
void on_webSocket_textMessageReceived(QString message);
|
||||
void on_webSocket_pong(quint64 elapsedTime, const QByteArray&);
|
||||
void on_webSocket_connected(void);
|
||||
void on_broadcastSocket_readyRead(void);
|
||||
|
||||
void on_jsonServerListDownload_Finished(QNetworkReply* reply);
|
||||
void on_dispatcherRegionListDownload_Finished(QNetworkReply* reply);
|
||||
void on_dispatcherServerCreate_Finished(QNetworkReply* reply);
|
||||
|
||||
void on_serverComboBox_currentIndexChanged(int index);
|
||||
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
|
||||
using namespace NetplayCommon;
|
||||
|
||||
// register type with qt
|
||||
Q_DECLARE_METATYPE(NetplayServerData);
|
||||
|
||||
void NetplayCommon::AddCommonJson(QJsonObject& json)
|
||||
{
|
||||
QCryptographicHash hash = QCryptographicHash(QCryptographicHash::Sha256);
|
||||
@@ -87,36 +84,14 @@ QList<QString> NetplayCommon::GetPluginNames(QString md5QString)
|
||||
return pluginNames;
|
||||
}
|
||||
|
||||
void NetplayCommon::AddServers(QComboBox* comboBox, const QJsonDocument& document, bool dispatcher)
|
||||
void NetplayCommon::AddServers(QComboBox* comboBox, const QJsonDocument& document)
|
||||
{
|
||||
if (dispatcher)
|
||||
{
|
||||
QJsonArray jsonServers = document.array();
|
||||
QJsonObject jsonObject = document.object();
|
||||
QStringList jsonServers = jsonObject.keys();
|
||||
|
||||
for (int i = 0; i < jsonServers.size(); i++)
|
||||
{
|
||||
comboBox->addItem(jsonServers.at(i).toString(),
|
||||
QVariant::fromValue<NetplayServerData>(
|
||||
{
|
||||
dispatcher,
|
||||
jsonServers.at(i).toString()
|
||||
}));
|
||||
}
|
||||
}
|
||||
else
|
||||
for (int i = 0; i < jsonServers.size(); i++)
|
||||
{
|
||||
QJsonObject jsonObject = document.object();
|
||||
QStringList jsonServers = jsonObject.keys();
|
||||
|
||||
for (int i = 0; i < jsonServers.size(); i++)
|
||||
{
|
||||
comboBox->addItem(jsonServers.at(i),
|
||||
QVariant::fromValue<NetplayServerData>(
|
||||
{
|
||||
dispatcher,
|
||||
jsonObject.value(jsonServers.at(i)).toString()
|
||||
}));
|
||||
}
|
||||
comboBox->addItem(jsonServers.at(i), jsonObject.value(jsonServers.at(i)).toString());
|
||||
}
|
||||
|
||||
NetplayCommon::RestoreSelectedServer(comboBox);
|
||||
@@ -137,16 +112,6 @@ void NetplayCommon::RestoreSelectedServer(QComboBox* comboBox)
|
||||
}
|
||||
}
|
||||
|
||||
bool NetplayCommon::IsServerDispatcher(QComboBox* comboBox, int index)
|
||||
{
|
||||
if (index == -1)
|
||||
{
|
||||
index = comboBox->currentIndex();
|
||||
}
|
||||
|
||||
return comboBox->itemData(index).value<NetplayServerData>().Dispatcher;
|
||||
}
|
||||
|
||||
QString NetplayCommon::GetServerData(QComboBox* comboBox, int index)
|
||||
{
|
||||
if (index == -1)
|
||||
@@ -154,7 +119,7 @@ QString NetplayCommon::GetServerData(QComboBox* comboBox, int index)
|
||||
index = comboBox->currentIndex();
|
||||
}
|
||||
|
||||
return comboBox->itemData(index).value<NetplayServerData>().Data;
|
||||
return comboBox->itemData(index).toString();
|
||||
}
|
||||
|
||||
QNetworkRequest NetplayCommon::GetNetworkRequest(QUrl url)
|
||||
|
||||
@@ -22,12 +22,6 @@
|
||||
|
||||
namespace NetplayCommon
|
||||
{
|
||||
struct NetplayServerData
|
||||
{
|
||||
bool Dispatcher;
|
||||
QString Data;
|
||||
};
|
||||
|
||||
#define NETPLAYCOMMON_SESSION_REGEX "[a-zA-Z0-9 ]+"
|
||||
#define NETPLAYCOMMON_NICKNAME_REGEX "[a-zA-Z0-9]+"
|
||||
#define NETPLAYCOMMON_PASSWORD_REGEX "[a-zA-Z0-9,.\\/<>?;:[\\]{}\\-=_+`~!@#$%^&*()]+"
|
||||
@@ -39,14 +33,11 @@ namespace NetplayCommon
|
||||
QList<QString> GetPluginNames(QString md5QString);
|
||||
|
||||
// Adds servers from json to combobox
|
||||
void AddServers(QComboBox* comboBox, const QJsonDocument& document, bool dispatcher = false);
|
||||
void AddServers(QComboBox* comboBox, const QJsonDocument& document);
|
||||
|
||||
// Restores previously selected server
|
||||
void RestoreSelectedServer(QComboBox* comboBox);
|
||||
|
||||
// Returns whether server from comboBox is dispatcher
|
||||
bool IsServerDispatcher(QComboBox* comboBox, int index = -1);
|
||||
|
||||
// Returns server data from comboBox
|
||||
QString GetServerData(QComboBox* comboBox, int index = -1);
|
||||
|
||||
|
||||
@@ -71,11 +71,6 @@ NetplaySessionBrowserDialog::NetplaySessionBrowserDialog(QWidget *parent, QWebSo
|
||||
this->nickNameLineEdit->setValidator(new QRegularExpressionValidator(re, this));
|
||||
this->nickNameLineEdit->setText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_Nickname)));
|
||||
|
||||
// configure dispatcher network access manager
|
||||
this->dispatcherNetworkAccessManager = new QNetworkAccessManager(this);
|
||||
this->dispatcherNetworkAccessManager->setTransferTimeout(15000);
|
||||
connect(this->dispatcherNetworkAccessManager, &QNetworkAccessManager::finished, this, &NetplaySessionBrowserDialog::on_dispatcherRetrieveServers_Finished);
|
||||
|
||||
// request server list
|
||||
QString serverUrl = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_ServerJsonUrl));
|
||||
if (!serverUrl.isEmpty())
|
||||
@@ -102,18 +97,6 @@ NetplaySessionBrowserDialog::NetplaySessionBrowserDialog(QWidget *parent, QWebSo
|
||||
}
|
||||
}
|
||||
|
||||
QString dispatcherUrl = QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_DispatcherUrl));
|
||||
if (!dispatcherUrl.isEmpty() && QUrl(dispatcherUrl).isValid())
|
||||
{
|
||||
this->dispatcherUrl = dispatcherUrl;
|
||||
|
||||
QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager(this);
|
||||
connect(networkAccessManager, &QNetworkAccessManager::finished, this, &NetplaySessionBrowserDialog::on_dispatcherRegionListDownload_Finished);
|
||||
networkAccessManager->setTransferTimeout(15000);
|
||||
|
||||
networkAccessManager->get(NetplayCommon::GetNetworkRequest(this->dispatcherUrl + "/getRegions"));
|
||||
}
|
||||
|
||||
this->validateJoinButton();
|
||||
}
|
||||
|
||||
@@ -215,14 +198,7 @@ void NetplaySessionBrowserDialog::refreshSessions(void)
|
||||
// disable join and refresh button while refreshing
|
||||
this->toggleUI(false, false, false);
|
||||
|
||||
if (NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->on_serverComboBox_currentIndexChanged(this->serverComboBox->currentIndex());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->on_webSocket_connected();
|
||||
}
|
||||
this->on_webSocket_connected();
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::joinSession(void)
|
||||
@@ -241,31 +217,6 @@ void NetplaySessionBrowserDialog::joinSession(void)
|
||||
this->webSocket->sendTextMessage(QJsonDocument(json).toJson());
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::resetDispatcherState(void)
|
||||
{
|
||||
if (this->dispatcherTimerId != -1)
|
||||
{
|
||||
this->killTimer(this->dispatcherTimerId);
|
||||
this->dispatcherTimerId = -1;
|
||||
}
|
||||
|
||||
if (this->dispatcherTimeoutTimerId != -1)
|
||||
{
|
||||
this->killTimer(this->dispatcherTimeoutTimerId);
|
||||
this->dispatcherTimeoutTimerId = -1;
|
||||
}
|
||||
|
||||
if (this->dispatcherNetworkReply != nullptr)
|
||||
{
|
||||
this->dispatcherNetworkReply->abort();
|
||||
this->dispatcherNetworkReply = nullptr;
|
||||
}
|
||||
|
||||
this->dispatcherMoveThroughList = false;
|
||||
this->dispatcherJoinSession = false;
|
||||
this->dispatcherAddressListIndex = false;
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == this->pingTimerId)
|
||||
@@ -275,44 +226,6 @@ void NetplaySessionBrowserDialog::timerEvent(QTimerEvent *event)
|
||||
this->webSocket->ping();
|
||||
}
|
||||
}
|
||||
else if (event->timerId() == this->dispatcherTimerId)
|
||||
{
|
||||
if (this->dispatcherMoveThroughList)
|
||||
{
|
||||
this->dispatcherAddressListIndex++;
|
||||
|
||||
if (this->dispatcherAddressListIndex < this->dispatcherAddressList.size())
|
||||
{
|
||||
QString address = this->dispatcherAddressList.at(this->dispatcherAddressListIndex);
|
||||
this->webSocket->open(QUrl(address));
|
||||
|
||||
this->dispatcherMoveThroughList = false;
|
||||
|
||||
// start socket timeout
|
||||
if (this->dispatcherTimeoutTimerId != -1)
|
||||
{
|
||||
this->killTimer(this->dispatcherTimeoutTimerId);
|
||||
this->dispatcherTimeoutTimerId = -1;
|
||||
}
|
||||
|
||||
this->dispatcherTimeoutTimerId = this->startTimer(15000);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->sessionBrowserWidget->RefreshDone();
|
||||
this->resetDispatcherState();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event->timerId() == this->dispatcherTimeoutTimerId)
|
||||
{
|
||||
this->webSocket->close();
|
||||
this->dispatcherMoveThroughList = true;
|
||||
|
||||
this->killTimer(this->dispatcherTimeoutTimerId);
|
||||
this->dispatcherTimeoutTimerId = -1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_webSocket_connected(void)
|
||||
@@ -323,20 +236,8 @@ void NetplaySessionBrowserDialog::on_webSocket_connected(void)
|
||||
return;
|
||||
}
|
||||
|
||||
bool dispatcher = NetplayCommon::IsServerDispatcher(this->serverComboBox);
|
||||
|
||||
if (dispatcher && this->dispatcherJoinSession)
|
||||
{
|
||||
this->joinSession();
|
||||
this->dispatcherJoinSession = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// clear sessions when we're not using the dispatcher server
|
||||
if (!dispatcher)
|
||||
{
|
||||
this->sessionBrowserWidget->StartRefresh();
|
||||
}
|
||||
// clear sessions
|
||||
this->sessionBrowserWidget->StartRefresh();
|
||||
|
||||
// request session list from server
|
||||
QJsonObject json;
|
||||
@@ -353,8 +254,6 @@ void NetplaySessionBrowserDialog::on_webSocket_textMessageReceived(QString messa
|
||||
|
||||
QString type = json.value("type").toString();
|
||||
|
||||
bool dispatcher = NetplayCommon::IsServerDispatcher(this->serverComboBox);
|
||||
|
||||
if (type == "reply_get_rooms")
|
||||
{
|
||||
if (json.value("accept").toInt() == 0)
|
||||
@@ -377,10 +276,7 @@ void NetplaySessionBrowserDialog::on_webSocket_textMessageReceived(QString messa
|
||||
}
|
||||
|
||||
// we're done refreshing the sessions
|
||||
if (!dispatcher)
|
||||
{
|
||||
this->sessionBrowserWidget->RefreshDone();
|
||||
}
|
||||
this->sessionBrowserWidget->RefreshDone();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -401,27 +297,16 @@ void NetplaySessionBrowserDialog::on_webSocket_textMessageReceived(QString messa
|
||||
this->toggleUI(true, this->validate());
|
||||
}
|
||||
}
|
||||
|
||||
if (dispatcher)
|
||||
{
|
||||
this->dispatcherMoveThroughList = true;
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_webSocket_pong(quint64 elapsedTime, const QByteArray&)
|
||||
{
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->pingLineEdit->setText(QString::number(elapsedTime) + " ms");
|
||||
}
|
||||
this->pingLineEdit->setText(QString::number(elapsedTime) + " ms");
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_webSocket_disconnected()
|
||||
{
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->sessionBrowserWidget->Reset();
|
||||
}
|
||||
this->sessionBrowserWidget->Reset();
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_broadcastSocket_readyRead(void)
|
||||
@@ -453,61 +338,6 @@ void NetplaySessionBrowserDialog::on_jsonServerListDownload_Finished(QNetworkRep
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_dispatcherRegionListDownload_Finished(QNetworkReply* reply)
|
||||
{
|
||||
if (reply->error())
|
||||
{
|
||||
this->sessionBrowserWidget->Reset();
|
||||
QtMessageBox::Error(this, "Server Error", "Failed to retrieve region list: " + reply->errorString());
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
NetplayCommon::AddServers(this->serverComboBox,
|
||||
QJsonDocument::fromJson(reply->readAll()), true);
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_dispatcherRetrieveServers_Finished(QNetworkReply* reply)
|
||||
{
|
||||
// don't show an error when the request has been aborted
|
||||
if (reply->error() == QNetworkReply::OperationCanceledError)
|
||||
{
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply->error())
|
||||
{
|
||||
this->sessionBrowserWidget->Reset();
|
||||
QtMessageBox::Error(this, "Server Error", "Failed to retrieve server list: " + reply->errorString());
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(reply->readAll());
|
||||
QJsonObject jsonObject = jsonDocument.object();
|
||||
QStringList jsonKeys = jsonObject.keys();
|
||||
|
||||
this->sessionBrowserWidget->StartRefresh();
|
||||
this->resetDispatcherState();
|
||||
|
||||
// we only care about the addresses
|
||||
this->dispatcherAddressList.clear();
|
||||
for (int i = 0; i < jsonKeys.size(); i++)
|
||||
{
|
||||
QString address = jsonObject[jsonKeys.at(i)].toString();
|
||||
this->dispatcherAddressList.append(address);
|
||||
}
|
||||
|
||||
this->dispatcherAddressListIndex = -1;
|
||||
this->dispatcherMoveThroughList = true;
|
||||
this->dispatcherTimerId = this->startTimer(250);
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_serverComboBox_currentIndexChanged(int index)
|
||||
{
|
||||
if (index == -1)
|
||||
@@ -518,47 +348,19 @@ void NetplaySessionBrowserDialog::on_serverComboBox_currentIndexChanged(int inde
|
||||
// disable join and refresh button while refreshing
|
||||
this->toggleUI(false, false, false);
|
||||
|
||||
bool dispatcher = NetplayCommon::IsServerDispatcher(this->serverComboBox, index);
|
||||
|
||||
if (this->pingTimerId != -1)
|
||||
{
|
||||
this->killTimer(this->pingTimerId);
|
||||
this->pingTimerId = -1;
|
||||
}
|
||||
|
||||
this->resetDispatcherState();
|
||||
this->pingLineEdit->setText(dispatcher ? "N/A" : "Calculating...");
|
||||
this->pingLineEdit->setText("Calculating...");
|
||||
this->sessionBrowserWidget->StartRefresh();
|
||||
|
||||
if (dispatcher)
|
||||
{
|
||||
QString region = NetplayCommon::GetServerData(this->serverComboBox, index);
|
||||
this->pingTimerId = this->startTimer(2000);
|
||||
|
||||
QUrl url(this->dispatcherUrl + "/getServers");
|
||||
|
||||
QUrlQuery urlQuery;
|
||||
urlQuery.addQueryItem("region", region);
|
||||
url.setQuery(urlQuery);
|
||||
|
||||
QNetworkRequest networkRequest = NetplayCommon::GetNetworkRequest(url);
|
||||
|
||||
// sadly we have to force HTTP/1 here due to a Qt bug,
|
||||
// we abort the connection which sadly in Qt6 causes an error and eventually segfault,
|
||||
// so to workaround this, force HTTP/1 until it's fixed in Qt6
|
||||
//
|
||||
// thank you MapLibre devs for figuring out this issue:
|
||||
// https://github.com/maplibre/maplibre-native/issues/3644
|
||||
networkRequest.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
|
||||
|
||||
this->dispatcherNetworkReply = this->dispatcherNetworkAccessManager->get(networkRequest);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->pingTimerId = this->startTimer(2000);
|
||||
|
||||
QString address = NetplayCommon::GetServerData(this->serverComboBox, index);
|
||||
this->webSocket->open(QUrl(address));
|
||||
}
|
||||
QString address = NetplayCommon::GetServerData(this->serverComboBox, index);
|
||||
this->webSocket->open(QUrl(address));
|
||||
}
|
||||
|
||||
void NetplaySessionBrowserDialog::on_sessionBrowserWidget_OnSessionChanged(bool valid)
|
||||
@@ -589,8 +391,7 @@ void NetplaySessionBrowserDialog::on_buttonBox_clicked(QAbstractButton* button)
|
||||
|
||||
void NetplaySessionBrowserDialog::accept()
|
||||
{
|
||||
if (!NetplayCommon::IsServerDispatcher(this->serverComboBox) &&
|
||||
!this->webSocket->isValid())
|
||||
if (!this->webSocket->isValid())
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", "Connection Failed");
|
||||
return;
|
||||
@@ -666,13 +467,5 @@ void NetplaySessionBrowserDialog::accept()
|
||||
|
||||
this->sessionData = sessionData;
|
||||
|
||||
if (NetplayCommon::IsServerDispatcher(this->serverComboBox))
|
||||
{
|
||||
this->dispatcherJoinSession = true;
|
||||
this->webSocket->open(sessionData.Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->joinSession();
|
||||
}
|
||||
this->joinSession();
|
||||
}
|
||||
|
||||
@@ -48,17 +48,6 @@ class NetplaySessionBrowserDialog : public QDialog, private Ui::NetplaySessionBr
|
||||
QMap<QString, CoreRomSettings> romData;
|
||||
|
||||
int pingTimerId = -1;
|
||||
int dispatcherTimerId = -1;
|
||||
int dispatcherTimeoutTimerId = -1;
|
||||
|
||||
bool dispatcherMoveThroughList = false;
|
||||
bool dispatcherJoinSession = false;
|
||||
QNetworkAccessManager* dispatcherNetworkAccessManager = nullptr;
|
||||
QNetworkReply* dispatcherNetworkReply = nullptr;
|
||||
QString dispatcherUrl;
|
||||
|
||||
QStringList dispatcherAddressList;
|
||||
int dispatcherAddressListIndex = 0;
|
||||
|
||||
QString showROMDialog(QString name, QString md5);
|
||||
|
||||
@@ -84,9 +73,6 @@ class NetplaySessionBrowserDialog : public QDialog, private Ui::NetplaySessionBr
|
||||
void on_broadcastSocket_readyRead(void);
|
||||
void on_jsonServerListDownload_Finished(QNetworkReply* reply);
|
||||
|
||||
void on_dispatcherRegionListDownload_Finished(QNetworkReply* reply);
|
||||
void on_dispatcherRetrieveServers_Finished(QNetworkReply* reply);
|
||||
|
||||
void on_serverComboBox_currentIndexChanged(int index);
|
||||
void on_sessionBrowserWidget_OnSessionChanged(bool valid);
|
||||
void on_sessionBrowserWidget_OnRefreshDone(void);
|
||||
|
||||
@@ -526,7 +526,6 @@ void SettingsDialog::loadInterfaceNetplaySettings(void)
|
||||
|
||||
this->netplayNicknameLineEdit->setText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_Nickname)));
|
||||
this->netplayServerUrlLineEdit->setText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_ServerJsonUrl)));
|
||||
this->netplayDispatcherUrlLineEdit->setText(QString::fromStdString(CoreSettingsGetStringValue(SettingsID::Netplay_DispatcherUrl)));
|
||||
}
|
||||
|
||||
void SettingsDialog::loadDefaultCoreSettings(void)
|
||||
@@ -680,7 +679,6 @@ void SettingsDialog::loadDefaultInterfaceNetplaySettings(void)
|
||||
{
|
||||
this->netplayNicknameLineEdit->setText(QString::fromStdString(CoreSettingsGetDefaultStringValue(SettingsID::Netplay_Nickname)));
|
||||
this->netplayServerUrlLineEdit->setText(QString::fromStdString(CoreSettingsGetDefaultStringValue(SettingsID::Netplay_ServerJsonUrl)));
|
||||
this->netplayDispatcherUrlLineEdit->setText(QString::fromStdString(CoreSettingsGetDefaultStringValue(SettingsID::Netplay_DispatcherUrl)));
|
||||
}
|
||||
|
||||
void SettingsDialog::saveSettings(void)
|
||||
@@ -916,7 +914,6 @@ void SettingsDialog::saveInterfaceNetplaySettings(void)
|
||||
{
|
||||
CoreSettingsSetValue(SettingsID::Netplay_Nickname, this->netplayNicknameLineEdit->text().toStdString());
|
||||
CoreSettingsSetValue(SettingsID::Netplay_ServerJsonUrl, this->netplayServerUrlLineEdit->text().toStdString());
|
||||
CoreSettingsSetValue(SettingsID::Netplay_DispatcherUrl, this->netplayDispatcherUrlLineEdit->text().toStdString());
|
||||
}
|
||||
|
||||
void SettingsDialog::commonHotkeySettings(SettingsDialogAction action)
|
||||
|
||||
@@ -665,27 +665,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_21">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Dispatcher URL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="netplayDispatcherUrlLineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_19">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -457,6 +457,7 @@ QString MainWindow::getWindowTitle(void)
|
||||
const QStringList secondWordList = {
|
||||
{
|
||||
" rights!!!",
|
||||
" rights are human rights <3",
|
||||
"s rise up!!!"
|
||||
}};
|
||||
|
||||
@@ -601,12 +602,15 @@ void MainWindow::updateUI(bool inEmulation, bool isPaused)
|
||||
// launch RMG with a ROM on the commandline or drag & drop
|
||||
this->ui_Widgets->setCurrentWidget(this->ui_Widget_Dummy);
|
||||
}
|
||||
|
||||
this->storeGeometry();
|
||||
}
|
||||
else if (!this->ui_NoSwitchToRomBrowser)
|
||||
{
|
||||
this->setWindowTitle(this->ui_WindowTitle);
|
||||
this->ui_Widgets->setCurrentWidget(this->ui_Widget_RomBrowser);
|
||||
this->ui_StatusBar_RenderModeLabel->clear();
|
||||
this->loadGeometry();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -619,9 +623,69 @@ void MainWindow::updateUI(bool inEmulation, bool isPaused)
|
||||
|
||||
void MainWindow::storeGeometry(void)
|
||||
{
|
||||
std::string geometryStr = this->saveGeometry().toBase64().toStdString();
|
||||
if (this->ui_Geometry_Saved)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->ui_Geometry = this->saveGeometry();
|
||||
this->ui_Geometry_Maximized = this->isMaximized();
|
||||
this->ui_Geometry_Saved = true;
|
||||
|
||||
std::string geometryStr = this->ui_Geometry.toBase64().toStdString();
|
||||
CoreSettingsSetValue(SettingsID::RomBrowser_Geometry, geometryStr);
|
||||
CoreSettingsSetValue(SettingsID::RomBrowser_Maximized, this->isMaximized());
|
||||
CoreSettingsSetValue(SettingsID::RomBrowser_Maximized, this->ui_Geometry_Maximized);
|
||||
}
|
||||
|
||||
void MainWindow::loadGeometry(void)
|
||||
{
|
||||
if (!this->ui_Geometry_Saved)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->ui_Geometry_Maximized)
|
||||
{
|
||||
this->showMaximized();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->restoreGeometry(this->ui_Geometry);
|
||||
}
|
||||
|
||||
if (this->isFullScreen())
|
||||
{
|
||||
this->showNormal();
|
||||
}
|
||||
|
||||
if (this->ui_ShowMenubar && this->menuBar()->isHidden())
|
||||
{
|
||||
this->menuBar()->show();
|
||||
}
|
||||
else if (!this->ui_ShowMenubar && !this->menuBar()->isHidden())
|
||||
{
|
||||
this->menuBar()->hide();
|
||||
}
|
||||
|
||||
if (this->ui_ShowToolbar && this->toolBar->isHidden())
|
||||
{
|
||||
this->toolBar->show();
|
||||
}
|
||||
else if (!this->ui_ShowToolbar && !this->toolBar->isHidden())
|
||||
{
|
||||
this->toolBar->hide();
|
||||
}
|
||||
|
||||
if (this->ui_ShowStatusbar && this->statusBar()->isHidden())
|
||||
{
|
||||
this->statusBar()->show();
|
||||
}
|
||||
else if (!this->ui_ShowStatusbar && !this->statusBar()->isHidden())
|
||||
{
|
||||
this->statusBar()->hide();
|
||||
}
|
||||
|
||||
this->ui_Geometry_Saved = false;
|
||||
}
|
||||
|
||||
void MainWindow::initializeEmulationThread(void)
|
||||
@@ -738,8 +802,6 @@ void MainWindow::launchEmulationThread(QString cartRom, QString diskRom, bool re
|
||||
this->ui_ShowStatusbar = CoreSettingsGetBoolValue(SettingsID::GUI_StatusBar);
|
||||
}
|
||||
|
||||
this->emulationThread->SetVideoSize(this->ui_Widgets->width() * this->devicePixelRatio(),
|
||||
this->ui_Widgets->height() * this->devicePixelRatio());
|
||||
this->emulationThread->SetRomFile(cartRom);
|
||||
this->emulationThread->SetDiskFile(diskRom);
|
||||
this->emulationThread->start();
|
||||
@@ -2304,7 +2366,8 @@ void MainWindow::on_NetplaySessionDialog_rejected()
|
||||
|
||||
void MainWindow::on_VidExt_Init(VidExtRenderMode renderMode)
|
||||
{
|
||||
this->ui_VidExtRenderMode = renderMode;
|
||||
this->ui_VidExtRenderMode = renderMode;
|
||||
this->ui_VidExtForceSetMode = true;
|
||||
|
||||
if (CoreSettingsGetBoolValue(SettingsID::GUI_OpenGLES))
|
||||
{
|
||||
@@ -2491,9 +2554,12 @@ void MainWindow::on_VidExt_ResizeWindow(int width, int height)
|
||||
height += this->statusBar()->height();
|
||||
}
|
||||
|
||||
if (this->size() == QSize(width, height))
|
||||
if (!this->ui_VidExtForceSetMode)
|
||||
{
|
||||
return;
|
||||
if (this->size() == QSize(width, height))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->isMaximized() || this->isMinimized())
|
||||
@@ -2502,6 +2568,10 @@ void MainWindow::on_VidExt_ResizeWindow(int width, int height)
|
||||
}
|
||||
|
||||
this->resize(width, height);
|
||||
|
||||
// we've force set the size once,
|
||||
// we can safely disable it now
|
||||
this->ui_VidExtForceSetMode = false;
|
||||
}
|
||||
|
||||
void MainWindow::on_VidExt_ToggleFS(bool fullscreen)
|
||||
|
||||
@@ -63,9 +63,14 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
|
||||
QLabel *ui_StatusBar_Label = nullptr;
|
||||
QLabel *ui_StatusBar_RenderModeLabel = nullptr;
|
||||
|
||||
QByteArray ui_Geometry;
|
||||
bool ui_Geometry_Maximized = false;
|
||||
bool ui_Geometry_Saved = false;
|
||||
|
||||
bool ui_HideCursorInEmulation = false;
|
||||
bool ui_HideCursorInFullscreenEmulation = false;
|
||||
bool ui_NoSwitchToRomBrowser = false;
|
||||
bool ui_VidExtForceSetMode = false;
|
||||
bool ui_LaunchInFullscreen = false;
|
||||
bool ui_QuitAfterEmulation = false;
|
||||
bool ui_RefreshRomListAfterEmulation = false;
|
||||
@@ -131,6 +136,7 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
|
||||
void updateUI(bool inEmulation, bool isPaused);
|
||||
|
||||
void storeGeometry(void);
|
||||
void loadGeometry(void);
|
||||
|
||||
void initializeEmulationThread(void);
|
||||
void connectEmulationThreadSignals(void);
|
||||
|
||||
@@ -69,11 +69,6 @@ void OGLWidget::resizeEvent(QResizeEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->oldSize() == event->size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->timerId != 0)
|
||||
{
|
||||
this->killTimer(this->timerId);
|
||||
|
||||
@@ -42,11 +42,6 @@ void VKWidget::resizeEvent(QResizeEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->oldSize() == event->size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->timerId != 0)
|
||||
{
|
||||
this->killTimer(this->timerId);
|
||||
|
||||
Reference in New Issue
Block a user