Compare commits

...

36 commits

Author SHA1 Message Date
JSaurusRex 13faf02ae6
Merge 6c0427d23c into d5e81ca78d 2024-09-11 23:30:44 +02:00
Jupeyy d5e81ca78d
Merge pull request #8932 from Robyt3/Client-Network-Before-Graphics
Initialize client networking before graphics
2024-09-11 18:07:20 +00:00
Robert Müller 128ffd2313 Initialize client networking before graphics
Avoid Vulkan crash if the backend is destroyed immediately after being created.

Slightly decreases time of initial black screen before loading menu is rendered.
2024-09-11 19:34:31 +02:00
Dennis Felsing af1b32d296
Merge pull request #8930 from timakro/pr-fix-econ-listening-publicly
Fixes a bug where econ was exposed publicly when ec_bindaddr was set to localhost
2024-09-11 16:50:42 +00:00
Tim Schumacher 0ad1c08c22 Fixes a bug where econ was exposed publicly when ec_bindaddr was set to localhost
Also implements the original intention of 85f5e9c that is to disable
econ if ec_binaddr is invalid.
2024-09-11 18:28:07 +02:00
Dennis Felsing 9f278979e5
Merge pull request #8926 from Robyt3/Editor-RGB-Mapres-Fix
Fix editor crash when saving maps with RGB mapres
2024-09-10 22:01:35 +00:00
Robert Müller 32e9240634 Fix editor crash when saving maps with RGB mapres
Convert mapres to RGBA immediately when loading them, so the image data is always in RGBA format internally, instead of only converting when the map is saved (which was erroneously removed in #8670).

This means the `cl_editor_dilate` setting will now also be applied to converted RGB images.
2024-09-10 21:22:56 +02:00
Dennis Felsing b5d662622c
Merge pull request #8918 from Robyt3/Cleanup-Color-mem_comp
Use operator `!=` instead of `mem_comp` for colors
2024-09-09 16:14:43 +00:00
Robert Müller 58ce5985d4 Use operator != instead of mem_comp for colors 2024-09-09 17:17:17 +02:00
Dennis Felsing 46acbdd6bf
Merge pull request #8916 from Robyt3/Android-API-Version-Building-Fix
Fix minimum Android API version and linking errors
2024-09-08 16:41:58 +00:00
Robert Müller d536bceed6 Fix minimum Android API version and linking errors
The minimum supported API version must be specified when building the native libraries, otherwise this may cause linking errors when launching the app.

The minimum API level is increased to 24 (Android 7.0, covering 97.2% of usages) because:

- Vulkan is only available from API 24+ on ARM64 and x64.
- curl only compiles with API 23+.
- The NDK version we use supports only API 21+.

Ensure that the C++/Linker flags are set when building Android libraries, which was causing errors due to `-fPIC` not being set for all libraries.
2024-09-08 17:59:41 +02:00
Dennis Felsing 337d5c7ab3
Merge pull request #8915 from Robyt3/Base-Detect-ARM-Redefinition-Fix
Fix redefinition of `CONF_ARCH_STRING` for ARM architectures
2024-09-07 21:03:40 +00:00
Robert Müller 8e45d0a71a Fix redefinition of CONF_ARCH_STRING for ARM architectures
The macro `__ARM_ARCH` is defined both for 32-bit and 64-bit ARM so it cannot be used to identify ARM64. Now `__ARM_ARCH_ISA_A64` is used instead, which should only be defined for ARM64. This caused a warning due to the macro `CONF_ARCH_STRING` being redefined when compiling for Android. Furthermore, support for detecting big-endian ARM64 with the `__ARM_BIG_ENDIAN` macro is added.

See https://developer.arm.com/documentation/dui0774/g/chr1383660321827
2024-09-07 21:16:09 +02:00
Robert Müller a865354320
Merge pull request #8914 from Jupeyy/pr_cpy_into_fake_buffer
Add another row to do the copying for presented images in when pitch is bigger than width
2024-09-07 18:56:16 +00:00
Jupeyy 3595b70170
Add another row to do the copying for presented images in when pitch is bigger than width 2024-09-07 18:31:06 +02:00
Jupeyy 11fd82077a
Merge pull request #8913 from Robyt3/Video-Stop-ASAN-Fix
Fix heap-use-after-free in `CVideo::Stop`
2024-09-07 16:17:29 +00:00
Dennis Felsing 3d30ce4bf2
Merge pull request #8817 from Robyt3/Client-Start-Menu-Console
Add icon button to open console in bottom right of start menu
2024-09-07 17:19:15 +02:00
Robert Müller 9e0ba8a91f Fix heap-use-after-free in CVideo::Stop
The `delete ms_pCurrentVideo` deletes the current video instance (`this`) so the subsequent write to `m_Stopped` was invalid.

Closes #8899.
2024-09-07 16:57:27 +02:00
Robert Müller c89509bc4b Add icon button to open console in bottom right of start menu
Add a button with the "terminal" icon in the bottom right of the start menu to open the local console to ensure that the local console is usable also when no physical keyboard (with F-keys) is available.
2024-09-07 13:12:30 +02:00
Dennis Felsing 306d3c7b58
Merge pull request #8910 from Robyt3/Android-Manifest-Flags-SDL
Adopt changes to `AndroidManifest.xml` from SDL sample project
2024-09-07 10:29:41 +00:00
Robert Müller 9832288983 Adopt changes to AndroidManifest.xml from SDL sample project
Specify `android:installLocation="auto"` so the app can be installed on and move to the external storage.

Specify optional features which the app may use (touchscreen, game controller, external mouse).

Specify `android:preferMinimalPostProcessing="true"` so lower latency HDMI mode is enabled when available. Specify `android:hardwareAccelerated="true"` for consistency (it is already the default setting).

Specify same `android:configChanges` and `android:alwaysRetainTaskState` values as SDL to avoid potential bugs due to inconsistency with what the `SDLActivity` expects.

See f5ed158d1f/android-project/app/src/main/AndroidManifest.xml
2024-09-07 12:09:41 +02:00
Dennis Felsing fc058fa432
Merge pull request #8906 from Robyt3/Client-Download-Gameserver-Fix
Fix map download fallback from game server
2024-09-06 22:11:02 +00:00
Dennis Felsing 3b22a3e02f
Merge pull request #8905 from furo321/hot-reload-super-crash
Fix crash with `hot_reload` while in `super`
2024-09-06 22:08:14 +00:00
Robert Müller ed1ef4e694 Fix map download fallback from game server
Do not reset the active map download's information before using the fallback map download.

Remove redundant calls of `ResetMapDownload` before disconnecting, as this already resets the map download.

Closes #8885. Regression from #8848.
2024-09-06 20:55:02 +02:00
furo 9103332e36 Fix crash with hot_reload while in super 2024-09-06 20:12:07 +02:00
Dennis Felsing 0948a53648
Merge pull request #8904 from furo321/fix-force-yes
Fix `random_unfinished_map` not working with `vote yes`
2024-09-06 17:34:21 +00:00
furo bbd34c9452 Fix random_unfinished_map not working with vote yes 2024-09-06 18:56:58 +02:00
Dennis Felsing e4282f100a
Merge pull request #8902 from KebsCS/pr-hotreload-lasttp
Add /lasttp to hot reload
2024-09-06 16:24:48 +00:00
KebsCS eb9e73f68b
Add /lasttp to hot reload 2024-09-06 16:31:46 +02:00
JSaurusRex 6c0427d23c made antiping limit have new functionality as a limit to the amount of antiping there is but backwards, higher number means less antiping. Basically the amount of time antiping doesn't predict 2024-09-04 14:52:04 +02:00
JSaurusRex 38324489a2 replaced floor with std::floor 2024-05-30 17:14:32 +02:00
JSaurusRex 4dc74376e5 renamed to cl_antiping_max 2024-05-29 20:41:26 +02:00
JSaurusRex 849fa743ba fixed crash? 2024-05-29 20:10:41 +02:00
JSaurusRex 01f77c6059 Fixed code style and removed commented out code 2024-05-18 22:35:53 +02:00
JSaurusRex ac806a37f9 weapons and projectiles are properly delayed / predicted as well 2024-05-18 20:12:12 +02:00
JSaurusRex ba9ba69d1e inital antiping percent commit{ 2024-05-18 18:31:21 +02:00
27 changed files with 269 additions and 113 deletions

View file

@ -10,7 +10,8 @@ ANDROID_NDK_VERSION="${ANDROID_NDK_VERSION:2}"
# ANDROID_NDK_HOME must be exported for cargo-ndk # ANDROID_NDK_HOME must be exported for cargo-ndk
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/$ANDROID_NDK_VERSION" export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/$ANDROID_NDK_VERSION"
ANDROID_API_LEVEL=34 # ANDROID_API_LEVEL must specify the _minimum_ supported SDK version, otherwise this will cause linking errors at launch
ANDROID_API_LEVEL=24
ANDROID_SUB_BUILD_DIR=build_arch ANDROID_SUB_BUILD_DIR=build_arch
COLOR_RED="\e[1;31m" COLOR_RED="\e[1;31m"

View file

@ -1,15 +1,40 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="auto">
<!-- Vulkan 1.1.0 is used if supported --> <!-- Vulkan 1.1.0 is used if supported -->
<uses-feature <uses-feature
android:name="android.hardware.vulkan.version" android:name="android.hardware.vulkan.version"
android:required="false" android:required="false"
android:version="0x00401000" /> android:version="0x00401000" />
<!-- android:glEsVersion is not specified as OpenGL ES 1.0 is supported as fallback --> <!-- android:glEsVersion is not specified as OpenGL ES 1.0 is supported as fallback -->
<!-- Only playable in landscape mode -->
<uses-feature <uses-feature
android:name="android.hardware.screen.landscape" android:name="android.hardware.screen.landscape"
android:required="true" /> android:required="true" />
<!-- Touchscreen support -->
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<!-- Game controller support -->
<uses-feature
android:name="android.hardware.bluetooth"
android:required="false" />
<uses-feature
android:name="android.hardware.gamepad"
android:required="false" />
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />
<!-- External mouse input events -->
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />
<!-- Teeworlds does broadcasts over local networks --> <!-- Teeworlds does broadcasts over local networks -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
@ -25,17 +50,24 @@
android:isGame="true" android:isGame="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:hardwareAccelerated="true">
<activity <activity
android:name="org.ddnet.client.NativeMain" android:name="org.ddnet.client.NativeMain"
android:alwaysRetainTaskState="true"
android:exported="true" android:exported="true"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden" android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:preferMinimalPostProcessing="true"
android:screenOrientation="landscape" android:screenOrientation="landscape"
android:launchMode="singleInstance"> android:launchMode="singleInstance">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
<!-- Let Android know that we can handle some USB devices and should receive this event -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data <meta-data
android:name="android.app.lib_name" android:name="android.app.lib_name"
android:value="DDNet" /> android:value="DDNet" />

View file

@ -21,7 +21,7 @@ android {
defaultConfig { defaultConfig {
applicationId "org.ddnet.client" applicationId "org.ddnet.client"
namespace("org.ddnet.client") namespace("org.ddnet.client")
minSdkVersion 19 minSdkVersion 24
targetSdkVersion 34 targetSdkVersion 34
versionCode TW_VERSION_CODE versionCode TW_VERSION_CODE
versionName "TW_VERSION_NAME" versionName "TW_VERSION_NAME"

View file

@ -29,6 +29,8 @@ function compile_source_android() {
-DCMAKE_SYSTEM_NAME=Android \ -DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION="$1" \ -DCMAKE_SYSTEM_VERSION="$1" \
-DCMAKE_ANDROID_ARCH_ABI="${3}" \ -DCMAKE_ANDROID_ARCH_ABI="${3}" \
-DCMAKE_C_FLAGS="$COMPILEFLAGS" -DCMAKE_CXX_FLAGS="$COMPILEFLAGS" -DCMAKE_CXX_FLAGS_RELEASE="$COMPILEFLAGS" -DCMAKE_C_FLAGS_RELEASE="$COMPILEFLAGS" \
-DCMAKE_SHARED_LINKER_FLAGS="$LINKFLAGS" -DCMAKE_SHARED_LINKER_FLAGS_RELEASE="$LINKFLAGS" \
-B"$2" \ -B"$2" \
-DBUILD_SHARED_LIBS=OFF \ -DBUILD_SHARED_LIBS=OFF \
-DHIDAPI_SKIP_LIBUSB=TRUE \ -DHIDAPI_SKIP_LIBUSB=TRUE \

View file

@ -46,7 +46,8 @@ fi
mkdir -p "$1" mkdir -p "$1"
cd "$1" || exit 1 cd "$1" || exit 1
_ANDROID_ABI_LEVEL=34 # ANDROID_API_LEVEL must specify the _minimum_ supported SDK version, otherwise this will cause linking errors at launch
ANDROID_API_LEVEL=24
function build_cmake_lib() { function build_cmake_lib() {
if [ ! -d "${1}" ]; then if [ ! -d "${1}" ]; then
@ -59,7 +60,7 @@ function build_cmake_lib() {
( (
cd "${1}" || exit 1 cd "${1}" || exit 1
cp "${CURDIR}"/scripts/compile_libs/cmake_lib_compile.sh cmake_lib_compile.sh cp "${CURDIR}"/scripts/compile_libs/cmake_lib_compile.sh cmake_lib_compile.sh
./cmake_lib_compile.sh "$_ANDROID_ABI_LEVEL" "$OS_NAME" "$COMPILEFLAGS" "$LINKFLAGS" ./cmake_lib_compile.sh "$ANDROID_API_LEVEL" "$OS_NAME" "$COMPILEFLAGS" "$LINKFLAGS"
) )
} }
@ -74,7 +75,7 @@ cd compile_libs || exit 1
( (
cd openssl || exit 1 cd openssl || exit 1
cp "${CURDIR}"/scripts/compile_libs/make_lib_openssl.sh make_lib_openssl.sh cp "${CURDIR}"/scripts/compile_libs/make_lib_openssl.sh make_lib_openssl.sh
./make_lib_openssl.sh "$_ANDROID_ABI_LEVEL" "$OS_NAME" "$COMPILEFLAGS" "$LINKFLAGS" ./make_lib_openssl.sh "$ANDROID_API_LEVEL" "$OS_NAME" "$COMPILEFLAGS" "$LINKFLAGS"
) )
) )
@ -97,7 +98,7 @@ build_cmake_lib opus https://github.com/xiph/opus
./autogen.sh ./autogen.sh
fi fi
cp "${CURDIR}"/scripts/compile_libs/make_lib_opusfile.sh make_lib_opusfile.sh cp "${CURDIR}"/scripts/compile_libs/make_lib_opusfile.sh make_lib_opusfile.sh
./make_lib_opusfile.sh "$_ANDROID_ABI_LEVEL" "$OS_NAME" "$COMPILEFLAGS" "$LINKFLAGS" ./make_lib_opusfile.sh "$ANDROID_API_LEVEL" "$OS_NAME" "$COMPILEFLAGS" "$LINKFLAGS"
) )
# SQLite, just download and built by hand # SQLite, just download and built by hand
@ -109,7 +110,7 @@ fi
( (
cd sqlite3 || exit 1 cd sqlite3 || exit 1
cp "${CURDIR}"/scripts/compile_libs/make_lib_sqlite3.sh make_lib_sqlite3.sh cp "${CURDIR}"/scripts/compile_libs/make_lib_sqlite3.sh make_lib_sqlite3.sh
./make_lib_sqlite3.sh "$_ANDROID_ABI_LEVEL" "$OS_NAME" "$COMPILEFLAGS" "$LINKFLAGS" ./make_lib_sqlite3.sh "$ANDROID_API_LEVEL" "$OS_NAME" "$COMPILEFLAGS" "$LINKFLAGS"
) )
cd .. cd ..

View file

@ -163,19 +163,19 @@
#define CONF_ARCH_ARM 1 #define CONF_ARCH_ARM 1
#define CONF_ARCH_STRING "arm" #define CONF_ARCH_STRING "arm"
#define CONF_ARCH_ENDIAN_BIG 1 #define CONF_ARCH_ENDIAN_BIG 1
#endif #elif defined(__ARMEL__)
#if defined(__ARMEL__)
#define CONF_ARCH_ARM 1 #define CONF_ARCH_ARM 1
#define CONF_ARCH_STRING "arm" #define CONF_ARCH_STRING "arm"
#define CONF_ARCH_ENDIAN_LITTLE 1 #define CONF_ARCH_ENDIAN_LITTLE 1
#endif #elif defined(__aarch64__) || defined(__arm64__) || defined(__ARM_ARCH_ISA_A64)
#if defined(__aarch64__) || defined(__arm64__) || defined(__ARM_ARCH)
#define CONF_ARCH_ARM64 1 #define CONF_ARCH_ARM64 1
#define CONF_ARCH_STRING "arm64" #define CONF_ARCH_STRING "arm64"
#if defined(__ARM_BIG_ENDIAN)
#define CONF_ARCH_ENDIAN_BIG 1
#else
#define CONF_ARCH_ENDIAN_LITTLE 1 #define CONF_ARCH_ENDIAN_LITTLE 1
#endif #endif
#endif
#ifndef CONF_FAMILY_STRING #ifndef CONF_FAMILY_STRING
#define CONF_FAMILY_STRING "unknown" #define CONF_FAMILY_STRING "unknown"

View file

@ -1508,8 +1508,9 @@ protected:
vkInvalidateMappedMemoryRanges(m_VKDevice, 1, &MemRange); vkInvalidateMappedMemoryRanges(m_VKDevice, 1, &MemRange);
size_t RealFullImageSize = maximum(ImageTotalSize, (size_t)(Height * m_GetPresentedImgDataHelperMappedLayoutPitch)); size_t RealFullImageSize = maximum(ImageTotalSize, (size_t)(Height * m_GetPresentedImgDataHelperMappedLayoutPitch));
if(vDstData.size() < RealFullImageSize) size_t ExtraRowSize = Width * 4;
vDstData.resize(RealFullImageSize); if(vDstData.size() < RealFullImageSize + ExtraRowSize)
vDstData.resize(RealFullImageSize + ExtraRowSize);
mem_copy(vDstData.data(), pResImageData, RealFullImageSize); mem_copy(vDstData.data(), pResImageData, RealFullImageSize);
@ -1520,7 +1521,8 @@ protected:
{ {
size_t OffsetImagePacked = (Y * Width * 4); size_t OffsetImagePacked = (Y * Width * 4);
size_t OffsetImageUnpacked = (Y * m_GetPresentedImgDataHelperMappedLayoutPitch); size_t OffsetImageUnpacked = (Y * m_GetPresentedImgDataHelperMappedLayoutPitch);
mem_copy(vDstData.data() + OffsetImagePacked, vDstData.data() + OffsetImageUnpacked, Width * 4); mem_copy(vDstData.data() + RealFullImageSize, vDstData.data() + OffsetImageUnpacked, Width * 4);
mem_copy(vDstData.data() + OffsetImagePacked, vDstData.data() + RealFullImageSize, Width * 4);
} }
} }

View file

@ -668,10 +668,7 @@ void CClient::DisconnectWithReason(const char *pReason)
m_CurrentServerCurrentPingTime = -1; m_CurrentServerCurrentPingTime = -1;
m_CurrentServerNextPingTime = -1; m_CurrentServerNextPingTime = -1;
ResetMapDownload(); ResetMapDownload(true);
m_aMapdownloadFilename[0] = '\0';
m_aMapdownloadFilenameTemp[0] = '\0';
m_aMapdownloadName[0] = '\0';
// clear the current server info // clear the current server info
mem_zero(&m_CurrentServerInfo, sizeof(m_CurrentServerInfo)); mem_zero(&m_CurrentServerInfo, sizeof(m_CurrentServerInfo));
@ -1019,11 +1016,11 @@ void CClient::Render()
GameClient()->OnRender(); GameClient()->OnRender();
DebugRender(); DebugRender();
if(State() == IClient::STATE_ONLINE && g_Config.m_ClAntiPingLimit) // if(State() == IClient::STATE_ONLINE && g_Config.m_ClAntiPingLimit)
{ // {
int64_t Now = time_get(); // int64_t Now = time_get();
g_Config.m_ClAntiPing = (m_PredictedTime.Get(Now) - m_aGameTime[g_Config.m_ClDummy].Get(Now)) * 1000 / (float)time_freq() > g_Config.m_ClAntiPingLimit; // g_Config.m_ClAntiPing = (m_PredictedTime.Get(Now) - m_aGameTime[g_Config.m_ClDummy].Get(Now)) * 1000 / (float)time_freq() > g_Config.m_ClAntiPingLimit;
} // }
} }
const char *CClient::LoadMap(const char *pName, const char *pFilename, SHA256_DIGEST *pWantedSha256, unsigned WantedCrc) const char *CClient::LoadMap(const char *pName, const char *pFilename, SHA256_DIGEST *pWantedSha256, unsigned WantedCrc)
@ -1528,7 +1525,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy)
DummyDisconnect(0); DummyDisconnect(0);
} }
ResetMapDownload(); ResetMapDownload(true);
SHA256_DIGEST *pMapSha256 = nullptr; SHA256_DIGEST *pMapSha256 = nullptr;
const char *pMapUrl = nullptr; const char *pMapUrl = nullptr;
@ -2196,7 +2193,7 @@ int CClient::UnpackAndValidateSnapshot(CSnapshot *pFrom, CSnapshot *pTo)
return Builder.Finish(pTo); return Builder.Finish(pTo);
} }
void CClient::ResetMapDownload() void CClient::ResetMapDownload(bool ResetActive)
{ {
if(m_pMapdownloadTask) if(m_pMapdownloadTask)
{ {
@ -2215,19 +2212,24 @@ void CClient::ResetMapDownload()
Storage()->RemoveFile(m_aMapdownloadFilenameTemp, IStorage::TYPE_SAVE); Storage()->RemoveFile(m_aMapdownloadFilenameTemp, IStorage::TYPE_SAVE);
} }
m_MapdownloadChunk = 0; if(ResetActive)
m_MapdownloadSha256Present = false; {
m_MapdownloadSha256 = SHA256_ZEROED; m_MapdownloadChunk = 0;
m_MapdownloadCrc = 0; m_MapdownloadSha256Present = false;
m_MapdownloadTotalsize = -1; m_MapdownloadSha256 = SHA256_ZEROED;
m_MapdownloadAmount = 0; m_MapdownloadCrc = 0;
m_MapdownloadTotalsize = -1;
m_MapdownloadAmount = 0;
m_aMapdownloadFilename[0] = '\0';
m_aMapdownloadFilenameTemp[0] = '\0';
m_aMapdownloadName[0] = '\0';
}
} }
void CClient::FinishMapDownload() void CClient::FinishMapDownload()
{ {
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "download complete, loading map"); m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "download complete, loading map");
const int PrevMapdownloadTotalsize = m_MapdownloadTotalsize;
SHA256_DIGEST *pSha256 = m_MapdownloadSha256Present ? &m_MapdownloadSha256 : nullptr; SHA256_DIGEST *pSha256 = m_MapdownloadSha256Present ? &m_MapdownloadSha256 : nullptr;
bool FileSuccess = true; bool FileSuccess = true;
@ -2236,7 +2238,6 @@ void CClient::FinishMapDownload()
FileSuccess &= Storage()->RenameFile(m_aMapdownloadFilenameTemp, m_aMapdownloadFilename, IStorage::TYPE_SAVE); FileSuccess &= Storage()->RenameFile(m_aMapdownloadFilenameTemp, m_aMapdownloadFilename, IStorage::TYPE_SAVE);
if(!FileSuccess) if(!FileSuccess)
{ {
ResetMapDownload();
char aError[128 + IO_MAX_PATH_LENGTH]; char aError[128 + IO_MAX_PATH_LENGTH];
str_format(aError, sizeof(aError), Localize("Could not save downloaded map. Try manually deleting this file: %s"), m_aMapdownloadFilename); str_format(aError, sizeof(aError), Localize("Could not save downloaded map. Try manually deleting this file: %s"), m_aMapdownloadFilename);
DisconnectWithReason(aError); DisconnectWithReason(aError);
@ -2246,19 +2247,17 @@ void CClient::FinishMapDownload()
const char *pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, pSha256, m_MapdownloadCrc); const char *pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, pSha256, m_MapdownloadCrc);
if(!pError) if(!pError)
{ {
ResetMapDownload(); ResetMapDownload(true);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "loading done"); m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "loading done");
SendReady(CONN_MAIN); SendReady(CONN_MAIN);
} }
else if(m_pMapdownloadTask) // fallback else if(m_pMapdownloadTask) // fallback
{ {
ResetMapDownload(); ResetMapDownload(false);
m_MapdownloadTotalsize = PrevMapdownloadTotalsize;
SendMapRequest(); SendMapRequest();
} }
else else
{ {
ResetMapDownload();
DisconnectWithReason(pError); DisconnectWithReason(pError);
} }
} }
@ -2784,7 +2783,7 @@ void CClient::Update()
else if(m_pMapdownloadTask->State() == EHttpState::ERROR || m_pMapdownloadTask->State() == EHttpState::ABORTED) else if(m_pMapdownloadTask->State() == EHttpState::ERROR || m_pMapdownloadTask->State() == EHttpState::ABORTED)
{ {
dbg_msg("webdl", "http failed, falling back to gameserver"); dbg_msg("webdl", "http failed, falling back to gameserver");
ResetMapDownload(); ResetMapDownload(false);
SendMapRequest(); SendMapRequest();
} }
} }
@ -2930,6 +2929,24 @@ void CClient::Run()
g_UuidManager.DebugDump(); g_UuidManager.DebugDump();
} }
#ifndef CONF_WEBASM
char aNetworkError[256];
if(!InitNetworkClient(aNetworkError, sizeof(aNetworkError)))
{
log_error("client", "%s", aNetworkError);
ShowMessageBox("Network Error", aNetworkError);
return;
}
#endif
if(!m_Http.Init(std::chrono::seconds{1}))
{
const char *pErrorMessage = "Failed to initialize the HTTP client.";
log_error("client", "%s", pErrorMessage);
ShowMessageBox("HTTP Error", pErrorMessage);
return;
}
// init graphics // init graphics
m_pGraphics = CreateEngineGraphicsThreaded(); m_pGraphics = CreateEngineGraphicsThreaded();
Kernel()->RegisterInterface(m_pGraphics); // IEngineGraphics Kernel()->RegisterInterface(m_pGraphics); // IEngineGraphics
@ -2953,24 +2970,6 @@ void CClient::Run()
CVideo::Init(); CVideo::Init();
#endif #endif
#ifndef CONF_WEBASM
char aNetworkError[256];
if(!InitNetworkClient(aNetworkError, sizeof(aNetworkError)))
{
log_error("client", "%s", aNetworkError);
ShowMessageBox("Network Error", aNetworkError);
return;
}
#endif
if(!m_Http.Init(std::chrono::seconds{1}))
{
const char *pErrorMessage = "Failed to initialize the HTTP client.";
log_error("client", "%s", pErrorMessage);
ShowMessageBox("HTTP Error", pErrorMessage);
return;
}
// init text render // init text render
m_pTextRender = Kernel()->RequestInterface<IEngineTextRender>(); m_pTextRender = Kernel()->RequestInterface<IEngineTextRender>();
m_pTextRender->Init(); m_pTextRender->Init();

View file

@ -360,7 +360,7 @@ public:
int UnpackAndValidateSnapshot(CSnapshot *pFrom, CSnapshot *pTo); int UnpackAndValidateSnapshot(CSnapshot *pFrom, CSnapshot *pTo);
void ResetMapDownload(); void ResetMapDownload(bool ResetActive);
void FinishMapDownload(); void FinishMapDownload();
void RequestDDNetInfo() override; void RequestDDNetInfo() override;

View file

@ -300,7 +300,7 @@ void CGraphics_Threaded::UnloadTexture(CTextureHandle *pIndex)
FreeTextureIndex(pIndex); FreeTextureIndex(pIndex);
} }
static bool ConvertToRGBA(uint8_t *pDest, const CImageInfo &SrcImage) bool ConvertToRGBA(uint8_t *pDest, const CImageInfo &SrcImage)
{ {
if(SrcImage.m_Format == CImageInfo::FORMAT_RGBA) if(SrcImage.m_Format == CImageInfo::FORMAT_RGBA)
{ {

View file

@ -283,6 +283,7 @@ void CVideo::Pause(bool Pause)
void CVideo::Stop() void CVideo::Stop()
{ {
dbg_assert(!m_Stopped, "Already stopped"); dbg_assert(!m_Stopped, "Already stopped");
m_Stopped = true;
m_pGraphics->WaitForIdle(); m_pGraphics->WaitForIdle();
@ -341,8 +342,6 @@ void CVideo::Stop()
pSound->PauseAudioDevice(); pSound->PauseAudioDevice();
delete ms_pCurrentVideo; delete ms_pCurrentVideo;
pSound->UnpauseAudioDevice(); pSound->UnpauseAudioDevice();
m_Stopped = true;
} }
void CVideo::NextVideoFrameThread() void CVideo::NextVideoFrameThread()

View file

@ -124,6 +124,8 @@ public:
} }
}; };
bool ConvertToRGBA(uint8_t *pDest, const CImageInfo &SrcImage);
/* /*
Structure: CVideoMode Structure: CVideoMode
*/ */

View file

@ -13,7 +13,8 @@
// client // client
MACRO_CONFIG_INT(ClPredict, cl_predict, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict client movements") MACRO_CONFIG_INT(ClPredict, cl_predict, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict client movements")
MACRO_CONFIG_INT(ClPredictDummy, cl_predict_dummy, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict dummy movements") MACRO_CONFIG_INT(ClPredictDummy, cl_predict_dummy, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict dummy movements")
MACRO_CONFIG_INT(ClAntiPingLimit, cl_antiping_limit, 0, 0, 200, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Antiping limit (0 to disable)") MACRO_CONFIG_INT(ClAntiPingLimit, cl_antiping_limit, 0, 0, 200, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Adds delay to antiping (0 to disable)")
MACRO_CONFIG_INT(ClAntiPingpercent, cl_antiping_percent, 100, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "how far ahead Antiping predicts, ignored when antiping limit is used")
MACRO_CONFIG_INT(ClAntiPing, cl_antiping, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Enable antiping, i. e. more aggressive prediction.") MACRO_CONFIG_INT(ClAntiPing, cl_antiping, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Enable antiping, i. e. more aggressive prediction.")
MACRO_CONFIG_INT(ClAntiPingPlayers, cl_antiping_players, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict other player's movement more aggressively (only enabled if cl_antiping is set to 1)") MACRO_CONFIG_INT(ClAntiPingPlayers, cl_antiping_players, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict other player's movement more aggressively (only enabled if cl_antiping is set to 1)")
MACRO_CONFIG_INT(ClAntiPingGrenade, cl_antiping_grenade, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict grenades (only enabled if cl_antiping is set to 1)") MACRO_CONFIG_INT(ClAntiPingGrenade, cl_antiping_grenade, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict grenades (only enabled if cl_antiping is set to 1)")

View file

@ -341,7 +341,7 @@ void CConsole::Print(int Level, const char *pFrom, const char *pStr, ColorRGBA P
{ {
LEVEL LogLevel = IConsole::ToLogLevel(Level); LEVEL LogLevel = IConsole::ToLogLevel(Level);
// if console colors are not enabled or if the color is pure white, use default terminal color // if console colors are not enabled or if the color is pure white, use default terminal color
if(g_Config.m_ConsoleEnableColors && mem_comp(&PrintColor, &gs_ConsoleDefaultColor, sizeof(ColorRGBA)) != 0) if(g_Config.m_ConsoleEnableColors && PrintColor != gs_ConsoleDefaultColor)
{ {
log_log_color(LogLevel, ColorToLogColor(PrintColor), pFrom, "%s", pStr); log_log_color(LogLevel, ColorToLogColor(PrintColor), pFrom, "%s", pStr);
} }

View file

@ -70,18 +70,18 @@ void CEcon::Init(CConfig *pConfig, IConsole *pConsole, CNetBan *pNetBan)
} }
NETADDR BindAddr; NETADDR BindAddr;
if(g_Config.m_EcBindaddr[0] == '\0') if(g_Config.m_EcBindaddr[0] && net_host_lookup(g_Config.m_EcBindaddr, &BindAddr, NETTYPE_ALL) == 0)
{ {
mem_zero(&BindAddr, sizeof(BindAddr)); // got bindaddr
BindAddr.port = g_Config.m_EcPort;
} }
else if(net_host_lookup(g_Config.m_EcBindaddr, &BindAddr, NETTYPE_ALL) != 0) else
{ {
char aBuf[256]; char aBuf[256];
str_format(aBuf, sizeof(aBuf), "The configured bindaddr '%s' cannot be resolved.", g_Config.m_Bindaddr); str_format(aBuf, sizeof(aBuf), "The configured bindaddr '%s' cannot be resolved.", g_Config.m_EcBindaddr);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf);
return;
} }
BindAddr.type = NETTYPE_ALL;
BindAddr.port = g_Config.m_EcPort;
if(m_NetConsole.Open(BindAddr, pNetBan)) if(m_NetConsole.Open(BindAddr, pNetBan))
{ {

View file

@ -93,6 +93,7 @@ MAYBE_UNUSED static const char *FONT_ICON_EARTH_AMERICAS = "\xEF\x95\xBD";
MAYBE_UNUSED static const char *FONT_ICON_NETWORK_WIRED = "\xEF\x9B\xBF"; MAYBE_UNUSED static const char *FONT_ICON_NETWORK_WIRED = "\xEF\x9B\xBF";
MAYBE_UNUSED static const char *FONT_ICON_LIST_UL = "\xEF\x83\x8A"; MAYBE_UNUSED static const char *FONT_ICON_LIST_UL = "\xEF\x83\x8A";
MAYBE_UNUSED static const char *FONT_ICON_INFO = "\xEF\x84\xA9"; MAYBE_UNUSED static const char *FONT_ICON_INFO = "\xEF\x84\xA9";
MAYBE_UNUSED static const char *FONT_ICON_TERMINAL = "\xEF\x84\xA0";
MAYBE_UNUSED static const char *FONT_ICON_SLASH = "\xEF\x9C\x95"; MAYBE_UNUSED static const char *FONT_ICON_SLASH = "\xEF\x9C\x95";
MAYBE_UNUSED static const char *FONT_ICON_PLAY = "\xEF\x81\x8B"; MAYBE_UNUSED static const char *FONT_ICON_PLAY = "\xEF\x81\x8B";

View file

@ -160,8 +160,6 @@ class CGameConsole : public CComponent
static const ColorRGBA ms_SearchHighlightColor; static const ColorRGBA ms_SearchHighlightColor;
static const ColorRGBA ms_SearchSelectedColor; static const ColorRGBA ms_SearchSelectedColor;
void Toggle(int Type);
static void PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser); static void PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser);
static void ConToggleLocalConsole(IConsole::IResult *pResult, void *pUserData); static void ConToggleLocalConsole(IConsole::IResult *pResult, void *pUserData);
static void ConToggleRemoteConsole(IConsole::IResult *pResult, void *pUserData); static void ConToggleRemoteConsole(IConsole::IResult *pResult, void *pUserData);
@ -196,6 +194,7 @@ public:
virtual bool OnInput(const IInput::CEvent &Event) override; virtual bool OnInput(const IInput::CEvent &Event) override;
void Prompt(char (&aPrompt)[32]); void Prompt(char (&aPrompt)[32]);
void Toggle(int Type);
bool IsClosed() { return m_ConsoleState == CONSOLE_CLOSED; } bool IsClosed() { return m_ConsoleState == CONSOLE_CLOSED; }
}; };
#endif #endif

View file

@ -58,9 +58,11 @@ void CItems::RenderProjectile(const CProjectileData *pCurrent, int ItemId)
bool IsOtherTeam = (pCurrent->m_ExtraInfo && pCurrent->m_Owner >= 0 && m_pClient->IsOtherTeam(pCurrent->m_Owner)); bool IsOtherTeam = (pCurrent->m_ExtraInfo && pCurrent->m_Owner >= 0 && m_pClient->IsOtherTeam(pCurrent->m_Owner));
int predictTick = GameClient()->GetPredictionTick();
float Ct; float Ct;
if(m_pClient->Predict() && m_pClient->AntiPingGrenade() && LocalPlayerInGame && !IsOtherTeam) if(m_pClient->Predict() && m_pClient->AntiPingGrenade() && LocalPlayerInGame && !IsOtherTeam)
Ct = ((float)(Client()->PredGameTick(g_Config.m_ClDummy) - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed(); Ct = ((float)(predictTick - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed();
else else
Ct = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)Client()->GameTickSpeed() + s_LastGameTickTime; Ct = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)Client()->GameTickSpeed() + s_LastGameTickTime;
if(Ct < 0) if(Ct < 0)
@ -304,9 +306,11 @@ void CItems::RenderLaser(const CLaserData *pCurrent, bool IsPredicted)
{ {
Dir = normalize_pre_length(Pos - From, Len); Dir = normalize_pre_length(Pos - From, Len);
int predictTick = GameClient()->GetPredictionTick();
float Ticks; float Ticks;
if(IsPredicted) if(IsPredicted)
Ticks = (float)(Client()->PredGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy); Ticks = (float)(predictTick - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy);
else else
Ticks = (float)(Client()->GameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->IntraGameTick(g_Config.m_ClDummy); Ticks = (float)(Client()->GameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->IntraGameTick(g_Config.m_ClDummy);
float Ms = (Ticks / Client()->GameTickSpeed()) * 1000.0f; float Ms = (Ticks / Client()->GameTickSpeed()) * 1000.0f;
@ -377,7 +381,7 @@ void CItems::OnRender()
auto &aSwitchers = GameClient()->Switchers(); auto &aSwitchers = GameClient()->Switchers();
if(UsePredicted) if(UsePredicted)
{ {
for(auto *pProj = (CProjectile *)GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile *)pProj->NextEntity()) for(auto *pProj = (CProjectile *)GameClient()->m_PrevPredictedWorld.FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile *)pProj->NextEntity())
{ {
if(!IsSuper && pProj->m_Number > 0 && pProj->m_Number < (int)aSwitchers.size() && !aSwitchers[pProj->m_Number].m_aStatus[SwitcherTeam] && (pProj->m_Explosive ? BlinkingProjEx : BlinkingProj)) if(!IsSuper && pProj->m_Number > 0 && pProj->m_Number < (int)aSwitchers.size() && !aSwitchers[pProj->m_Number].m_aStatus[SwitcherTeam] && (pProj->m_Explosive ? BlinkingProjEx : BlinkingProj))
continue; continue;
@ -385,7 +389,7 @@ void CItems::OnRender()
CProjectileData Data = pProj->GetData(); CProjectileData Data = pProj->GetData();
RenderProjectile(&Data, pProj->GetId()); RenderProjectile(&Data, pProj->GetId());
} }
for(CEntity *pEnt = GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_LASER); pEnt; pEnt = pEnt->NextEntity()) for(CEntity *pEnt = GameClient()->m_PrevPredictedWorld.FindFirst(CGameWorld::ENTTYPE_LASER); pEnt; pEnt = pEnt->NextEntity())
{ {
auto *const pLaser = dynamic_cast<CLaser *>(pEnt); auto *const pLaser = dynamic_cast<CLaser *>(pEnt);
if(!pLaser || pLaser->GetOwner() < 0 || !GameClient()->m_aClients[pLaser->GetOwner()].m_IsPredictedLocal) if(!pLaser || pLaser->GetOwner() < 0 || !GameClient()->m_aClients[pLaser->GetOwner()].m_IsPredictedLocal)
@ -393,7 +397,7 @@ void CItems::OnRender()
CLaserData Data = pLaser->GetData(); CLaserData Data = pLaser->GetData();
RenderLaser(&Data, true); RenderLaser(&Data, true);
} }
for(auto *pPickup = (CPickup *)GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_PICKUP); pPickup; pPickup = (CPickup *)pPickup->NextEntity()) for(auto *pPickup = (CPickup *)GameClient()->m_PrevPredictedWorld.FindFirst(CGameWorld::ENTTYPE_PICKUP); pPickup; pPickup = (CPickup *)pPickup->NextEntity())
{ {
if(!IsSuper && pPickup->m_Layer == LAYER_SWITCH && pPickup->m_Number > 0 && pPickup->m_Number < (int)aSwitchers.size() && !aSwitchers[pPickup->m_Number].m_aStatus[SwitcherTeam] && BlinkingPickup) if(!IsSuper && pPickup->m_Layer == LAYER_SWITCH && pPickup->m_Number > 0 && pPickup->m_Number < (int)aSwitchers.size() && !aSwitchers[pPickup->m_Number].m_aStatus[SwitcherTeam] && BlinkingPickup)
continue; continue;
@ -601,7 +605,10 @@ void CItems::ReconstructSmokeTrail(const CProjectileData *pCurrent, int DestroyT
LocalPlayerInGame = m_pClient->m_aClients[m_pClient->m_Snap.m_pLocalInfo->m_ClientId].m_Team != TEAM_SPECTATORS; LocalPlayerInGame = m_pClient->m_aClients[m_pClient->m_Snap.m_pLocalInfo->m_ClientId].m_Team != TEAM_SPECTATORS;
if(!m_pClient->AntiPingGunfire() || !LocalPlayerInGame) if(!m_pClient->AntiPingGunfire() || !LocalPlayerInGame)
return; return;
if(Client()->PredGameTick(g_Config.m_ClDummy) == pCurrent->m_StartTick)
int predictTick = GameClient()->GetPredictionTick();
if(predictTick == pCurrent->m_StartTick)
return; return;
// get positions // get positions
@ -625,7 +632,7 @@ void CItems::ReconstructSmokeTrail(const CProjectileData *pCurrent, int DestroyT
Speed = pTuning->m_GunSpeed; Speed = pTuning->m_GunSpeed;
} }
float Pt = ((float)(Client()->PredGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed(); float Pt = ((float)(predictTick - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed();
if(Pt < 0) if(Pt < 0)
return; // projectile haven't been shot yet return; // projectile haven't been shot yet

View file

@ -17,6 +17,8 @@
#include "menus.h" #include "menus.h"
using namespace FontIcons;
void CMenus::RenderStartMenu(CUIRect MainView) void CMenus::RenderStartMenu(CUIRect MainView)
{ {
GameClient()->m_MenuBackground.ChangePosition(CMenuBackground::POS_START); GameClient()->m_MenuBackground.ChangePosition(CMenuBackground::POS_START);
@ -186,13 +188,27 @@ void CMenus::RenderStartMenu(CUIRect MainView)
} }
// render version // render version
CUIRect VersionUpdate, CurVersion; CUIRect CurVersion, ConsoleButton;
MainView.HSplitBottom(20.0f, nullptr, &VersionUpdate); MainView.HSplitBottom(45.0f, nullptr, &CurVersion);
VersionUpdate.VSplitRight(50.0f, &CurVersion, nullptr); CurVersion.VSplitRight(40.0f, &CurVersion, nullptr);
VersionUpdate.VMargin(VMargin, &VersionUpdate); CurVersion.HSplitTop(20.0f, &ConsoleButton, &CurVersion);
CurVersion.HSplitTop(5.0f, nullptr, &CurVersion);
ConsoleButton.VSplitRight(40.0f, nullptr, &ConsoleButton);
Ui()->DoLabel(&CurVersion, GAME_RELEASE_VERSION, 14.0f, TEXTALIGN_MR); Ui()->DoLabel(&CurVersion, GAME_RELEASE_VERSION, 14.0f, TEXTALIGN_MR);
static CButtonContainer s_ConsoleButton;
TextRender()->SetFontPreset(EFontPreset::ICON_FONT);
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE);
if(DoButton_Menu(&s_ConsoleButton, FONT_ICON_TERMINAL, 0, &ConsoleButton, nullptr, IGraphics::CORNER_ALL, 5.0f, 0.0f, ColorRGBA(0.0f, 0.0f, 0.0f, 0.1f)))
{
GameClient()->m_GameConsole.Toggle(CGameConsole::CONSOLETYPE_LOCAL);
}
TextRender()->SetRenderFlags(0);
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
CUIRect VersionUpdate;
MainView.HSplitBottom(20.0f, nullptr, &VersionUpdate);
VersionUpdate.VMargin(VMargin, &VersionUpdate);
#if defined(CONF_AUTOUPDATE) #if defined(CONF_AUTOUPDATE)
CUIRect UpdateButton; CUIRect UpdateButton;
VersionUpdate.VSplitRight(100.0f, &VersionUpdate, &UpdateButton); VersionUpdate.VSplitRight(100.0f, &VersionUpdate, &UpdateButton);

View file

@ -2100,6 +2100,25 @@ void CGameClient::UpdateEditorIngameMoved()
} }
} }
int CGameClient::GetPredictionTick()
{
int predictTick = Client()->GetPredictionTime() * Client()->GameTickSpeed() / 1000.0f;
float predictPercentage = 1 - g_Config.m_ClAntiPingpercent / 100.0f;
int predictMin = std::floor(predictTick * predictPercentage);
int predictMin2 = g_Config.m_ClAntiPingLimit * Client()->GameTickSpeed() / 1000.0f;
if (g_Config.m_ClAntiPingLimit != 0)
predictMin = predictMin2;
predictTick = Client()->PredGameTick(g_Config.m_ClDummy) - predictMin;
if(predictTick < Client()->GameTick(g_Config.m_ClDummy) + 1)
{
predictTick = Client()->GameTick(g_Config.m_ClDummy) + 1;
}
return predictTick;
}
void CGameClient::OnPredict() void CGameClient::OnPredict()
{ {
// store the previous values so we can detect prediction errors // store the previous values so we can detect prediction errors
@ -2156,20 +2175,33 @@ void CGameClient::OnPredict()
CCharacter *pDummyChar = 0; CCharacter *pDummyChar = 0;
if(PredictDummy()) if(PredictDummy())
pDummyChar = m_PredictedWorld.GetCharacterById(m_PredictedDummyId); pDummyChar = m_PredictedWorld.GetCharacterById(m_PredictedDummyId);
int predictTick = GetPredictionTick();
// predict // predict
for(int Tick = Client()->GameTick(g_Config.m_ClDummy) + 1; Tick <= Client()->PredGameTick(g_Config.m_ClDummy); Tick++) for(int Tick = Client()->GameTick(g_Config.m_ClDummy) + 1; Tick <= Client()->PredGameTick(g_Config.m_ClDummy); Tick++)
{ {
// fetch the previous characters // fetch the previous characters
if(Tick == Client()->PredGameTick(g_Config.m_ClDummy)) if(Tick == predictTick)
{ {
m_PrevPredictedWorld.CopyWorld(&m_PredictedWorld);
m_PredictedPrevChar = pLocalChar->GetCore();
for(int i = 0; i < MAX_CLIENTS; i++) for(int i = 0; i < MAX_CLIENTS; i++)
if(CCharacter *pChar = m_PredictedWorld.GetCharacterById(i)) if(CCharacter *pChar = m_PredictedWorld.GetCharacterById(i))
m_aClients[i].m_PrevPredicted = pChar->GetCore(); m_aClients[i].m_PrevPredicted = pChar->GetCore();
} }
if(Tick == Client()->PredGameTick(g_Config.m_ClDummy))
{
m_PredictedPrevChar = pLocalChar->GetCore();
m_aClients[m_Snap.m_LocalClientId].m_PrevPredicted = pLocalChar->GetCore();
if(pDummyChar)
m_aClients[m_PredictedDummyId].m_PrevPredicted = pDummyChar->GetCore();
}
if(Tick == predictTick)
{
m_PrevPredictedWorld.CopyWorld(&m_PredictedWorld);
}
// optionally allow some movement in freeze by not predicting freeze the last one to two ticks // optionally allow some movement in freeze by not predicting freeze the last one to two ticks
if(g_Config.m_ClPredictFreeze == 2 && Client()->PredGameTick(g_Config.m_ClDummy) - 1 - Client()->PredGameTick(g_Config.m_ClDummy) % 2 <= Tick) if(g_Config.m_ClPredictFreeze == 2 && Client()->PredGameTick(g_Config.m_ClDummy) - 1 - Client()->PredGameTick(g_Config.m_ClDummy) % 2 <= Tick)
pLocalChar->m_CanMoveInFreeze = true; pLocalChar->m_CanMoveInFreeze = true;
@ -2193,14 +2225,22 @@ void CGameClient::OnPredict()
m_PredictedWorld.Tick(); m_PredictedWorld.Tick();
// fetch the current characters // fetch the current characters
if(Tick == Client()->PredGameTick(g_Config.m_ClDummy)) if(Tick == predictTick)
{ {
m_PredictedChar = pLocalChar->GetCore();
for(int i = 0; i < MAX_CLIENTS; i++) for(int i = 0; i < MAX_CLIENTS; i++)
if(CCharacter *pChar = m_PredictedWorld.GetCharacterById(i)) if(CCharacter *pChar = m_PredictedWorld.GetCharacterById(i))
m_aClients[i].m_Predicted = pChar->GetCore(); m_aClients[i].m_Predicted = pChar->GetCore();
} }
if(Tick == Client()->PredGameTick(g_Config.m_ClDummy))
{
m_PredictedChar = pLocalChar->GetCore();
m_aClients[m_Snap.m_LocalClientId].m_Predicted = pLocalChar->GetCore();
if(pDummyChar)
m_aClients[m_PredictedDummyId].m_Predicted = pDummyChar->GetCore();
}
for(int i = 0; i < MAX_CLIENTS; i++) for(int i = 0; i < MAX_CLIENTS; i++)
if(CCharacter *pChar = m_PredictedWorld.GetCharacterById(i)) if(CCharacter *pChar = m_PredictedWorld.GetCharacterById(i))
{ {

View file

@ -499,6 +499,7 @@ public:
CRenderTools m_RenderTools; CRenderTools m_RenderTools;
void OnReset(); void OnReset();
int GetPredictionTick();
size_t ComponentCount() { return m_vpAll.size(); } size_t ComponentCount() { return m_vpAll.size(); }

View file

@ -57,7 +57,7 @@ void CUIElement::SUIElementRect::Reset()
void CUIElement::SUIElementRect::Draw(const CUIRect *pRect, ColorRGBA Color, int Corners, float Rounding) void CUIElement::SUIElementRect::Draw(const CUIRect *pRect, ColorRGBA Color, int Corners, float Rounding)
{ {
bool NeedsRecreate = false; bool NeedsRecreate = false;
if(m_UIRectQuadContainer == -1 || m_Width != pRect->w || m_Height != pRect->h || mem_comp(&m_QuadColor, &Color, sizeof(Color)) != 0) if(m_UIRectQuadContainer == -1 || m_Width != pRect->w || m_Height != pRect->h || m_QuadColor != Color)
{ {
m_pParent->Ui()->Graphics()->DeleteQuadContainer(m_UIRectQuadContainer); m_pParent->Ui()->Graphics()->DeleteQuadContainer(m_UIRectQuadContainer);
NeedsRecreate = true; NeedsRecreate = true;

View file

@ -4384,7 +4384,7 @@ bool CEditor::ReplaceImage(const char *pFileName, int StorageType, bool CheckDup
} }
} }
CEditorImage ImgInfo(this); CImageInfo ImgInfo;
if(!Graphics()->LoadPng(ImgInfo, pFileName, StorageType)) if(!Graphics()->LoadPng(ImgInfo, pFileName, StorageType))
{ {
ShowFileDialogError("Failed to load image from file '%s'.", pFileName); ShowFileDialogError("Failed to load image from file '%s'.", pFileName);
@ -4394,21 +4394,33 @@ bool CEditor::ReplaceImage(const char *pFileName, int StorageType, bool CheckDup
std::shared_ptr<CEditorImage> pImg = m_Map.m_vpImages[m_SelectedImage]; std::shared_ptr<CEditorImage> pImg = m_Map.m_vpImages[m_SelectedImage];
Graphics()->UnloadTexture(&(pImg->m_Texture)); Graphics()->UnloadTexture(&(pImg->m_Texture));
pImg->Free(); pImg->Free();
*pImg = ImgInfo; pImg->m_Width = ImgInfo.m_Width;
pImg->m_Height = ImgInfo.m_Height;
pImg->m_Format = ImgInfo.m_Format;
pImg->m_pData = ImgInfo.m_pData;
str_copy(pImg->m_aName, aBuf); str_copy(pImg->m_aName, aBuf);
pImg->m_External = IsVanillaImage(pImg->m_aName); pImg->m_External = IsVanillaImage(pImg->m_aName);
if(!pImg->m_External && g_Config.m_ClEditorDilate == 1 && pImg->m_Format == CImageInfo::FORMAT_RGBA) if(!pImg->m_External && pImg->m_Format != CImageInfo::FORMAT_RGBA)
{ {
DilateImage(ImgInfo.m_pData, ImgInfo.m_Width, ImgInfo.m_Height); uint8_t *pRgbaData = static_cast<uint8_t *>(malloc((size_t)pImg->m_Width * pImg->m_Height * CImageInfo::PixelSize(CImageInfo::FORMAT_RGBA)));
ConvertToRGBA(pRgbaData, *pImg);
free(pImg->m_pData);
pImg->m_pData = pRgbaData;
pImg->m_Format = CImageInfo::FORMAT_RGBA;
}
if(!pImg->m_External && g_Config.m_ClEditorDilate == 1)
{
DilateImage(pImg->m_pData, pImg->m_Width, pImg->m_Height);
} }
pImg->m_AutoMapper.Load(pImg->m_aName); pImg->m_AutoMapper.Load(pImg->m_aName);
int TextureLoadFlag = Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE; int TextureLoadFlag = Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0) if(pImg->m_Width % 16 != 0 || pImg->m_Height % 16 != 0)
TextureLoadFlag = 0; TextureLoadFlag = 0;
pImg->m_Texture = Graphics()->LoadTextureRaw(ImgInfo, TextureLoadFlag, pFileName); pImg->m_Texture = Graphics()->LoadTextureRaw(*pImg, TextureLoadFlag, pFileName);
ImgInfo.m_pData = nullptr;
SortImages(); SortImages();
for(size_t i = 0; i < m_Map.m_vpImages.size(); ++i) for(size_t i = 0; i < m_Map.m_vpImages.size(); ++i)
{ {
@ -4447,7 +4459,7 @@ bool CEditor::AddImage(const char *pFileName, int StorageType, void *pUser)
return false; return false;
} }
CEditorImage ImgInfo(pEditor); CImageInfo ImgInfo;
if(!pEditor->Graphics()->LoadPng(ImgInfo, pFileName, StorageType)) if(!pEditor->Graphics()->LoadPng(ImgInfo, pFileName, StorageType))
{ {
pEditor->ShowFileDialogError("Failed to load image from file '%s'.", pFileName); pEditor->ShowFileDialogError("Failed to load image from file '%s'.", pFileName);
@ -4455,19 +4467,30 @@ bool CEditor::AddImage(const char *pFileName, int StorageType, void *pUser)
} }
std::shared_ptr<CEditorImage> pImg = std::make_shared<CEditorImage>(pEditor); std::shared_ptr<CEditorImage> pImg = std::make_shared<CEditorImage>(pEditor);
*pImg = ImgInfo; pImg->m_Width = ImgInfo.m_Width;
pImg->m_Height = ImgInfo.m_Height;
pImg->m_Format = ImgInfo.m_Format;
pImg->m_pData = ImgInfo.m_pData;
pImg->m_External = IsVanillaImage(aBuf); pImg->m_External = IsVanillaImage(aBuf);
if(!pImg->m_External && g_Config.m_ClEditorDilate == 1 && pImg->m_Format == CImageInfo::FORMAT_RGBA) if(pImg->m_Format != CImageInfo::FORMAT_RGBA)
{ {
DilateImage(ImgInfo.m_pData, ImgInfo.m_Width, ImgInfo.m_Height); uint8_t *pRgbaData = static_cast<uint8_t *>(malloc((size_t)pImg->m_Width * pImg->m_Height * CImageInfo::PixelSize(CImageInfo::FORMAT_RGBA)));
ConvertToRGBA(pRgbaData, *pImg);
free(pImg->m_pData);
pImg->m_pData = pRgbaData;
pImg->m_Format = CImageInfo::FORMAT_RGBA;
}
if(!pImg->m_External && g_Config.m_ClEditorDilate == 1)
{
DilateImage(pImg->m_pData, pImg->m_Width, pImg->m_Height);
} }
int TextureLoadFlag = pEditor->Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE; int TextureLoadFlag = pEditor->Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0) if(pImg->m_Width % 16 != 0 || pImg->m_Height % 16 != 0)
TextureLoadFlag = 0; TextureLoadFlag = 0;
pImg->m_Texture = pEditor->Graphics()->LoadTextureRaw(ImgInfo, TextureLoadFlag, pFileName); pImg->m_Texture = pEditor->Graphics()->LoadTextureRaw(*pImg, TextureLoadFlag, pFileName);
ImgInfo.m_pData = nullptr;
str_copy(pImg->m_aName, aBuf); str_copy(pImg->m_aName, aBuf);
pImg->m_AutoMapper.Load(pImg->m_aName); pImg->m_AutoMapper.Load(pImg->m_aName);
pEditor->m_Map.m_vpImages.push_back(pImg); pEditor->m_Map.m_vpImages.push_back(pImg);

View file

@ -509,6 +509,15 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
pImg->m_Height = ImgInfo.m_Height; pImg->m_Height = ImgInfo.m_Height;
pImg->m_Format = ImgInfo.m_Format; pImg->m_Format = ImgInfo.m_Format;
pImg->m_pData = ImgInfo.m_pData; pImg->m_pData = ImgInfo.m_pData;
if(pImg->m_Format != CImageInfo::FORMAT_RGBA)
{
uint8_t *pRgbaData = static_cast<uint8_t *>(malloc((size_t)pImg->m_Width * pImg->m_Height * CImageInfo::PixelSize(CImageInfo::FORMAT_RGBA)));
ConvertToRGBA(pRgbaData, *pImg);
free(pImg->m_pData);
pImg->m_pData = pRgbaData;
pImg->m_Format = CImageInfo::FORMAT_RGBA;
}
int TextureLoadFlag = m_pEditor->Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE; int TextureLoadFlag = m_pEditor->Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0) if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0)
TextureLoadFlag = 0; TextureLoadFlag = 0;

View file

@ -123,6 +123,13 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos)
delete GameServer()->m_apSavedTees[m_pPlayer->GetCid()]; delete GameServer()->m_apSavedTees[m_pPlayer->GetCid()];
GameServer()->m_apSavedTees[m_pPlayer->GetCid()] = nullptr; GameServer()->m_apSavedTees[m_pPlayer->GetCid()] = nullptr;
} }
if(GameServer()->m_apSavedTeleTees[m_pPlayer->GetCid()])
{
m_pPlayer->m_LastTeleTee = *GameServer()->m_apSavedTeleTees[m_pPlayer->GetCid()];
delete GameServer()->m_apSavedTeleTees[m_pPlayer->GetCid()];
GameServer()->m_apSavedTeleTees[m_pPlayer->GetCid()] = nullptr;
}
} }
return true; return true;

View file

@ -108,6 +108,9 @@ void CGameContext::Construct(int Resetting)
for(auto &pSavedTee : m_apSavedTees) for(auto &pSavedTee : m_apSavedTees)
pSavedTee = nullptr; pSavedTee = nullptr;
for(auto &pSavedTeleTee : m_apSavedTeleTees)
pSavedTeleTee = nullptr;
for(auto &pSavedTeam : m_apSavedTeams) for(auto &pSavedTeam : m_apSavedTeams)
pSavedTeam = nullptr; pSavedTeam = nullptr;
@ -131,6 +134,9 @@ void CGameContext::Destruct(int Resetting)
for(auto &pSavedTee : m_apSavedTees) for(auto &pSavedTee : m_apSavedTees)
delete pSavedTee; delete pSavedTee;
for(auto &pSavedTeleTee : m_apSavedTeleTees)
delete pSavedTeleTee;
for(auto &pSavedTeam : m_apSavedTeams) for(auto &pSavedTeam : m_apSavedTeams)
delete pSavedTeam; delete pSavedTeam;
@ -773,7 +779,6 @@ void CGameContext::StartVote(const char *pDesc, const char *pCommand, const char
{ {
// reset votes // reset votes
m_VoteEnforce = VOTE_ENFORCE_UNKNOWN; m_VoteEnforce = VOTE_ENFORCE_UNKNOWN;
m_VoteEnforcer = -1;
for(auto &pPlayer : m_apPlayers) for(auto &pPlayer : m_apPlayers)
{ {
if(pPlayer) if(pPlayer)
@ -1204,7 +1209,7 @@ void CGameContext::OnTick()
} }
else if(m_VoteEnforce == VOTE_ENFORCE_YES_ADMIN) else if(m_VoteEnforce == VOTE_ENFORCE_YES_ADMIN)
{ {
Console()->ExecuteLine(m_aVoteCommand, m_VoteEnforcer); Console()->ExecuteLine(m_aVoteCommand, m_VoteCreator);
SendChat(-1, TEAM_ALL, "Vote passed enforced by authorized player", -1, FLAG_SIX); SendChat(-1, TEAM_ALL, "Vote passed enforced by authorized player", -1, FLAG_SIX);
EndVote(); EndVote();
} }
@ -1712,6 +1717,9 @@ void CGameContext::OnClientDrop(int ClientId, const char *pReason)
delete m_apSavedTees[ClientId]; delete m_apSavedTees[ClientId];
m_apSavedTees[ClientId] = nullptr; m_apSavedTees[ClientId] = nullptr;
delete m_apSavedTeleTees[ClientId];
m_apSavedTeleTees[ClientId] = nullptr;
m_aTeamMapping[ClientId] = -1; m_aTeamMapping[ClientId] = -1;
m_VoteUpdate = true; m_VoteUpdate = true;
@ -3208,12 +3216,19 @@ void CGameContext::ConHotReload(IConsole::IResult *pResult, void *pUserData)
if(!pSelf->GetPlayerChar(i)) if(!pSelf->GetPlayerChar(i))
continue; continue;
CCharacter *pChar = pSelf->GetPlayerChar(i);
// Save the tee individually // Save the tee individually
pSelf->m_apSavedTees[i] = new CSaveTee(); pSelf->m_apSavedTees[i] = new CSaveTee();
pSelf->m_apSavedTees[i]->Save(pSelf->GetPlayerChar(i), false); pSelf->m_apSavedTees[i]->Save(pChar, false);
if(pSelf->m_apPlayers[i])
pSelf->m_apSavedTeleTees[i] = new CSaveTee(pSelf->m_apPlayers[i]->m_LastTeleTee);
// Save the team state // Save the team state
pSelf->m_aTeamMapping[i] = pSelf->GetDDRaceTeam(i); pSelf->m_aTeamMapping[i] = pSelf->GetDDRaceTeam(i);
if(pSelf->m_aTeamMapping[i] == TEAM_SUPER)
pSelf->m_aTeamMapping[i] = pChar->m_TeamBeforeSuper;
if(pSelf->m_apSavedTeams[pSelf->m_aTeamMapping[i]]) if(pSelf->m_apSavedTeams[pSelf->m_aTeamMapping[i]])
continue; continue;
@ -4820,7 +4835,6 @@ void CGameContext::ForceVote(int EnforcerId, bool Success)
return; return;
m_VoteEnforce = Success ? CGameContext::VOTE_ENFORCE_YES_ADMIN : CGameContext::VOTE_ENFORCE_NO_ADMIN; m_VoteEnforce = Success ? CGameContext::VOTE_ENFORCE_YES_ADMIN : CGameContext::VOTE_ENFORCE_NO_ADMIN;
m_VoteEnforcer = EnforcerId;
char aBuf[256]; char aBuf[256];
const char *pOption = Success ? "yes" : "no"; const char *pOption = Success ? "yes" : "no";

View file

@ -183,6 +183,7 @@ public:
bool m_aPlayerHasInput[MAX_CLIENTS]; bool m_aPlayerHasInput[MAX_CLIENTS];
CSaveTeam *m_apSavedTeams[MAX_CLIENTS]; CSaveTeam *m_apSavedTeams[MAX_CLIENTS];
CSaveTee *m_apSavedTees[MAX_CLIENTS]; CSaveTee *m_apSavedTees[MAX_CLIENTS];
CSaveTee *m_apSavedTeleTees[MAX_CLIENTS];
int m_aTeamMapping[MAX_CLIENTS]; int m_aTeamMapping[MAX_CLIENTS];
// returns last input if available otherwise nulled PlayerInput object // returns last input if available otherwise nulled PlayerInput object
@ -575,7 +576,6 @@ public:
VOTE_TYPE_SPECTATE, VOTE_TYPE_SPECTATE,
}; };
int m_VoteVictim; int m_VoteVictim;
int m_VoteEnforcer;
inline bool IsOptionVote() const { return m_VoteType == VOTE_TYPE_OPTION; } inline bool IsOptionVote() const { return m_VoteType == VOTE_TYPE_OPTION; }
inline bool IsKickVote() const { return m_VoteType == VOTE_TYPE_KICK; } inline bool IsKickVote() const { return m_VoteType == VOTE_TYPE_KICK; }