fix for buildinds

This commit is contained in:
2026-04-29 22:05:57 +03:00
parent d952e7ca56
commit 1db8d744c8
4 changed files with 71 additions and 10 deletions

View File

@@ -833,8 +833,8 @@
return;
}
// Build queue, Recruit queue and Market queue are independent
const buildCmd = cmdData.build;
// Build queue: one command per town (all towns build in the same poll cycle)
const buildCmds = cmdData.builds || [];
const recruitCmd = cmdData.recruit;
const marketCmd = cmdData.market;
const researchCmd = cmdData.research;
@@ -873,8 +873,16 @@
reportResult(cmd.id, finalStatus, result.msg);
};
// Run sequentially — humans cannot perform 3 actions simultaneously!
await execute(buildCmd);
// Execute ALL town build commands (one per town, sequential with inter-town delay)
for (let i = 0; i < buildCmds.length; i++) {
await execute(buildCmds[i]);
if (i < buildCmds.length - 1) {
// Random gap between towns so it doesn't look like a macro
const gap = randInt(1500, 3000);
log(`Build: town done. Waiting ${gap}ms before next town...`);
await sleep(gap);
}
}
await execute(recruitCmd);
await execute(marketCmd);
await execute(researchCmd);

View File

@@ -22,7 +22,8 @@ async function pollAndExecute() {
const farmOn = features.includes('farm');
const adminOn = features.includes('admin');
const buildCmd = adminOn ? cmdData.build : null;
// Build: one command per town (server returns an array)
const buildCmds = adminOn ? (cmdData.builds || []) : [];
const recruitCmd = adminOn ? cmdData.recruit : null;
const marketCmd = adminOn ? cmdData.market : null;
const researchCmd = adminOn ? cmdData.research : null;
@@ -60,8 +61,16 @@ async function pollAndExecute() {
reportResult(cmd.id, finalStatus, result.msg);
};
// Run sequentially — humans cannot perform 3 actions simultaneously!
await execute(buildCmd);
// Execute one build command per town (simultaneous queue draining across all villages)
for (let i = 0; i < buildCmds.length; i++) {
await execute(buildCmds[i]);
if (i < buildCmds.length - 1) {
// Random inter-town gap — avoids looking like a macro
const gap = randInt(1500, 3000);
log(`Build: town done. Waiting ${gap}ms before next town...`);
await sleep(gap);
}
}
await execute(recruitCmd);
await execute(marketCmd);
await execute(researchCmd);

BIN
grepo.db

Binary file not shown.

View File

@@ -105,10 +105,11 @@ def receive_state():
# so both queues are served in parallel without blocking each other.
# ------------------------------------------------------------------
def _fetch_pending_of_type(c, cmd_type, player_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 id ASC
ORDER BY updated_at ASC, id ASC
LIMIT 1
''', (cmd_type, player_id)).fetchone()
if not row:
@@ -125,6 +126,49 @@ def _fetch_pending_of_type(c, cmd_type, player_id):
'payload': json.loads(row['payload'])
}
def _fetch_pending_builds_all_towns(c, player_id):
"""
Fetch ONE pending 'build' command per distinct town_id.
This allows all towns to build in parallel within a single poll cycle.
Within each town the oldest-updated command is picked first, so requeued
commands (updated_at = now) naturally sort behind fresh ones.
"""
# 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()
results = []
now = datetime.utcnow().isoformat()
for town_row in town_rows:
town_id = town_row['town_id']
row = c.execute('''
SELECT * FROM commands
WHERE status = 'pending' AND type = 'build'
AND player_id = ? AND town_id = ?
ORDER BY updated_at ASC, id ASC
LIMIT 1
''', (player_id, town_id)).fetchone()
if not row:
continue
c.execute('''
UPDATE commands SET status = 'executing', updated_at = ?
WHERE id = ?
''', (now, row['id']))
results.append({
'id': row['id'],
'town_id': row['town_id'],
'type': row['type'],
'payload': json.loads(row['payload'])
})
return results
@api.route('/api/commands/pending', methods=['GET'])
def get_pending_command():
player_id = request.args.get('player_id')
@@ -134,7 +178,7 @@ def get_pending_command():
conn = get_db()
c = conn.cursor()
build_cmd = _fetch_pending_of_type(c, 'build', 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)
@@ -164,7 +208,7 @@ def get_pending_command():
conn.close()
return jsonify({
'build': build_cmd,
'builds': build_cmds, # list: one build command per town
'recruit': recruit_cmd,
'market': market_cmd,
'research': research_cmd,