Skip to content

Commit 32d9093

Browse files
author
web3blind
committed
Reduce quest and travel UI delays
1 parent b3a1671 commit 32d9093

6 files changed

Lines changed: 58 additions & 9 deletions

File tree

app/index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@
164164
<script src="js/engine/quest-system.js?v=20260621e"></script>
165165
<script src="js/engine/loci.js"></script>
166166
<script src="js/engine/npc-framework.js"></script>
167-
<script src="js/engine/state-engine.js?v=20260621e"></script>
167+
<script src="js/engine/state-engine.js?v=20260621h"></script>
168168
<script src="js/engine/daily-leaderboard-storage.js"></script>
169169
<script src="js/engine/daily-leaderboard.js"></script>
170170

@@ -184,11 +184,11 @@
184184
<script src="js/ui/screens/character.js"></script>
185185
<script src="js/ui/screens/hunt.js"></script>
186186
<script src="js/ui/screens/inventory.js"></script>
187-
<script src="js/ui/screens/chronicle.js?v=20260621g"></script>
187+
<script src="js/ui/screens/chronicle.js?v=20260621h"></script>
188188
<script src="js/ui/screens/duel.js"></script>
189189
<script src="js/ui/screens/arena.js?v=20260621d"></script>
190190
<script src="js/ui/screens/guild.js?v=20260621d"></script>
191-
<script src="js/ui/screens/map.js"></script>
191+
<script src="js/ui/screens/map.js?v=20260621h"></script>
192192
<script src="js/ui/screens/marketplace.js"></script>
193193
<script src="js/ui/screens/crafting.js"></script>
194194
<script src="js/ui/screens/quests.js?v=20260621e"></script>

app/js/engine/state-engine.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,20 @@ var StateEngine = (function() {
12121212
return result;
12131213
}
12141214

1215+
/**
1216+
* Process movement for live UI — same authoritative mutation path as replay.
1217+
* @param {string} account
1218+
* @param {string} zoneId
1219+
* @param {number} blockNum
1220+
* @returns {Object|null}
1221+
*/
1222+
function processMoveResult(account, zoneId, blockNum) {
1223+
if (!zoneId) return null;
1224+
var events = _handleMove(account, { zone: zoneId }, blockNum || 0);
1225+
if (!events.length) return null;
1226+
return events[0];
1227+
}
1228+
12151229
/**
12161230
* Process Armageddon for live UI — same logic as _handleHuntArmageddon.
12171231
* @param {string} account
@@ -1247,6 +1261,7 @@ var StateEngine = (function() {
12471261
getCharacter: getCharacter,
12481262
getInventory: getInventory,
12491263
processHuntResult: processHuntResult,
1264+
processMoveResult: processMoveResult,
12501265
processArmageddonResult: processArmageddonResult,
12511266
reset: reset
12521267
};

app/js/ui/screens/chronicle.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,17 @@ var ChronicleScreen = (function() {
346346
events: []
347347
});
348348
cachedFeedHtml = {};
349+
_updateLocalBlessingQuestProgress(account);
350+
}
351+
352+
function _updateLocalBlessingQuestProgress(account) {
353+
var state = StateEngine.getState();
354+
var user = VizAccount.getCurrentUser();
355+
if (!state || !user || !account || !state.quests || !state.quests[user] || typeof QuestSystem === 'undefined') return;
356+
QuestSystem.updateQuestProgress(state.quests[user], 'social', { target: 'blessing', uniqueKey: account, count: 1 });
357+
try {
358+
CheckpointSystem.saveCheckpoint('global', state.headBlock || 0, state, function() {});
359+
} catch (e) {}
349360
}
350361

351362
function _renderEntry(entry) {

app/js/ui/screens/map.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ var MapScreen = (function() {
88

99
var t = Helpers.t;
1010
var pendingTravel = null;
11+
var PENDING_TRAVEL_TTL_MS = 5 * 60 * 1000;
1112
var TRAVEL_COST_LOW = 10; // 0.1%
1213
var TRAVEL_COST_HIGH = 100; // 1%
1314

@@ -35,6 +36,8 @@ var MapScreen = (function() {
3536
var confirmedZone = character ? character.currentZone : 'commons_first_light';
3637
if (pendingTravel && pendingTravel.account === user && pendingTravel.to === confirmedZone) {
3738
pendingTravel = null;
39+
} else if (pendingTravel && pendingTravel.account === user && pendingTravel.at && (Date.now() - pendingTravel.at) > PENDING_TRAVEL_TTL_MS) {
40+
pendingTravel = null;
3841
}
3942
var currentZone = confirmedZone;
4043
var myGuild = null;
@@ -158,7 +161,9 @@ var MapScreen = (function() {
158161
}
159162

160163
// Travel button
161-
if (!isCurrent && character) {
164+
if (pendingTravel && pendingTravel.account === user && regionId === pendingTravel.to) {
165+
html += '<div class="region-benefits" role="status">⏳ ' + t('map_pending_travel_short') + '</div>';
166+
} else if (!isCurrent && character && !(pendingTravel && pendingTravel.account === user)) {
162167
html += '<div class="region-travel-options">';
163168
html += '<button class="btn btn-secondary btn-sm region-travel-btn" ';
164169
html += 'data-region="' + regionId + '" data-cost="' + TRAVEL_COST_LOW + '" ';
@@ -171,8 +176,6 @@ var MapScreen = (function() {
171176
html += '\uD83D\uDEB6 ' + Helpers.manaCost(TRAVEL_COST_HIGH);
172177
html += '</button>';
173178
html += '</div>';
174-
} else if (pendingTravel && pendingTravel.account === user && regionId === pendingTravel.to) {
175-
html += '<div class="region-benefits">⏳ ' + t('map_pending_travel_short') + '</div>';
176179
}
177180

178181
html += '</section>';
@@ -226,14 +229,22 @@ var MapScreen = (function() {
226229
t: VizMagicConfig.ACTION_TYPES.MOVE,
227230
d: { zone: regionId }
228231
};
232+
var previousZone = character ? character.currentZone : '';
229233

230234
VizBroadcast.gameAction(moveAction, function(err) {
231235
if (err) {
232236
Toast.error(t('error_network'));
233237
} else {
234-
pendingTravel = { account: user, from: character ? character.currentZone : '', to: regionId, at: Date.now() };
238+
var stateAfterMove = StateEngine.getState();
239+
var optimisticBlock = (stateAfterMove.headBlock || 0) + 1;
240+
StateEngine.processMoveResult(user, regionId, optimisticBlock);
241+
stateAfterMove.headBlock = Math.max(stateAfterMove.headBlock || 0, optimisticBlock);
242+
pendingTravel = { account: user, from: previousZone, to: regionId, at: Date.now() };
235243
Toast.success(t('map_traveled') + ' ' + region.name);
236244
SoundManager.play('transition');
245+
try {
246+
CheckpointSystem.saveCheckpoint('global', stateAfterMove.headBlock || optimisticBlock, stateAfterMove, function() {});
247+
} catch (e) {}
237248
render();
238249
}
239250
});

app/sw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Viz Magic — Service Worker
2-
var CACHE_NAME = 'viz-magic-v20';
2+
var CACHE_NAME = 'viz-magic-v21';
33
var ASSETS = [
44
'/',
55
'/index.html',

tests/player-bug-regressions.test.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const inventoryJs = read('app/js/ui/screens/inventory.js');
3434
const huntJs = read('app/js/ui/screens/hunt.js');
3535
const mapJs = read('app/js/ui/screens/map.js');
3636
const chronicleJs = read('app/js/ui/screens/chronicle.js');
37+
const mapScreenJs = read('app/js/ui/screens/map.js');
3738
const questScreenJs = read('app/js/ui/screens/quests.js');
3839
const guildJs = read('app/js/ui/screens/guild.js');
3940
const leaderboardJs = read('app/js/ui/screens/leaderboard.js');
@@ -124,6 +125,7 @@ test('chronicle keeps loaded tabs visible and shows sent blessings immediately',
124125
assert.ok(/_injectLocalBlessing\(account, energy\)/.test(chronicleJs), 'blessing success path should inject visible local action');
125126
assert.ok(/receiver: action\.receiver/.test(chronicleJs), 'chronicle entries should preserve blessing receiver for dedupe');
126127
assert.ok(/\|blessing_sent\|/.test(chronicleJs), 'blessing dedupe should ignore optimistic/replay block mismatch');
128+
assert.ok(/function _updateLocalBlessingQuestProgress/.test(chronicleJs), 'blessing quests should update immediately after a successful local blessing');
127129
});
128130

129131

@@ -187,12 +189,22 @@ test('high-traffic UI narration and inventory stat labels are translated', funct
187189

188190
test('service worker updates quickly and keeps navigations network-first', function () {
189191
const swJs = read('app/sw.js');
190-
assert.ok(/viz-magic-v20/.test(swJs), 'service worker cache version should be bumped');
192+
assert.ok(/viz-magic-v21/.test(swJs), 'service worker cache version should be bumped');
191193
assert.ok(/self\.skipWaiting\(\)/.test(swJs), 'service worker should activate new cache without waiting for all tabs to close');
192194
assert.ok(/self\.clients\.claim\(\)/.test(swJs), 'service worker should claim clients after activation');
193195
assert.ok(/event\.request\.mode === 'navigate'[\s\S]*fetch\(event\.request\)/.test(swJs), 'navigation requests should prefer network to avoid stale cached index');
194196
});
195197

198+
199+
200+
test('map travel updates through state-engine and blocks repeat-click loops', function () {
201+
assert.ok(/function processMoveResult/.test(stateEngineJs), 'state engine should expose live movement path');
202+
assert.ok(/processMoveResult: processMoveResult/.test(stateEngineJs), 'live movement path should be exported');
203+
assert.ok(/StateEngine\.processMoveResult\(user, regionId, optimisticBlock\)/.test(mapScreenJs), 'map should update movement immediately through state engine');
204+
assert.ok(/PENDING_TRAVEL_TTL_MS/.test(mapScreenJs), 'pending travel state should have a stale guard');
205+
assert.ok(/!\(pendingTravel && pendingTravel\.account === user\)/.test(mapScreenJs), 'pending travel should suppress repeat travel buttons');
206+
});
207+
196208
test('leaderboard has local character fallback while 24h scan is empty or slow', function () {
197209
assert.ok(/function _fallbackRowsFromState/.test(leaderboardJs), 'leaderboard should expose local fallback rows');
198210
assert.ok(/rows = _fallbackRowsFromState\(\)/.test(leaderboardJs), 'leaderboard should use fallback when snapshot rows are empty');

0 commit comments

Comments
 (0)