Compare commits

..

4 Commits

3 changed files with 129 additions and 49 deletions

View File

@ -0,0 +1,29 @@
-- Manual travelnode coverage for the Aldrassil ramp in Shadowglen
-- (Teldrassil, map 1, zone 141). Adds 9 anchor nodes along the spiral
-- ramp (base -> intermediate ramp waypoints -> top platform near
-- Tenaron Stormgrip). All nodes are `linked = 0` so
-- `.playerbots travel generatenode` will iterate them and let mmap
-- compute the actual walk paths between consecutive nodes. Splitting
-- the climb into short segments (~30y each) gives mmap a much better
-- chance of resolving each piece than a single 300y end-to-end probe.
SET @n1 := (SELECT IFNULL(MAX(id), 0) + 1 FROM playerbots_travelnode);
SET @n2 := @n1 + 1;
SET @n3 := @n1 + 2;
SET @n4 := @n1 + 3;
SET @n5 := @n1 + 4;
SET @n6 := @n1 + 5;
SET @n7 := @n1 + 6;
SET @n8 := @n1 + 7;
SET @n9 := @n1 + 8;
INSERT INTO playerbots_travelnode (id, name, map_id, x, y, z, linked) VALUES
(@n1, 'Aldrassil Ramp 1 (base)', 1, 10413.756, 887.97363, 1319.3668, 0),
(@n2, 'Aldrassil Ramp 2', 1, 10440.520, 870.32320, 1328.9324, 0),
(@n3, 'Aldrassil Ramp 3', 1, 10497.001, 854.46014, 1345.1770, 0),
(@n4, 'Aldrassil Ramp 4', 1, 10517.199, 821.48640, 1354.7914, 0),
(@n5, 'Aldrassil Ramp 5', 1, 10477.926, 847.88855, 1372.1685, 0),
(@n6, 'Aldrassil Ramp 6', 1, 10455.358, 831.34240, 1380.9377, 0),
(@n7, 'Aldrassil Ramp 7', 1, 10460.220, 800.71716, 1388.3368, 0),
(@n8, 'Aldrassil Ramp 8', 1, 10507.434, 793.30420, 1397.2166, 0),
(@n9, 'Aldrassil Ramp 9 (top)', 1, 10495.496, 804.67700, 1397.2662, 0);

View File

@ -180,11 +180,11 @@ void MovementAction::EmitDebugMove(char const* method, char const* generator, fl
float dis = bot->GetExactDist(x, y, z);
std::ostringstream out;
out << "[MOVE] meth=" << method
<< " | via=" << (generator && *generator ? generator : "-")
<< " | rpg=" << statusName
<< " | d=" << dis << "y"
<< " | targ=" << (targetName.empty() ? "-" : targetName.c_str());
out << "[M] | " << method
<< " | " << (generator && *generator ? generator : "-")
<< " | " << statusName
<< " | " << std::fixed << std::setprecision(2) << dis << " yard"
<< " | " << (targetName.empty() ? "-" : targetName.c_str());
if (extra && *extra)
out << " | " << extra;
botAI->TellMasterNoFacing(out);

View File

@ -2018,15 +2018,24 @@ void TravelNodeMap::saveNodeStore()
hasToSave = false;
PlayerbotsDatabaseTransaction trans = PlayerbotsDatabase.BeginTransaction();
constexpr uint32 STMTS_PER_TX = 500; // bounded transaction size
trans->Append(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_TRAVELNODE));
trans->Append(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_TRAVELNODE_LINK));
trans->Append(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_TRAVELNODE_PATH));
// Phase 1: deletes in their own transaction.
{
PlayerbotsDatabaseTransaction delTrans = PlayerbotsDatabase.BeginTransaction();
delTrans->Append(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_TRAVELNODE));
delTrans->Append(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_TRAVELNODE_LINK));
delTrans->Append(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_TRAVELNODE_PATH));
PlayerbotsDatabase.CommitTransaction(delTrans);
}
std::unordered_map<TravelNode*, uint32> saveNodes;
std::vector<TravelNode*> anodes = TravelNodeMap::instance().getNodes();
// Phase 2: node inserts, chunked at STMTS_PER_TX per transaction.
{
PlayerbotsDatabaseTransaction nodeTrans = PlayerbotsDatabase.BeginTransaction();
uint32 inTx = 0;
for (uint32 i = 0; i < anodes.size(); i++)
{
TravelNode* node = anodes[i];
@ -2042,14 +2051,27 @@ void TravelNodeMap::saveNodeStore()
stmt->SetData(4, node->getY());
stmt->SetData(5, node->getZ());
stmt->SetData(6, node->isLinked());
trans->Append(stmt);
nodeTrans->Append(stmt);
saveNodes.insert(std::make_pair(node, i));
if (++inTx >= STMTS_PER_TX)
{
PlayerbotsDatabase.CommitTransaction(nodeTrans);
nodeTrans = PlayerbotsDatabase.BeginTransaction();
inTx = 0;
}
}
PlayerbotsDatabase.CommitTransaction(nodeTrans);
}
LOG_INFO("playerbots", ">> Saved {} travelNodes.", anodes.size());
// Phase 3: link inserts, chunked at STMTS_PER_TX per transaction.
uint32 paths = 0;
{
PlayerbotsDatabaseTransaction linkTrans = PlayerbotsDatabase.BeginTransaction();
uint32 inTx = 0;
for (uint32 i = 0; i < anodes.size(); i++)
{
TravelNode* node = anodes[i];
@ -2071,18 +2093,34 @@ void TravelNodeMap::saveNodeStore()
stmt->SetData(8, path->getMaxLevelCreature()[0]);
stmt->SetData(9, path->getMaxLevelCreature()[1]);
stmt->SetData(10, path->getMaxLevelCreature()[2]);
trans->Append(stmt);
linkTrans->Append(stmt);
paths++;
if (++inTx >= STMTS_PER_TX)
{
PlayerbotsDatabase.CommitTransaction(linkTrans);
linkTrans = PlayerbotsDatabase.BeginTransaction();
inTx = 0;
}
}
// Path points: bulk raw SQL multi-row INSERTs (~500 rows each) instead of
// 1M+ individual prepared statements. Appended to the same transaction so
// ordering is guaranteed.
}
PlayerbotsDatabase.CommitTransaction(linkTrans);
}
// Phase 2: path points in chunked transactions. Previously all
// ~1.5M point inserts went into a single mega-transaction which
// exceeded MySQL's packet/transaction limits and partial-committed,
// corrupting the DB (links saved, paths empty). Chunk now commits
// every ~10000 rows. A failed chunk loses only its rows; the rest
// survive.
constexpr uint32 BATCH_SIZE = 500;
constexpr uint32 BATCHES_PER_COMMIT = 20; // 20 * 500 = 10000 rows per tx
uint32 points = 0;
std::ostringstream ss;
uint32 batchCount = 0;
uint32 batchesInCurrentTx = 0;
PlayerbotsDatabaseTransaction pathTrans = PlayerbotsDatabase.BeginTransaction();
auto flushBatch = [&]()
{
@ -2091,10 +2129,21 @@ void TravelNodeMap::saveNodeStore()
std::string sql = ss.str();
sql.back() = ';'; // Replace trailing comma
trans->Append(sql.c_str());
pathTrans->Append(sql.c_str());
ss.str("");
ss.clear();
batchCount = 0;
batchesInCurrentTx++;
};
auto commitIfFull = [&]()
{
if (batchesInCurrentTx >= BATCHES_PER_COMMIT)
{
PlayerbotsDatabase.CommitTransaction(pathTrans);
pathTrans = PlayerbotsDatabase.BeginTransaction();
batchesInCurrentTx = 0;
}
};
for (uint32 i = 0; i < anodes.size(); i++)
@ -2125,16 +2174,18 @@ void TravelNodeMap::saveNodeStore()
points++;
if (batchCount >= BATCH_SIZE)
{
flushBatch();
commitIfFull();
}
}
}
}
flushBatch();
PlayerbotsDatabase.CommitTransaction(pathTrans);
LOG_INFO("playerbots", ">> Saved {} travelNode Paths, {} points.", paths, points);
PlayerbotsDatabase.CommitTransaction(trans);
}
void TravelNodeMap::LoadNodeStore()