enchance data
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Grepolis Remote Control
|
// @name Grepolis Remote Control
|
||||||
// @namespace http://tampermonkey.net/
|
// @namespace http://tampermonkey.net/
|
||||||
// @version 1.2
|
// @version 1.3
|
||||||
// @description Polls grepo.haunter-pets.top for remote commands and executes them in-game
|
// @description Polls grepo.haunter-pets.top for remote commands and executes them in-game
|
||||||
// @author Dimitrios
|
// @author Dimitrios
|
||||||
// @match https://*.grepolis.com/game/*
|
// @match https://*.grepolis.com/game/*
|
||||||
@@ -67,9 +67,13 @@
|
|||||||
// Push town state to relay
|
// Push town state to relay
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
function gatherState() {
|
function gatherState() {
|
||||||
const towns = uw.ITowns?.towns || {};
|
const towns = uw.ITowns?.towns || {};
|
||||||
const player = uw.Game?.player_name || '';
|
const player = uw.Game?.player_name || '';
|
||||||
const world = uw.Game?.world_id || '';
|
const player_id = uw.Game?.player_id ?? null;
|
||||||
|
const alliance_id = uw.Game?.alliance_id ?? null;
|
||||||
|
const total_points = uw.Game?.player_points ?? 0;
|
||||||
|
const world = uw.Game?.world_id || '';
|
||||||
|
|
||||||
|
|
||||||
const townList = Object.values(towns).map(town => {
|
const townList = Object.values(towns).map(town => {
|
||||||
const res = town.resources();
|
const res = town.resources();
|
||||||
@@ -135,9 +139,35 @@
|
|||||||
log(`storage capacity lookup failed: ${e}`);
|
log(`storage capacity lookup failed: ${e}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Coordinates & sea zone -----------------------------------------
|
||||||
|
let x = null, y = null, sea = null;
|
||||||
|
try {
|
||||||
|
x = town.getIslandCoordinateX?.() ?? null;
|
||||||
|
y = town.getIslandCoordinateY?.() ?? null;
|
||||||
|
if (typeof x === 'number' && typeof y === 'number') {
|
||||||
|
sea = Math.floor(x / 100) * 10 + Math.floor(y / 100);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
// ---- Researches -----------------------------------------------------
|
||||||
|
let researches = {};
|
||||||
|
try {
|
||||||
|
const r = town.researches?.();
|
||||||
|
if (r) researches = r.attributes ?? (typeof r === 'object' ? r : {});
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
// ---- Extra town flags -----------------------------------------------
|
||||||
|
let has_premium = false;
|
||||||
|
let bonuses = {};
|
||||||
|
let wonder_points = 0;
|
||||||
|
try { has_premium = town.hasPremium?.() || false; } catch (e) {}
|
||||||
|
try { bonuses = town.getBonus?.() || {}; } catch (e) {}
|
||||||
|
try { wonder_points = town.wonder_points || 0; } catch (e) {}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
town_id: town.id,
|
town_id: town.id,
|
||||||
town_name: town.name,
|
town_name: town.name,
|
||||||
|
x, y, sea,
|
||||||
wood: res.wood,
|
wood: res.wood,
|
||||||
stone: res.stone,
|
stone: res.stone,
|
||||||
iron: res.iron,
|
iron: res.iron,
|
||||||
@@ -149,10 +179,14 @@
|
|||||||
units: unitsObj,
|
units: unitsObj,
|
||||||
buildingOrder: buildQueue,
|
buildingOrder: buildQueue,
|
||||||
buildData: buildDataMap,
|
buildData: buildDataMap,
|
||||||
|
researches,
|
||||||
|
has_premium,
|
||||||
|
bonuses,
|
||||||
|
wonder_points,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return { player, world_id: world, towns: townList };
|
return { player, player_id, alliance_id, total_points, world_id: world, towns: townList };
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushState() {
|
function pushState() {
|
||||||
|
|||||||
18
db.py
18
db.py
@@ -35,11 +35,29 @@ def init_db():
|
|||||||
town_id TEXT PRIMARY KEY,
|
town_id TEXT PRIMARY KEY,
|
||||||
town_name TEXT,
|
town_name TEXT,
|
||||||
player TEXT,
|
player TEXT,
|
||||||
|
player_id TEXT,
|
||||||
|
alliance_id TEXT,
|
||||||
world_id TEXT,
|
world_id TEXT,
|
||||||
|
x REAL,
|
||||||
|
y REAL,
|
||||||
|
sea INTEGER,
|
||||||
data TEXT NOT NULL, -- full JSON snapshot
|
data TEXT NOT NULL, -- full JSON snapshot
|
||||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
# Migration: add new columns if upgrading an existing database
|
||||||
|
for _col in [
|
||||||
|
'ALTER TABLE town_state ADD COLUMN player_id TEXT',
|
||||||
|
'ALTER TABLE town_state ADD COLUMN alliance_id TEXT',
|
||||||
|
'ALTER TABLE town_state ADD COLUMN x REAL',
|
||||||
|
'ALTER TABLE town_state ADD COLUMN y REAL',
|
||||||
|
'ALTER TABLE town_state ADD COLUMN sea INTEGER',
|
||||||
|
]:
|
||||||
|
try:
|
||||||
|
c.execute(_col)
|
||||||
|
except Exception:
|
||||||
|
pass # column already exists
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|||||||
@@ -17,26 +17,40 @@ def receive_state():
|
|||||||
return jsonify({'error': 'no data'}), 400
|
return jsonify({'error': 'no data'}), 400
|
||||||
|
|
||||||
towns = data.get('towns', [])
|
towns = data.get('towns', [])
|
||||||
player = data.get('player', '')
|
player = data.get('player', '')
|
||||||
world_id = data.get('world_id', '')
|
player_id = data.get('player_id', '')
|
||||||
|
alliance_id = str(data.get('alliance_id', '') or '')
|
||||||
|
world_id = data.get('world_id', '')
|
||||||
|
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
for town in towns:
|
for town in towns:
|
||||||
|
x = town.get('x')
|
||||||
|
y = town.get('y')
|
||||||
|
sea = town.get('sea')
|
||||||
c.execute('''
|
c.execute('''
|
||||||
INSERT INTO town_state (town_id, town_name, player, world_id, data, updated_at)
|
INSERT INTO town_state
|
||||||
VALUES (?, ?, ?, ?, ?, ?)
|
(town_id, town_name, player, player_id, alliance_id, world_id, x, y, sea, data, updated_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
ON CONFLICT(town_id) DO UPDATE SET
|
ON CONFLICT(town_id) DO UPDATE SET
|
||||||
town_name = excluded.town_name,
|
town_name = excluded.town_name,
|
||||||
player = excluded.player,
|
player = excluded.player,
|
||||||
world_id = excluded.world_id,
|
player_id = excluded.player_id,
|
||||||
data = excluded.data,
|
alliance_id = excluded.alliance_id,
|
||||||
updated_at = excluded.updated_at
|
world_id = excluded.world_id,
|
||||||
|
x = excluded.x,
|
||||||
|
y = excluded.y,
|
||||||
|
sea = excluded.sea,
|
||||||
|
data = excluded.data,
|
||||||
|
updated_at = excluded.updated_at
|
||||||
''', (
|
''', (
|
||||||
str(town['town_id']),
|
str(town['town_id']),
|
||||||
town.get('town_name', ''),
|
town.get('town_name', ''),
|
||||||
player,
|
player,
|
||||||
|
player_id,
|
||||||
|
alliance_id,
|
||||||
world_id,
|
world_id,
|
||||||
|
x, y, sea,
|
||||||
json.dumps(town),
|
json.dumps(town),
|
||||||
datetime.utcnow().isoformat()
|
datetime.utcnow().isoformat()
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ def index():
|
|||||||
def get_towns():
|
def get_towns():
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
rows = conn.execute('''
|
rows = conn.execute('''
|
||||||
SELECT town_id, town_name, player, world_id, data, updated_at
|
SELECT town_id, town_name, player, player_id, alliance_id,
|
||||||
|
world_id, x, y, sea, data, updated_at
|
||||||
FROM town_state
|
FROM town_state
|
||||||
ORDER BY town_name ASC
|
ORDER BY town_name ASC
|
||||||
''').fetchall()
|
''').fetchall()
|
||||||
@@ -33,11 +34,16 @@ def get_towns():
|
|||||||
for row in rows:
|
for row in rows:
|
||||||
d = json.loads(row['data'])
|
d = json.loads(row['data'])
|
||||||
towns.append({
|
towns.append({
|
||||||
'town_id': row['town_id'],
|
'town_id': row['town_id'],
|
||||||
'town_name': row['town_name'],
|
'town_name': row['town_name'],
|
||||||
'player': row['player'],
|
'player': row['player'],
|
||||||
'world_id': row['world_id'],
|
'player_id': row['player_id'],
|
||||||
'updated_at': row['updated_at'],
|
'alliance_id': row['alliance_id'],
|
||||||
|
'world_id': row['world_id'],
|
||||||
|
'x': row['x'],
|
||||||
|
'y': row['y'],
|
||||||
|
'sea': row['sea'],
|
||||||
|
'updated_at': row['updated_at'],
|
||||||
'resources': {
|
'resources': {
|
||||||
'wood': d.get('wood', 0),
|
'wood': d.get('wood', 0),
|
||||||
'stone': d.get('stone', 0),
|
'stone': d.get('stone', 0),
|
||||||
@@ -45,12 +51,17 @@ def get_towns():
|
|||||||
'storage': d.get('storage', 0),
|
'storage': d.get('storage', 0),
|
||||||
'population': d.get('population', 0),
|
'population': d.get('population', 0),
|
||||||
},
|
},
|
||||||
'buildings': d.get('buildings', {}),
|
'buildings': d.get('buildings', {}),
|
||||||
'units': d.get('units', {}),
|
'units': d.get('units', {}),
|
||||||
'points': d.get('points', 0),
|
'points': d.get('points', 0),
|
||||||
'god': d.get('god', None),
|
'god': d.get('god', None),
|
||||||
'build_queue': d.get('buildingOrder', []),
|
'build_queue': d.get('buildingOrder', []),
|
||||||
'build_data': d.get('buildData', {}),
|
'build_data': d.get('buildData', {}),
|
||||||
|
'researches': d.get('researches', {}),
|
||||||
|
'has_premium': d.get('has_premium', False),
|
||||||
|
'bonuses': d.get('bonuses', {}),
|
||||||
|
'wonder_points': d.get('wonder_points', 0),
|
||||||
|
'total_points': d.get('total_points', 0),
|
||||||
})
|
})
|
||||||
return jsonify(towns)
|
return jsonify(towns)
|
||||||
|
|
||||||
|
|||||||
@@ -253,6 +253,11 @@
|
|||||||
<strong style="font-size: 0.75rem; color: #888; text-transform: uppercase;">Στρατος</strong>
|
<strong style="font-size: 0.75rem; color: #888; text-transform: uppercase;">Στρατος</strong>
|
||||||
<div id="td-units" style="font-size: 0.85rem; margin-top: 4px; line-height: 1.5; color: #a4c84a;"></div>
|
<div id="td-units" style="font-size: 0.85rem; margin-top: 4px; line-height: 1.5; color: #a4c84a;"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style="flex: 1; min-width: 130px;">
|
||||||
|
<strong style="font-size: 0.75rem; color: #888; text-transform: uppercase;">Ερευνες</strong>
|
||||||
|
<div id="td-researches" style="font-size: 0.8rem; margin-top: 4px; line-height: 1.5; color: #c8a44a;"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -474,8 +479,8 @@ function renderTowns() {
|
|||||||
return `
|
return `
|
||||||
<div class="town-card ${selected} ${stale ? 'town-stale' : ''}"
|
<div class="town-card ${selected} ${stale ? 'town-stale' : ''}"
|
||||||
onclick="selectTown('${t.town_id}')">
|
onclick="selectTown('${t.town_id}')">
|
||||||
<div class="town-name">${t.town_name}</div>
|
<div class="town-name">${t.town_name}${t.has_premium ? ' <span style="color:#c8a44a;font-size:0.7rem;">★</span>' : ''}</div>
|
||||||
<div class="town-meta">${t.points} pts · ${t.god || 'No god'} · ${ageMin}m ago</div>
|
<div class="town-meta">${t.sea != null ? `🌊 Θ${t.sea} · ` : ''}${t.points} pts · ${t.god || 'No god'} · ${ageMin}m ago</div>
|
||||||
<div class="town-res">
|
<div class="town-res">
|
||||||
<div class="res-item"><div class="res-icon res-wood"></div>${fmt(t.resources.wood)}</div>
|
<div class="res-item"><div class="res-icon res-wood"></div>${fmt(t.resources.wood)}</div>
|
||||||
<div class="res-item"><div class="res-icon res-stone"></div>${fmt(t.resources.stone)}</div>
|
<div class="res-item"><div class="res-icon res-stone"></div>${fmt(t.resources.stone)}</div>
|
||||||
@@ -532,12 +537,29 @@ function renderTownDetails() {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const godName = t.god ? t.god.charAt(0).toUpperCase() + t.god.slice(1) : 'Κανένας';
|
const godName = t.god ? t.god.charAt(0).toUpperCase() + t.god.slice(1) : 'Κανένας';
|
||||||
|
const seaStr = t.sea != null ? `Θ${t.sea}` : '—';
|
||||||
|
const coordStr = (t.x != null && t.y != null) ? ` (${Math.round(t.x)}:${Math.round(t.y)})` : '';
|
||||||
document.getElementById('td-general').innerHTML = `
|
document.getElementById('td-general').innerHTML = `
|
||||||
<div>Πόντοι: <strong>${t.points}</strong></div>
|
<div>Πόντοι: <strong>${t.points}</strong>${t.wonder_points ? ` / Θαύμα: <strong>${t.wonder_points}</strong>` : ''}</div>
|
||||||
<div>Θεός: <strong>${godName}</strong></div>
|
<div>Θεός: <strong>${godName}</strong></div>
|
||||||
<div>Παίκτης: <strong style="color:#aaa">${t.player}</strong></div>
|
<div>Θάλασσα: <strong style="color:#6fcfcf">${seaStr}</strong><span style="color:#666;font-size:0.72rem">${coordStr}</span></div>
|
||||||
|
<div>Παίκτης: <strong style="color:#aaa">${t.player}</strong>${t.has_premium ? ' <span style="color:#c8a44a" title="Premium">★</span>' : ''}</div>
|
||||||
|
${t.alliance_id ? `<div>Συμμαχία: <strong style="color:#aaa">${t.alliance_id}</strong></div>` : ''}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// ---- Researches ----
|
||||||
|
const researchObj = t.researches || {};
|
||||||
|
const researchEntries = Object.entries(researchObj).filter(([, v]) => v === true || v === 1 || Number(v) > 0);
|
||||||
|
let resHtml = '';
|
||||||
|
if (researchEntries.length) {
|
||||||
|
resHtml = researchEntries.map(([k]) =>
|
||||||
|
`<div>✓ ${k.replace(/_/g, ' ')}</div>`
|
||||||
|
).join('');
|
||||||
|
} else {
|
||||||
|
resHtml = '<div style="color:#555">Καμία έρευνα</div>';
|
||||||
|
}
|
||||||
|
document.getElementById('td-researches').innerHTML = resHtml;
|
||||||
|
|
||||||
const unitsObj = t.units || {};
|
const unitsObj = t.units || {};
|
||||||
let unitsHtml = '';
|
let unitsHtml = '';
|
||||||
for(const [unitKey, count] of Object.entries(unitsObj)) {
|
for(const [unitKey, count] of Object.entries(unitsObj)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user