Skip to content

Commit 36c7e62

Browse files
authored
Fix Brief messages override (#560)
1 parent 157a311 commit 36c7e62

File tree

5 files changed

+108
-42
lines changed

5 files changed

+108
-42
lines changed

cleo_plugins/Text/Text.cpp

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -152,28 +152,35 @@ class Text
152152
return result;
153153
}
154154

155-
static bool CanTextInThisSlotBeAddedToBrief(const char* slot)
155+
static bool CanThisTextBeAddedToBrief(const char* text)
156156
{
157-
// content dedup: exits early if another entry already holds the same text.
158-
for (size_t i = 0; i < BriefSize; i++)
157+
if (!CTheScripts::bAddNextMessageToPreviousBriefs) return false;
158+
159+
for (const auto& brief : CMessages::PreviousBriefs)
159160
{
160-
const auto pText = CMessages::PreviousBriefs[i].m_pText;
161-
if (pText == nullptr) break; // end of used entries
162-
if (pText == slot) continue; // stale self-reference, skip to avoid a false positive duplicate
163-
if (strcmp(pText, slot) == 0) return false; // content duplicate, exit
161+
const auto briefText = brief.m_pText;
162+
if (briefText && strcmp(briefText, text) == 0) return false;
164163
}
164+
return true;
165+
}
166+
167+
static char* PrepareThisTextForBrief(const char* text)
168+
{
169+
briefIdx = (briefIdx + 1) % BriefSize;
170+
char* msgSlot = briefs[briefIdx];
165171

166-
// stale pointer eviction: prevents the game's pointer-based dedup from rejecting the insertion
167-
for (size_t i = 0; i < BriefSize; i++)
172+
for (auto& brief : CMessages::PreviousBriefs)
168173
{
169-
auto& pText = CMessages::PreviousBriefs[i].m_pText;
170-
if (pText == slot)
171-
{
172-
pText = nullptr;
173-
break;
174-
}
174+
// stale pointer eviction: prevents the game's pointer-based brief dedup from rejecting the insertion
175+
const auto briefText = brief.m_pText;
176+
if (briefText == msgSlot) brief.m_pText = nullptr;
175177
}
176-
return true;
178+
179+
// put the message into a free slot in the static buffer to get a persistent pointer
180+
const auto msgSlotSize = sizeof(briefs[briefIdx]);
181+
strncpy_s(msgSlot, msgSlotSize, text, msgSlotSize - 1);
182+
183+
return msgSlot;
177184
}
178185

179186
static void PrintHelp(CLEO::CRunningScript* thread, const char* text)
@@ -182,17 +189,9 @@ class Text
182189

183190
if (IsLegacyScript(thread)) return;
184191

185-
if (CTheScripts::bAddNextMessageToPreviousBriefs)
192+
if (CanThisTextBeAddedToBrief(text))
186193
{
187-
briefIdx = (briefIdx + 1) % BriefSize;
188-
auto& briefSlot = briefs[briefIdx];
189-
190-
strncpy_s(briefSlot, text, sizeof(briefSlot) - 1);
191-
192-
if (CanTextInThisSlotBeAddedToBrief(briefSlot))
193-
{
194-
CMessages::AddToPreviousBriefArray(briefSlot, -1, -1, -1, -1, -1, -1, 0);
195-
}
194+
CMessages::AddToPreviousBriefArray(PrepareThisTextForBrief(text), -1, -1, -1, -1, -1, -1, 0);
196195
}
197196

198197
CTheScripts::bAddNextMessageToPreviousBriefs = true;
@@ -201,10 +200,10 @@ class Text
201200
static void AddToMessageQueue(CLEO::CRunningScript* pScript, const char* text, int time, bool now)
202201
{
203202
/*
204-
CLEO 4: always show messages, no brief change, no subtitle suppression (~z~)
205-
CLEO 5: show messages conditionally based on user preference, update brief
203+
CLEO 4: show subtitle ~z~ regarless of "Show Subtitles"; no brief update ever
204+
CLEO 5: show subtitle ~z~ only if "Show Subtitles" is ON; update brief if needed
206205
207-
Both: if message queue is full, don't show the message, unless it's a NOW message.
206+
Both: Queue messages; if the queue is full, skip the next message, unless it's a NOW message.
208207
*/
209208

210209
const auto isLegacy = IsLegacyScript(pScript);
@@ -231,15 +230,20 @@ class Text
231230

232231
if (display)
233232
{
234-
// put the message into a free slot in our static buffer to get a persistent pointer
235-
queueIdx = (queueIdx + 1) % MessageQueueSize;
236-
auto& messageSlot = messageQueue[queueIdx];
237-
strncpy_s(messageSlot, text, sizeof(messageSlot) - 1);
233+
// put the message into a free slot in the static buffer to get a persistent pointer
234+
queueIdx = (queueIdx + 1) % MessageQueueSize;
235+
char* messageSlot = messageQueue[queueIdx];
236+
const auto bufSize = sizeof(messageQueue[queueIdx]);
237+
strncpy_s(messageSlot, bufSize, text, bufSize - 1);
238238

239239
// check game brief and decide whether this message can be added to it.
240240
// Note: legacy scripts never modify the game brief.
241-
const auto addToBrief = !isLegacy && CTheScripts::bAddNextMessageToPreviousBriefs &&
242-
CanTextInThisSlotBeAddedToBrief(messageSlot);
241+
const auto addToBrief = !isLegacy && CanThisTextBeAddedToBrief(text);
242+
243+
if (addToBrief)
244+
{
245+
messageSlot = PrepareThisTextForBrief(text);
246+
}
243247

244248
if (now)
245249
{

tests/cleo_tests/Text/0ACC.txt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ function tests
2424
it_cs5("should not display message starting with ~z~ with subtitles off", test9_cs5)
2525
it_cs4("should display message starting with ~z~ with subtitles off", test9_cs4)
2626
it("should not display message when game queue is full", test10_queue_full)
27+
it_cs5("should dedup brief messages in loop", test11_dedup_loop_cs5)
2728
return
2829

2930
:cleanup
@@ -256,10 +257,25 @@ function tests
256257
// Queue is full; print_string must be silently dropped
257258
print_string {text} "Queue Full Str" {time} 900
258259
wait 0
259-
260260
// current subtitle must still be the first fill message, not the dropped one
261261
assert_subtitle("Fill Q 1")
262262
end
263+
264+
function test11_dedup_loop_cs5
265+
print_string "STAT001" 100
266+
wait 500
267+
TIMERA = 0
268+
while TIMERA < 1000
269+
wait 0
270+
print_string "STAT002" 100
271+
end
272+
273+
assert_brief_at(0, "STAT002")
274+
assert_brief_at(1, "STAT001")
275+
276+
int brief = getBriefTextAt(2)
277+
assert_eq(brief, 0)
278+
end
263279
end
264280

265281
{$INCLUDE_ONCE helpers.inc}

tests/cleo_tests/Text/0ACD.txt

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function tests
2020
it_cs5("should not display message starting with ~z~ with subtitles off", test7_cs5)
2121
it_cs4("should display message starting with ~z~ with subtitles off", test7_cs4)
2222
it("should display NOW message even when game queue is full", test8_queue_full_now)
23-
23+
it_cs5("should dedup brief messages in loop", test9_dedup_loop_cs5)
2424
return
2525

2626
:cleanup
@@ -179,10 +179,25 @@ function tests
179179
// Queue is full; print_string_now must still display (bypasses full-queue check)
180180
print_string_now {text} "Now Bypasses Q" {time} 100
181181
wait 0
182-
182+
183183
// NOW message must jump to front despite full queue
184184
assert_subtitle("Now Bypasses Q")
185185
end
186+
187+
function test9_dedup_loop_cs5
188+
print_string_now "STAT001" 1000
189+
TIMERA = 0
190+
while TIMERA < 1000
191+
wait 0
192+
print_string_now "STAT002" 100
193+
end
194+
195+
assert_brief_at(0, "STAT002")
196+
assert_brief_at(1, "STAT001")
197+
198+
int brief = getBriefTextAt(2)
199+
assert_eq(brief, 0)
200+
end
186201
end
187202

188203
{$INCLUDE_ONCE helpers.inc}

tests/cleo_tests/Text/0AD0.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ function tests
2222
it_cs5("should not add duplicate text to brief history", test8_queue_dedup)
2323
it_cs4("should not add any text to brief history in legacy mode", test8_queue_dedup_cs4)
2424
it_cs5("should not display message starting with ~z~ with subtitles off", test9_cs5)
25-
it_cs4("should display message starting with ~z~ with subtitles off", test9_cs4)
25+
it_cs4("should display message starting with ~z~ with subtitles off", test9_cs4)
2626
it("should not display message when game queue is full", test10_queue_full)
27+
it_cs5("should dedup brief messages in loop", test11_dedup_loop_cs5)
2728
return
2829

2930
:cleanup
@@ -243,6 +244,22 @@ function tests
243244
// current subtitle must still be the first fill message, not the dropped one
244245
assert_subtitle("Fill Q 1")
245246
end
247+
248+
function test11_dedup_loop_cs5
249+
print_formatted "STAT001" 100
250+
wait 500
251+
TIMERA = 0
252+
while TIMERA < 1000
253+
wait 0
254+
print_formatted "STAT002" 100
255+
end
256+
257+
assert_brief_at(0, "STAT002")
258+
assert_brief_at(1, "STAT001")
259+
260+
int brief = getBriefTextAt(2)
261+
assert_eq(brief, 0)
262+
end
246263
end
247264

248265
{$INCLUDE_ONCE helpers.inc}

tests/cleo_tests/Text/0AD1.txt

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function tests
2020
it_cs5("should not display message starting with ~z~ with subtitles off", test7_cs5)
2121
it_cs4("should display message starting with ~z~ with subtitles off", test7_cs4)
2222
it("should display NOW message even when game queue is full", test8_queue_full_now)
23-
23+
it_cs5("should dedup brief messages in loop", test9_dedup_loop_cs5)
2424
return
2525

2626
:cleanup
@@ -117,7 +117,7 @@ function tests
117117
print_formatted_now {format} "Flag test AD1 cs4" {time} 100
118118
assert_brief_flag(false) // flag must NOT be reset for legacy scripts
119119
end
120-
120+
121121
function test7_cs5
122122
toggle_subtitles(true)
123123
print_formatted_now {text} "~z~Subtitle 1" {time} 100
@@ -167,6 +167,21 @@ function tests
167167
// NOW message must jump to front despite full queue
168168
assert_subtitle("Now Bypasses Q")
169169
end
170+
171+
function test9_dedup_loop_cs5
172+
print_formatted_now "STAT001" 1000
173+
TIMERA = 0
174+
while TIMERA < 1000
175+
wait 0
176+
print_formatted_now "STAT002" 100
177+
end
178+
179+
assert_brief_at(0, "STAT002")
180+
assert_brief_at(1, "STAT001")
181+
182+
int brief = getBriefTextAt(2)
183+
assert_eq(brief, 0)
184+
end
170185
end
171186

172187
{$INCLUDE_ONCE helpers.inc}
@@ -200,4 +215,3 @@ function print_brief_messages
200215
msg2 = 0
201216
msg3 = 0
202217
end
203-

0 commit comments

Comments
 (0)