Compare commits

..

17 commits

Author SHA1 Message Date
Robert Müller 8ef01fcbaf
Merge 4df4fa237e into 306d3c7b58 2024-09-07 13:09:06 +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
Dennis Felsing e0a95d14a6
Merge pull request #8898 from KebsCS/pr-country-filters
Change country and types filter behavior
2024-09-05 13:16:21 +00:00
KebsCS fa28ed77a6
Change country and types filter behavior 2024-09-05 14:24:11 +02:00
Dennis Felsing 5335813629
Merge pull request #8897 from KebsCS/pr-command-argument-validation
Fix /tpxy arg validation
2024-09-05 09:26:15 +00:00
KebsCS 796fa4275f
Fix tpxy arg validation 2024-09-05 11:04:03 +02:00
Dennis Felsing 5b0163d069
Merge pull request #8896 from dobrykafe/pr-auto-map-reload-setting
Add `ed_auto_map_reload` setting
2024-09-05 07:33:35 +00:00
dobrykafe c9e7e0f01b add ed_auto_map_reload setting 2024-09-05 00:23:03 +02:00
14 changed files with 126 additions and 43 deletions

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

@ -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));
@ -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();
} }
} }

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

@ -27,9 +27,6 @@
#include <engine/http.h> #include <engine/http.h>
#include <engine/storage.h> #include <engine/storage.h>
static constexpr const char *COMMUNITY_COUNTRY_NONE = "none";
static constexpr const char *COMMUNITY_TYPE_NONE = "None";
class CSortWrap class CSortWrap
{ {
typedef bool (CServerBrowser::*SortFunc)(int, int) const; typedef bool (CServerBrowser::*SortFunc)(int, int) const;

View file

@ -309,6 +309,9 @@ public:
static constexpr const char *COMMUNITY_DDNET = "ddnet"; static constexpr const char *COMMUNITY_DDNET = "ddnet";
static constexpr const char *COMMUNITY_NONE = "none"; static constexpr const char *COMMUNITY_NONE = "none";
static constexpr const char *COMMUNITY_COUNTRY_NONE = "none";
static constexpr const char *COMMUNITY_TYPE_NONE = "None";
/** /**
* Special community value for country/type filters that * Special community value for country/type filters that
* affect all communities. * affect all communities.

View file

@ -110,6 +110,7 @@ MACRO_CONFIG_INT(EdZoomTarget, ed_zoom_target, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG
MACRO_CONFIG_INT(EdShowkeys, ed_showkeys, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show pressed keys") MACRO_CONFIG_INT(EdShowkeys, ed_showkeys, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show pressed keys")
MACRO_CONFIG_INT(EdAlignQuads, ed_align_quads, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Enable/disable quad alignment. When enabled, red lines appear to show how quad/points are aligned and snapped to other quads/points when moving them") MACRO_CONFIG_INT(EdAlignQuads, ed_align_quads, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Enable/disable quad alignment. When enabled, red lines appear to show how quad/points are aligned and snapped to other quads/points when moving them")
MACRO_CONFIG_INT(EdShowQuadsRect, ed_show_quads_rect, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show the bounds of the selected quad. In case of multiple quads, it shows the bounds of the englobing rect. Can be helpful when aligning a group of quads") MACRO_CONFIG_INT(EdShowQuadsRect, ed_show_quads_rect, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show the bounds of the selected quad. In case of multiple quads, it shows the bounds of the englobing rect. Can be helpful when aligning a group of quads")
MACRO_CONFIG_INT(EdAutoMapReload, ed_auto_map_reload, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Run 'hot_reload' on the local server while rcon authed on map save")
MACRO_CONFIG_INT(ClShowWelcome, cl_show_welcome, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show welcome message indicating the first launch of the client") MACRO_CONFIG_INT(ClShowWelcome, cl_show_welcome, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show welcome message indicating the first launch of the client")
MACRO_CONFIG_INT(ClMotdTime, cl_motd_time, 10, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "How long to show the server message of the day") MACRO_CONFIG_INT(ClMotdTime, cl_motd_time, 10, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "How long to show the server message of the day")

View file

@ -136,7 +136,7 @@ int CConsole::ParseStart(CResult *pResult, const char *pString, int Length)
return 0; return 0;
} }
int CConsole::ParseArgs(CResult *pResult, const char *pFormat, FCommandCallback pfnCallback) int CConsole::ParseArgs(CResult *pResult, const char *pFormat, bool IsColor)
{ {
char Command = *pFormat; char Command = *pFormat;
char *pStr; char *pStr;
@ -235,7 +235,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat, FCommandCallback
if(Command == 'i') if(Command == 'i')
{ {
// don't validate colors here // don't validate colors here
if(pfnCallback != &SColorConfigVariable::CommandCallback) if(!IsColor)
{ {
int Value; int Value;
if(!str_toint(pResult->GetString(pResult->NumArguments() - 1), &Value) || if(!str_toint(pResult->GetString(pResult->NumArguments() - 1), &Value) ||
@ -514,7 +514,7 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientId, bo
if(Stroke || IsStrokeCommand) if(Stroke || IsStrokeCommand)
{ {
if(int Error = ParseArgs(&Result, pCommand->m_pParams, pCommand->m_pfnCallback)) if(int Error = ParseArgs(&Result, pCommand->m_pParams, pCommand->m_pfnCallback == &SColorConfigVariable::CommandCallback))
{ {
char aBuf[CMDLINE_LENGTH + 64]; char aBuf[CMDLINE_LENGTH + 64];
if(Error == PARSEARGS_INVALID_INTEGER) if(Error == PARSEARGS_INVALID_INTEGER)

View file

@ -153,7 +153,7 @@ class CConsole : public IConsole
PARSEARGS_INVALID_FLOAT, PARSEARGS_INVALID_FLOAT,
}; };
int ParseArgs(CResult *pResult, const char *pFormat, FCommandCallback pfnCallback = 0); int ParseArgs(CResult *pResult, const char *pFormat, bool IsColor = false);
/* /*
this function will set pFormat to the next parameter (i,s,r,v,?) it contains and this function will set pFormat to the next parameter (i,s,r,v,?) it contains and

View file

@ -869,11 +869,14 @@ void CMenus::RenderServerbrowserDDNetFilter(CUIRect View,
{ {
if(Click == 1) if(Click == 1)
{ {
// Left click: when all are active, only activate one // Left click: when all are active, only activate one and none
for(int j = 0; j < MaxItems; ++j) for(int j = 0; j < MaxItems; ++j)
{ {
if(j != ItemIndex) if(const char *pItemName = GetItemName(j);
Filter.Add(GetItemName(j)); j != ItemIndex &&
!((&Filter == &ServerBrowser()->CountriesFilter() && str_comp(pItemName, IServerBrowser::COMMUNITY_COUNTRY_NONE) == 0) ||
(&Filter == &ServerBrowser()->TypesFilter() && str_comp(pItemName, IServerBrowser::COMMUNITY_TYPE_NONE) == 0)))
Filter.Add(pItemName);
} }
} }
else if(Click == 2) else if(Click == 2)
@ -890,7 +893,10 @@ void CMenus::RenderServerbrowserDDNetFilter(CUIRect View,
bool AllFilteredExceptUs = true; bool AllFilteredExceptUs = true;
for(int j = 0; j < MaxItems; ++j) for(int j = 0; j < MaxItems; ++j)
{ {
if(j != ItemIndex && !Filter.Filtered(GetItemName(j))) if(const char *pItemName = GetItemName(j);
j != ItemIndex && !Filter.Filtered(pItemName) &&
!((&Filter == &ServerBrowser()->CountriesFilter() && str_comp(pItemName, IServerBrowser::COMMUNITY_COUNTRY_NONE) == 0) ||
(&Filter == &ServerBrowser()->TypesFilter() && str_comp(pItemName, IServerBrowser::COMMUNITY_TYPE_NONE) == 0)))
{ {
AllFilteredExceptUs = false; AllFilteredExceptUs = false;
break; break;
@ -898,7 +904,7 @@ void CMenus::RenderServerbrowserDDNetFilter(CUIRect View,
} }
// When last one is removed, re-enable all currently selectable items. // When last one is removed, re-enable all currently selectable items.
// Don't use Clear, to avoid enabling also currently unselectable items. // Don't use Clear, to avoid enabling also currently unselectable items.
if(AllFilteredExceptUs) if(AllFilteredExceptUs && Active)
{ {
for(int j = 0; j < MaxItems; ++j) for(int j = 0; j < MaxItems; ++j)
{ {

View file

@ -7691,7 +7691,7 @@ void CEditor::RenderMenubar(CUIRect MenuBar)
if(DoButton_Ex(&s_SettingsButton, "Settings", 0, &SettingsButton, 0, nullptr, IGraphics::CORNER_T, EditorFontSizes::MENU, TEXTALIGN_ML)) if(DoButton_Ex(&s_SettingsButton, "Settings", 0, &SettingsButton, 0, nullptr, IGraphics::CORNER_T, EditorFontSizes::MENU, TEXTALIGN_ML))
{ {
static SPopupMenuId s_PopupMenuEntitiesId; static SPopupMenuId s_PopupMenuEntitiesId;
Ui()->DoPopupMenu(&s_PopupMenuEntitiesId, SettingsButton.x, SettingsButton.y + SettingsButton.h - 1.0f, 200.0f, 92.0f, this, PopupMenuSettings, PopupProperties); Ui()->DoPopupMenu(&s_PopupMenuEntitiesId, SettingsButton.x, SettingsButton.y + SettingsButton.h - 1.0f, 200.0f, 106.0f, this, PopupMenuSettings, PopupProperties);
} }
CUIRect ChangedIndicator, Info, Help, Close; CUIRect ChangedIndicator, Info, Help, Close;
@ -8592,7 +8592,7 @@ void CEditor::HandleWriterFinishJobs()
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "editor/save", aBuf); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "editor/save", aBuf);
// send rcon.. if we can // send rcon.. if we can
if(Client()->RconAuthed()) if(Client()->RconAuthed() && g_Config.m_EdAutoMapReload)
{ {
CServerInfo CurrentServerInfo; CServerInfo CurrentServerInfo;
Client()->GetServerInfo(&CurrentServerInfo); Client()->GetServerInfo(&CurrentServerInfo);

View file

@ -371,6 +371,30 @@ CUi::EPopupMenuFunctionResult CEditor::PopupMenuSettings(void *pContext, CUIRect
} }
} }
View.HSplitTop(2.0f, nullptr, &View);
View.HSplitTop(12.0f, &Slot, &View);
{
Slot.VMargin(5.0f, &Slot);
CUIRect Label, Selector;
Slot.VSplitMid(&Label, &Selector);
CUIRect No, Yes;
Selector.VSplitMid(&No, &Yes);
pEditor->Ui()->DoLabel(&Label, "Auto map reload", 10.0f, TEXTALIGN_ML);
static int s_ButtonNo = 0;
static int s_ButtonYes = 0;
if(pEditor->DoButton_Ex(&s_ButtonNo, "No", !g_Config.m_EdAutoMapReload, &No, 0, "Do not run 'hot_reload' on the local server while rcon authed on map save", IGraphics::CORNER_L))
{
g_Config.m_EdAutoMapReload = false;
}
if(pEditor->DoButton_Ex(&s_ButtonYes, "Yes", g_Config.m_EdAutoMapReload, &Yes, 0, "Run 'hot_reload' on the local server while rcon authed on map save", IGraphics::CORNER_R))
{
g_Config.m_EdAutoMapReload = true;
}
}
return CUi::POPUP_KEEP_OPEN; return CUi::POPUP_KEEP_OPEN;
} }

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;
@ -3778,7 +3793,7 @@ void CGameContext::RegisterChatCommands()
Console()->Register("rescuemode", "?r['auto'|'manual']", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConRescueMode, this, "Sets one of the two rescue modes (auto or manual). Prints current mode if no arguments provided"); Console()->Register("rescuemode", "?r['auto'|'manual']", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConRescueMode, this, "Sets one of the two rescue modes (auto or manual). Prints current mode if no arguments provided");
Console()->Register("tp", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleTo, this, "Depending on the number of supplied arguments, teleport yourself to; (0.) where you are spectating or aiming; (1.) the specified player name"); Console()->Register("tp", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleTo, this, "Depending on the number of supplied arguments, teleport yourself to; (0.) where you are spectating or aiming; (1.) the specified player name");
Console()->Register("teleport", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleTo, this, "Depending on the number of supplied arguments, teleport yourself to; (0.) where you are spectating or aiming; (1.) the specified player name"); Console()->Register("teleport", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleTo, this, "Depending on the number of supplied arguments, teleport yourself to; (0.) where you are spectating or aiming; (1.) the specified player name");
Console()->Register("tpxy", "f[x] f[y]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleXY, this, "Teleport yourself to the specified coordinates. A tilde (~) can be used to denote your current position, e.g. '/tpxy ~1 ~' to teleport one tile to the right"); Console()->Register("tpxy", "s[x] s[y]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleXY, this, "Teleport yourself to the specified coordinates. A tilde (~) can be used to denote your current position, e.g. '/tpxy ~1 ~' to teleport one tile to the right");
Console()->Register("lasttp", "", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConLastTele, this, "Teleport yourself to the last location you teleported to"); Console()->Register("lasttp", "", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConLastTele, this, "Teleport yourself to the last location you teleported to");
Console()->Register("tc", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleCursor, this, "Teleport yourself to player or to where you are spectating/or looking if no player name is given"); Console()->Register("tc", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleCursor, this, "Teleport yourself to player or to where you are spectating/or looking if no player name is given");
Console()->Register("telecursor", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleCursor, this, "Teleport yourself to player or to where you are spectating/or looking if no player name is given"); Console()->Register("telecursor", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER | CMDFLAG_PRACTICE, ConTeleCursor, this, "Teleport yourself to player or to where you are spectating/or looking if no player name is given");
@ -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; }