Skip to content

Commit 17b28d4

Browse files
committed
Add mod weapon
1 parent 60a5af1 commit 17b28d4

File tree

9 files changed

+258
-50
lines changed

9 files changed

+258
-50
lines changed

ddnet-libs

src/base/system.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3923,7 +3923,8 @@ void str_escape(char **dst, const char *src, const char *end)
39233923
{
39243924
while(*src && *dst + 1 < end)
39253925
{
3926-
if(*src == '"' || *src == '\\') // escape \ and "
3926+
// TClient wants { and } to be escaped
3927+
if(*src == '"' || *src == '\\' || *src == '{' || *src == '}') // escape \ and "
39273928
{
39283929
if(*dst + 2 < end)
39293930
*(*dst)++ = '\\';

src/engine/shared/config_variables_tclient.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,5 @@ MACRO_CONFIG_STR(ClVolleyBallBetterBallSkin, tc_volleyball_better_ball_skin, 24,
248248
// Mod
249249
MACRO_CONFIG_INT(ClShowPlayerHitBoxes, tc_show_player_hit_boxes, 0, 0, 2, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show player hit boxes (1 = predicted, 2 = predicted and unpredicted)")
250250
MACRO_CONFIG_INT(ClHideChatBubbles, tc_hide_chat_bubbles, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Hide your own chat bubbles, only works when authed in remote console")
251+
MACRO_CONFIG_INT(ClModWeapon, tc_mod_weapon, -1, -1, 0, CFGFLAG_CLIENT, "Run a command (default kill) when attacking someone with a weapon (-1 = disable, 0 = hammer, 1 = gun)")
252+
MACRO_CONFIG_STR(ClModWeaponCommand, tc_mod_weapon_command, 256, "rcon kill_pl {0}; say \"{name {0}}\": blocking is not allowed", CFGFLAG_CLIENT | CFGFLAG_SAVE, "Command to run with tc_mod_weapon")

src/game/client/components/menus_start.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,11 @@ void CMenusStart::RenderStartMenu(CUIRect MainView)
189189
CUIRect UpdateToDateText;
190190
MainView.HSplitTop(15.0f, &UpdateToDateText, nullptr);
191191
UpdateToDateText.VSplitRight(40.0f, &UpdateToDateText, nullptr);
192-
if(!GameClient()->m_TClient.NeedUpdate() && GameClient()->m_TClient.m_FetchedTClientInfo)
192+
if(!GameClient()->m_TClient.NeedUpdate() && GameClient()->m_TClient.m_FetchedTClientInfo)
193193
{
194194
Ui()->DoLabel(&UpdateToDateText, TCLocalize("(On Latest)"), 14.0f, TEXTALIGN_MR);
195195
}
196-
else
196+
else
197197
{
198198
Ui()->DoLabel(&UpdateToDateText, TCLocalize("(Fetching Update Info)"), 14.0f, TEXTALIGN_MR);
199199
}

src/game/client/components/tclient/conditional.cpp

Lines changed: 78 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ int CConditional::ParseValue(char *pBuf, int Length)
4747
int Index;
4848
if(str_toint(pBuf, &Index))
4949
{
50-
if(Index >= 0 && Index < m_pResult->NumArguments())
50+
if(Index >= 0)
5151
return str_copy(pBuf, m_pResult->GetString(Index), Length);
5252
else
5353
return str_copy(pBuf, "", Length);
@@ -62,16 +62,16 @@ int CConditional::ParseValue(char *pBuf, int Length)
6262

6363
void CConditional::ParseString(char *pBuf, int Length)
6464
{
65-
// May give incorrect values on buffer overflow
6665
if(!pBuf || Length <= 0)
6766
return;
68-
69-
std::vector<std::pair<int, int>> vParsedRanges;
70-
const auto IsInParsedRegion = [&vParsedRanges](int Pos) {
71-
return std::any_of(vParsedRanges.begin(), vParsedRanges.end(), [Pos](const auto &ParsedRange) {
72-
return Pos >= ParsedRange.first && Pos < ParsedRange.second;
73-
});
74-
};
67+
bool HasBrackets = false;
68+
for(const char *p = pBuf; *p != '\0'; ++p)
69+
if(*p == '{' || *p == '}')
70+
HasBrackets = true;
71+
if(!HasBrackets)
72+
return;
73+
74+
// May give malformed result on buffer overflow
7575

7676
int Len = strnlen(pBuf, Length);
7777
while(true)
@@ -82,11 +82,19 @@ void CConditional::ParseString(char *pBuf, int Length)
8282
// Find the innermost {...} not inside any parsed range
8383
for(int i = 0; i < Len; ++i)
8484
{
85-
if(pBuf[i] == '{' && !IsInParsedRegion(i))
85+
if(pBuf[i] != '{' && pBuf[i] != '}')
86+
continue;
87+
// Count number of backslashes before this character
88+
int BackslashCount = 0;
89+
for (int j = i - 1; j >= 0 && pBuf[j] == '\\'; --j)
90+
BackslashCount++;
91+
if(BackslashCount % 2 != 0)
92+
continue;
93+
if (pBuf[i] == '{')
8694
{
8795
LastOpen = i;
8896
}
89-
else if(pBuf[i] == '}' && LastOpen != -1 && !IsInParsedRegion(i))
97+
else if (pBuf[i] == '}' && LastOpen != -1)
9098
{
9199
ClosePos = i;
92100
break;
@@ -106,44 +114,76 @@ void CConditional::ParseString(char *pBuf, int Length)
106114
int ResultLen = ParseValue(aTemp, sizeof(aTemp));
107115
if(ResultLen == -1)
108116
{
109-
ResultLen = CopyLen;
117+
if(Len + 2 >= Length)
118+
break; // Not enough space; stop
119+
mem_move(pBuf + ClosePos + 1, pBuf + ClosePos, Len - ClosePos + 1);
120+
pBuf[ClosePos] = '\\';
121+
Len++;
122+
mem_move(pBuf + LastOpen + 1, pBuf + LastOpen, Len - LastOpen + 1);
123+
pBuf[LastOpen] = '\\';
124+
Len++;
110125
}
111126
else
112127
{
113-
int TailLen = Len - ClosePos - 1;
114-
int NewLen = LastOpen + ResultLen + TailLen;
128+
for(const char *p = aTemp; *p != '\0'; ++p)
129+
if(*p == '{' || *p == '}' || *p == '\\')
130+
ResultLen++;
131+
mem_move(pBuf + LastOpen + ResultLen, pBuf + ClosePos + 1, Len - ClosePos);
132+
EscapeString(aTemp, pBuf + LastOpen, Length - LastOpen);
133+
Len -= ClosePos - LastOpen + 1;
134+
Len += ResultLen;
135+
pBuf[Len] = '\0';
136+
}
137+
}
138+
UnescapeString(pBuf, Length);
139+
}
115140

116-
if(NewLen >= Length)
117-
{
118-
ResultLen = Length - 1 - LastOpen - TailLen;
119-
if(ResultLen < 0)
120-
ResultLen = 0;
121-
NewLen = LastOpen + ResultLen + TailLen;
122-
}
141+
int CConditional::EscapeString(char *pIn, char *pBuf, int Length)
142+
{
143+
int WriteIndex = 0;
144+
for (int i = 0; pIn[i] != '\0'; ++i)
145+
{
146+
char c = pIn[i];
123147

124-
// Move tail forward/backward
125-
mem_move(pBuf + LastOpen + ResultLen, pBuf + ClosePos + 1, TailLen);
126-
pBuf[NewLen] = '\0';
148+
// If we need to write an escape character and the actual character
149+
if((c == '{' || c == '}' || c == '\\'))
150+
{
151+
if(WriteIndex + 2 >= Length)
152+
break; // not enough room for escape + char + null
153+
pBuf[WriteIndex++] = '\\';
154+
}
155+
else
156+
{
157+
if(WriteIndex + 1 >= Length)
158+
break; // not enough room for char + null
159+
}
127160

128-
// Copy result
129-
mem_copy(pBuf + LastOpen, aTemp, ResultLen);
130-
Len = NewLen;
161+
pBuf[WriteIndex++] = c;
162+
}
163+
return WriteIndex;
164+
}
131165

132-
// Shift existing ranges after ClosePos
133-
for(auto &ParsedRange : vParsedRanges)
166+
void CConditional::UnescapeString(char *pString, int Length)
167+
{
168+
int WritePos = 0; // Position to write the unescaped char
169+
for (int ReadPos = 0; ReadPos < Length - 1; ReadPos++)
170+
{
171+
if (pString[ReadPos] == '\\' && ReadPos + 1 < Length)
172+
{
173+
char NextChar = pString[ReadPos + 1];
174+
if (NextChar == '\\' || NextChar == '{' || NextChar == '}')
134175
{
135-
if(ParsedRange.first > ClosePos)
136-
{
137-
int Delta = ResultLen - (ClosePos + 1 - LastOpen);
138-
ParsedRange.first += Delta;
139-
ParsedRange.second += Delta;
140-
}
176+
// Replace the escape sequence by the actual character
177+
pString[WritePos++] = NextChar;
178+
ReadPos++; // Skip the escaped character
179+
continue;
141180
}
142181
}
143-
144-
// Add this region to parsed ranges
145-
vParsedRanges.emplace_back(LastOpen, LastOpen + ResultLen);
182+
// Normal character, copy as-is
183+
pString[WritePos++] = pString[ReadPos];
146184
}
185+
// Null-terminate the resulting string
186+
pString[WritePos] = '\0';
147187
}
148188

149189
void CConditional::ConIfeq(IConsole::IResult *pResult, void *pUserData)
@@ -230,12 +270,6 @@ static int TimeFromStr(const char *pStr, char OutUnit)
230270

231271
void CConditional::OnConsoleInit()
232272
{
233-
m_vVariables.emplace_back("l", [&](char *pOut, int Length) {
234-
return str_copy(pOut, "{", Length);
235-
});
236-
m_vVariables.emplace_back("r", [&](char *pOut, int Length) {
237-
return str_copy(pOut, "}", Length);
238-
});
239273
m_vVariables.emplace_back("game_mode", [&](char *pOut, int Length) {
240274
return str_copy(pOut, GameClient()->m_GameInfo.m_aGameType, Length);
241275
});

src/game/client/components/tclient/conditional.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ class CConditional : public CComponent
2020
const IConsole::IResult *m_pResult = nullptr;
2121

2222
void ParseString(char *pBuf, int Length);
23+
static int EscapeString(char *pIn, char *pBuf, int Length);
24+
static void UnescapeString(char *pString, int Length); // Inplace
25+
2326
static void ConIfeq(IConsole::IResult *pResult, void *pUserData);
2427
static void ConIfneq(IConsole::IResult *pResult, void *pUserData);
2528
static void ConIfreq(IConsole::IResult *pResult, void *pUserData);

0 commit comments

Comments
 (0)