fix different world different admin

This commit is contained in:
2026-05-02 00:25:02 +03:00
parent 5f6855ec69
commit 2552d3d075
8 changed files with 80 additions and 51 deletions

View File

@@ -112,14 +112,15 @@ def receive_state():
# Returns one 'build' AND one 'recruit' command independently,
# so both queues are served in parallel without blocking each other.
# ------------------------------------------------------------------
def _fetch_pending_of_type(c, cmd_type, player_id):
def _fetch_pending_of_type(c, cmd_type, player_id, world_id):
"""Fetch a single oldest pending command of a given type (recruit, market, etc.)."""
row = c.execute('''
SELECT * FROM commands
WHERE status = 'pending' AND type = ? AND player_id = ?
ORDER BY updated_at ASC, id ASC
SELECT c.* FROM commands c
JOIN town_state ts ON c.town_id = ts.town_id
WHERE c.status = 'pending' AND c.type = ? AND c.player_id = ? AND ts.world_id = ?
ORDER BY c.updated_at ASC, c.id ASC
LIMIT 1
''', (cmd_type, player_id)).fetchone()
''', (cmd_type, player_id, world_id)).fetchone()
if not row:
return None
c.execute('''
@@ -135,7 +136,7 @@ def _fetch_pending_of_type(c, cmd_type, player_id):
}
def _fetch_pending_builds_all_towns(c, player_id):
def _fetch_pending_builds_all_towns(c, player_id, world_id):
"""
Fetch ONE pending 'build' command per distinct town_id.
This allows all towns to build in parallel within a single poll cycle.
@@ -148,20 +149,22 @@ def _fetch_pending_builds_all_towns(c, player_id):
"""
# Towns that currently have a build already in-flight — don't touch those.
executing_rows = c.execute('''
SELECT DISTINCT town_id FROM commands
WHERE status = 'executing' AND type = 'build' AND player_id = ?
''', (player_id,)).fetchall()
SELECT DISTINCT c.town_id FROM commands c
JOIN town_state ts ON c.town_id = ts.town_id
WHERE c.status = 'executing' AND c.type = 'build' AND c.player_id = ? AND ts.world_id = ?
''', (player_id, world_id)).fetchall()
busy_towns = {r['town_id'] for r in executing_rows}
# Get every town that has at least one pending build, ordered by
# which town has been waiting longest (MIN updated_at across its commands).
town_rows = c.execute('''
SELECT town_id
FROM commands
WHERE status = 'pending' AND type = 'build' AND player_id = ?
GROUP BY town_id
ORDER BY MIN(updated_at) ASC
''', (player_id,)).fetchall()
SELECT c.town_id
FROM commands c
JOIN town_state ts ON c.town_id = ts.town_id
WHERE c.status = 'pending' AND c.type = 'build' AND c.player_id = ? AND ts.world_id = ?
GROUP BY c.town_id
ORDER BY MIN(c.updated_at) ASC
''', (player_id, world_id)).fetchall()
results = []
now = datetime.utcnow().isoformat()
@@ -196,6 +199,7 @@ def _fetch_pending_builds_all_towns(c, player_id):
@api.route('/api/commands/pending', methods=['GET'])
def get_pending_command():
player_id = request.args.get('player_id')
world_id = request.args.get('world_id')
if not player_id:
return jsonify({'error': 'no player_id provided'}), 400
@@ -210,12 +214,12 @@ def get_pending_command():
WHERE status = 'executing' AND updated_at < ? AND player_id = ?
''', (two_minutes_ago, player_id))
build_cmds = _fetch_pending_builds_all_towns(c, player_id) # one per town
recruit_cmd = _fetch_pending_of_type(c, 'recruit', player_id)
market_cmd = _fetch_pending_of_type(c, 'market_offer', player_id)
farm_cmd = _fetch_pending_of_type(c, 'farm_loot', player_id)
farm_upgrade_cmd = _fetch_pending_of_type(c, 'farm_upgrade', player_id)
research_cmd = _fetch_pending_of_type(c, 'research', player_id)
build_cmds = _fetch_pending_builds_all_towns(c, player_id, world_id) # one per town
recruit_cmd = _fetch_pending_of_type(c, 'recruit', player_id, world_id)
market_cmd = _fetch_pending_of_type(c, 'market_offer', player_id, world_id)
farm_cmd = _fetch_pending_of_type(c, 'farm_loot', player_id, world_id)
farm_upgrade_cmd = _fetch_pending_of_type(c, 'farm_upgrade', player_id, world_id)
research_cmd = _fetch_pending_of_type(c, 'research', player_id, world_id)
sync_req = _check_and_reset_sync(c, player_id)
# Farm settings

View File

@@ -26,12 +26,12 @@ def index():
# Only fetch players that are members of this clan
rows = conn.execute('''
SELECT ts.player, ts.player_id, MAX(ts.updated_at) as last_seen, MAX(ts.world_id) as world_id
SELECT ts.player, ts.player_id, ts.world_id, MAX(ts.updated_at) as last_seen
FROM town_state ts
INNER JOIN clan_members cm ON cm.player_id = ts.player_id AND cm.clan_id = ?
WHERE ts.player IS NOT NULL
GROUP BY ts.player, ts.player_id
ORDER BY ts.player ASC
GROUP BY ts.player, ts.player_id, ts.world_id
ORDER BY ts.player ASC, ts.world_id ASC
''', (clan_id,)).fetchall()
captcha_rows = conn.execute("SELECT key, value FROM kv_store WHERE key LIKE 'captcha_active_%'").fetchall()
@@ -61,20 +61,20 @@ def index():
return render_template('index.html', players=players, no_clan=False)
@dashboard.route('/player/<player_id>')
@dashboard.route('/player/<player_id>/<world_id>')
@login_required
def player_hub(player_id):
return render_template('hub.html', player_id=player_id)
def player_hub(player_id, world_id):
return render_template('hub.html', player_id=player_id, world_id=world_id)
@dashboard.route('/player/<player_id>/admin')
@dashboard.route('/player/<player_id>/<world_id>/admin')
@login_required
def player_dashboard(player_id):
return render_template('dashboard.html', player_id=player_id)
def player_dashboard(player_id, world_id):
return render_template('dashboard.html', player_id=player_id, world_id=world_id)
@dashboard.route('/player/<player_id>/farm')
@dashboard.route('/player/<player_id>/<world_id>/farm')
@login_required
def player_farm(player_id):
return render_template('farm.html', player_id=player_id)
def player_farm(player_id, world_id):
return render_template('farm.html', player_id=player_id, world_id=world_id)
# ------------------------------------------------------------------
@@ -176,16 +176,26 @@ def get_market_data():
@dashboard.route('/dashboard/towns', methods=['GET'])
def get_towns():
player_id = request.args.get('player_id')
world_id = request.args.get('world_id')
conn = get_db()
rows = conn.execute('''
query = '''
SELECT ts.town_id, ts.town_name, ts.player, ts.player_id, ts.alliance_id,
ts.world_id, ts.x, ts.y, ts.sea, ts.data, ts.updated_at,
tb.blueprint_name, tb.is_active as blueprint_active
FROM town_state ts
LEFT JOIN town_blueprints tb ON ts.town_id = tb.town_id AND tb.is_active = 1
WHERE ts.player_id = ?
ORDER BY ts.town_name ASC
''', (player_id, )).fetchall()
'''
params = [player_id]
if world_id:
query += ' AND ts.world_id = ?'
params.append(world_id)
query += ' ORDER BY ts.town_name ASC'
rows = conn.execute(query, params).fetchall()
conn.close()
towns = []
@@ -367,13 +377,24 @@ def reorder_commands():
def get_commands():
player_id = request.args.get('player_id')
conn = get_db()
rows = conn.execute('''
SELECT id, town_id, town_name, type, payload, status, result_msg, created_at, updated_at
FROM commands
WHERE player_id = ?
ORDER BY id DESC
LIMIT 50
''', (player_id, )).fetchall()
world_id = request.args.get('world_id')
conn = get_db()
query = '''
SELECT c.id, c.town_id, c.town_name, c.type, c.payload, c.status, c.result_msg, c.created_at, c.updated_at
FROM commands c
JOIN town_state ts ON c.town_id = ts.town_id
WHERE c.player_id = ?
'''
params = [player_id]
if world_id:
query += ' AND ts.world_id = ?'
params.append(world_id)
query += ' ORDER BY c.id DESC LIMIT 50'
rows = conn.execute(query, params).fetchall()
conn.close()
return jsonify([dict(r) for r in rows])