live scan fix

This commit is contained in:
2026-05-03 22:25:30 +03:00
parent 51485c0048
commit a153b397d3
2 changed files with 125 additions and 5 deletions

View File

@@ -126,8 +126,9 @@
// --- Bind to GameEvents (passive, zero server cost) ---
try {
// New incoming attack detected
uw.$.Observer(uw.GameEvents.attack.incoming).subscribe(
// New incoming attack detected (This event works according to logs)
const attackEvent = uw.GameEvents?.attack?.incoming || 'attack:incoming';
uw.$.Observer(attackEvent).subscribe(
'GRC_TRACKER_ATTACK',
function(e, data) {
// Small delay so game model updates before we read it
@@ -141,17 +142,25 @@
try {
// Any command state changed (sent, landed, recalled, etc.)
uw.$.Observer(uw.GameEvents.command.change).subscribe(
// Fallback to string if the constant doesn't exist in this version
const cmdEvent = (uw.GameEvents?.command && uw.GameEvents.command.change)
? uw.GameEvents.command.change
: 'CommandsMenuBubble:change';
uw.$.Observer(cmdEvent).subscribe(
'GRC_TRACKER_CMD',
function(e, data) {
setTimeout(_pushMovements, 500);
}
);
log('[tracker] ✅ Subscribed to command.change event');
log('[tracker] ✅ Subscribed to command changes');
} catch (e) {
log(`[tracker] Could not subscribe to command.change: ${e}`);
log(`[tracker] Could not subscribe to command changes: ${e}`);
}
// --- Failsafe: push every 15 seconds regardless of events ---
setInterval(_pushMovements, 15000);
}, 6000); // 6s after boot — ensures CommandsMenuBubble model is loaded
}

111
future_ideas.md Normal file
View File

@@ -0,0 +1,111 @@
# Future Ideas & Optimizations
This document tracks potential architectural improvements and features inspired by other Grepolis alliance coordination scripts (like GrepoData and Noct).
## 1. Timestamp-Based Polling Optimization (`since` parameter)
**Inspired by:** `noct-api.grepo-soft.workers.dev`
**Current State:**
The Tampermonkey client polls the server every 8-18 seconds and receives the full state/command payload every time, even if nothing has changed.
**Proposed Implementation:**
- Add a `since` timestamp parameter to the client's poll requests.
- The server checks if any commands or state updates have occurred *after* the `since` timestamp.
- **If no new data:** The server returns an empty `HTTP 204 No Content` response.
- **If new data:** The server returns `HTTP 200 OK` with only the data that changed.
**Benefits:**
- Drastically reduces server bandwidth and CPU load.
- Minimizes the size of network requests on the client side, making the script stealthier and less resource-intensive in the browser.
**Concrete Code Example (How Noct does it):**
```javascript
// 1. Client-side polling logic
let lastFetchTime = Date.now();
async function pollCommands() {
const url = `https://noct-api.grepo-soft.workers.dev/api/alliance/commands` +
`?alliance=p0PmzsZMo4xZ2o29uvqggy5d` +
`&world=gr118` +
`&clientId=848938473` +
`&since=${lastFetchTime}`; // Ask only for things after this timestamp
const response = await fetch(url);
// 2. Server returns HTTP 204 (No Content) if nothing new happened
if (response.status === 204) {
return; // Empty payload, exit early
}
// 3. Server returns HTTP 200 (OK) only if there are NEW commands
if (response.status === 200) {
const data = await response.json();
// Process new commands...
executeCommands(data.commands);
// Update the timestamp so the next poll only asks for things after this moment
lastFetchTime = Date.now();
}
}
```
```python
# Backend (Python/Flask Equivalent)
@app.route('/api/alliance/commands')
def get_commands():
# Get the timestamp from the URL query
since_ts = int(request.args.get('since', 0))
# Query DB for commands created AFTER the 'since' timestamp
new_commands = db.execute(
"SELECT * FROM commands WHERE created_at_ts > ?", (since_ts,)
).fetchall()
if not new_commands:
# Return empty body with 204 No Content
return '', 204
return jsonify({"commands": new_commands}), 200
```
## 2. WebSocket Architecture for Real-Time Synchronization
**Inspired by:** `grepodata.com` (ReactPHP WebSocket server)
**Current State:**
Command delivery relies on HTTP polling. If an attack plan requires a launch in 30 seconds, but the client is on an 18-second polling interval, there is a high risk of missing the execution window or executing late.
**Proposed Implementation:**
- Integrate `Flask-SocketIO` (or a standalone async WebSocket server) into the backend.
- The client script establishes a persistent `wss://` connection upon loading the game.
- The client authenticates using its `clan_key` and subscribes to its alliance "topic/room".
- When an admin arms an attack plan or a player updates their town state, the server instantly *pushes* the payload to all connected alliance members.
**Benefits:**
- **Zero Polling Latency:** Commands arrive in ~100ms instead of 8-18 seconds.
- **Perfect Attack Timing:** Ensures clients receive armed plans immediately, maximizing the margin for precise execution.
- **Instant UI Updates:** The dashboard and attack planner can update in real-time as members come online or troop counts change.
## 3. Server-Sent Events (SSE) Lag/Refresh Bug Fix
**Issue:**
When refreshing or hitting the "back" button on the Live Tracker (`tracker.html`), the page occasionally hangs, lags heavily, or completely fails to load.
**Root Cause:**
The Live Tracker uses SSE (`EventSource`) to receive real-time movement updates. Modern browsers strictly limit simultaneous HTTP/1.1 connections to the same server (usually 6 maximum). When the user navigates away or refreshes, the browser drops the frontend page, but the Python/Flask backend (`tracker.py`) does not immediately detect the broken pipe and keeps the socket open, waiting to send data.
If the user hits refresh multiple times, these "ghost" connections stack up. Upon reaching 6 ghost connections, the browser refuses to load any further requests until the old connections naturally time out (which can take 30+ seconds).
**Proposed Fix:**
1. **Client-side (`tracker.html`)**: Ensure the browser explicitly tells the server the connection is closing exactly as the page unloads.
```javascript
window.addEventListener('beforeunload', () => {
if (typeof es !== 'undefined' && es !== null) {
es.close();
}
});
```
2. **Server-side (`tracker.py`)**: Ensure the generator handles client disconnects gracefully and immediately cleans up the subscriber queue without waiting for a timeout.
```python
# Make sure the generator yields spaces/heartbeats actively so the OS
# throws an IOError/GeneratorExit the moment the client drops.
```