Refactor proposal generation in FalukantService to improve character selection logic
- Removed the tracking of used character IDs and streamlined the exclusion of characters already proposed or currently active as directors. - Enhanced logging for SQL queries and fallback mechanisms to ensure better visibility during character selection. - Implemented a more efficient approach to gather and process character knowledge for proposal creation, ensuring accurate average calculations. - Improved error handling to provide clearer feedback when no eligible characters are found.
This commit is contained in:
@@ -2462,8 +2462,6 @@ class FalukantService extends BaseService {
|
|||||||
try {
|
try {
|
||||||
const threeWeeksAgo = new Date(Date.now() - 21 * 24 * 60 * 60 * 1000);
|
const threeWeeksAgo = new Date(Date.now() - 21 * 24 * 60 * 60 * 1000);
|
||||||
const proposalCount = Math.floor(Math.random() * 3) + 3;
|
const proposalCount = Math.floor(Math.random() * 3) + 3;
|
||||||
let createdProposals = 0;
|
|
||||||
const usedCharacterIds = new Set(); // Verhindere doppelte Proposals
|
|
||||||
|
|
||||||
// Hole bereits existierende Proposals, um diese Charaktere auszuschließen
|
// Hole bereits existierende Proposals, um diese Charaktere auszuschließen
|
||||||
const existingProposals = await DirectorProposal.findAll({
|
const existingProposals = await DirectorProposal.findAll({
|
||||||
@@ -2471,18 +2469,34 @@ class FalukantService extends BaseService {
|
|||||||
attributes: ['directorCharacterId'],
|
attributes: ['directorCharacterId'],
|
||||||
raw: true
|
raw: true
|
||||||
});
|
});
|
||||||
existingProposals.forEach(p => usedCharacterIds.add(p.directorCharacterId));
|
const proposalCharacterIds = existingProposals.map(p => p.directorCharacterId);
|
||||||
|
|
||||||
|
// Hole alle Charaktere, die bereits als Direktor arbeiten (egal für welchen User)
|
||||||
|
const existingDirectors = await Director.findAll({
|
||||||
|
attributes: ['directorCharacterId'],
|
||||||
|
raw: true
|
||||||
|
});
|
||||||
|
const directorCharacterIds = existingDirectors.map(d => d.directorCharacterId);
|
||||||
|
|
||||||
|
// Kombiniere beide Listen
|
||||||
|
const excludedCharacterIds = [...new Set([...proposalCharacterIds, ...directorCharacterIds])];
|
||||||
|
|
||||||
|
console.log(`[generateProposals] Excluding ${excludedCharacterIds.length} characters (${proposalCharacterIds.length} proposals + ${directorCharacterIds.length} active directors)`);
|
||||||
|
console.log(`[generateProposals] Region ID: ${regionId}, Proposal count needed: ${proposalCount}`);
|
||||||
|
|
||||||
for (let i = 0; i < proposalCount; i++) {
|
|
||||||
// Versuche zuerst Charaktere, die mindestens 3 Wochen alt sind
|
// Versuche zuerst Charaktere, die mindestens 3 Wochen alt sind
|
||||||
let whereClause = {
|
let whereClause = {
|
||||||
regionId,
|
regionId,
|
||||||
userId: null, // Nur NPCs
|
userId: null, // Nur NPCs
|
||||||
id: { [Op.notIn]: Array.from(usedCharacterIds) }, // Keine bereits verwendeten
|
|
||||||
createdAt: { [Op.lt]: threeWeeksAgo },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let directorCharacter = await FalukantCharacter.findOne({
|
if (excludedCharacterIds.length > 0) {
|
||||||
|
whereClause.id = { [Op.notIn]: excludedCharacterIds };
|
||||||
|
}
|
||||||
|
whereClause.createdAt = { [Op.lt]: threeWeeksAgo };
|
||||||
|
|
||||||
|
// Erstelle Query-Objekt für Logging
|
||||||
|
const queryOptions = {
|
||||||
where: whereClause,
|
where: whereClause,
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
@@ -2492,18 +2506,38 @@ class FalukantService extends BaseService {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
order: sequelize.literal('RANDOM()'),
|
order: sequelize.literal('RANDOM()'),
|
||||||
});
|
limit: proposalCount,
|
||||||
|
};
|
||||||
|
|
||||||
// Fallback: Wenn keine älteren Charaktere gefunden werden, verwende auch neuere
|
// Logge die SQL-Query
|
||||||
if (!directorCharacter) {
|
try {
|
||||||
console.log(`[generateProposals] No characters older than 3 weeks found in region ${regionId}, trying all NPCs...`);
|
const query = FalukantCharacter.findAll(queryOptions);
|
||||||
whereClause = {
|
const sqlQuery = query.toSQL ? query.toSQL() : query;
|
||||||
|
console.log(`[generateProposals] SQL Query (older than 3 weeks):`, JSON.stringify(sqlQuery, null, 2));
|
||||||
|
} catch (e) {
|
||||||
|
// Fallback: Logge die Query-Optionen direkt
|
||||||
|
console.log(`[generateProposals] Query Options (older than 3 weeks):`, JSON.stringify(queryOptions, null, 2));
|
||||||
|
}
|
||||||
|
console.log(`[generateProposals] WHERE clause:`, JSON.stringify(whereClause, null, 2));
|
||||||
|
console.log(`[generateProposals] Excluded character IDs:`, excludedCharacterIds);
|
||||||
|
|
||||||
|
let directorCharacters = await FalukantCharacter.findAll(queryOptions);
|
||||||
|
|
||||||
|
// Fallback: Wenn nicht genug ältere Charaktere gefunden werden, verwende auch neuere
|
||||||
|
if (directorCharacters.length < proposalCount) {
|
||||||
|
console.log(`[generateProposals] Only found ${directorCharacters.length} characters older than 3 weeks, trying all NPCs...`);
|
||||||
|
|
||||||
|
const fallbackWhereClause = {
|
||||||
regionId,
|
regionId,
|
||||||
userId: null, // Nur NPCs
|
userId: null, // Nur NPCs
|
||||||
id: { [Op.notIn]: Array.from(usedCharacterIds) },
|
|
||||||
};
|
};
|
||||||
directorCharacter = await FalukantCharacter.findOne({
|
|
||||||
where: whereClause,
|
if (excludedCharacterIds.length > 0) {
|
||||||
|
fallbackWhereClause.id = { [Op.notIn]: excludedCharacterIds };
|
||||||
|
}
|
||||||
|
|
||||||
|
const fallbackQueryOptions = {
|
||||||
|
where: fallbackWhereClause,
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: TitleOfNobility,
|
model: TitleOfNobility,
|
||||||
@@ -2512,35 +2546,79 @@ class FalukantService extends BaseService {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
order: sequelize.literal('RANDOM()'),
|
order: sequelize.literal('RANDOM()'),
|
||||||
|
limit: proposalCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Logge die Fallback-SQL-Query
|
||||||
|
try {
|
||||||
|
const fallbackQuery = FalukantCharacter.findAll(fallbackQueryOptions);
|
||||||
|
const fallbackSqlQuery = fallbackQuery.toSQL ? fallbackQuery.toSQL() : fallbackQuery;
|
||||||
|
console.log(`[generateProposals] SQL Query (all NPCs):`, JSON.stringify(fallbackSqlQuery, null, 2));
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`[generateProposals] Fallback Query Options:`, JSON.stringify(fallbackQueryOptions, null, 2));
|
||||||
|
}
|
||||||
|
console.log(`[generateProposals] Fallback WHERE clause:`, JSON.stringify(fallbackWhereClause, null, 2));
|
||||||
|
|
||||||
|
const fallbackCharacters = await FalukantCharacter.findAll(fallbackQueryOptions);
|
||||||
|
|
||||||
|
// Kombiniere beide Listen und entferne Duplikate
|
||||||
|
const allCharacterIds = new Set(directorCharacters.map(c => c.id));
|
||||||
|
fallbackCharacters.forEach(c => {
|
||||||
|
if (!allCharacterIds.has(c.id)) {
|
||||||
|
directorCharacters.push(c);
|
||||||
|
allCharacterIds.add(c.id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Limitiere auf proposalCount
|
||||||
|
directorCharacters = directorCharacters.slice(0, proposalCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!directorCharacter) {
|
if (directorCharacters.length === 0) {
|
||||||
console.warn(`[generateProposals] No more available NPCs in region ${regionId} (${usedCharacterIds.size} already used)`);
|
console.error(`[generateProposals] No NPCs found in region ${regionId} at all`);
|
||||||
// Wenn keine Charaktere gefunden werden, breche die Schleife ab
|
|
||||||
// aber wirf keinen Fehler, wenn bereits einige Proposals erstellt wurden
|
|
||||||
if (createdProposals === 0) {
|
|
||||||
throw new Error('No directors available for the region');
|
throw new Error('No directors available for the region');
|
||||||
}
|
}
|
||||||
break; // Stoppe die Schleife, aber wirf keinen Fehler
|
|
||||||
}
|
|
||||||
|
|
||||||
// Füge diesen Charakter zu den verwendeten hinzu
|
console.log(`[generateProposals] Found ${directorCharacters.length} available NPCs`);
|
||||||
usedCharacterIds.add(directorCharacter.id);
|
|
||||||
|
// Batch-Berechnung der Knowledge-Werte
|
||||||
|
const characterIds = directorCharacters.map(c => c.id);
|
||||||
|
const allKnowledges = await Knowledge.findAll({
|
||||||
|
where: { characterId: { [Op.in]: characterIds } },
|
||||||
|
attributes: ['characterId', 'knowledge'],
|
||||||
|
raw: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gruppiere Knowledge nach characterId und berechne Durchschnitt
|
||||||
|
const knowledgeMap = new Map();
|
||||||
|
characterIds.forEach(id => knowledgeMap.set(id, []));
|
||||||
|
allKnowledges.forEach(k => {
|
||||||
|
const list = knowledgeMap.get(k.characterId) || [];
|
||||||
|
list.push(k.knowledge);
|
||||||
|
knowledgeMap.set(k.characterId, list);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Erstelle alle Proposals in einem Batch
|
||||||
|
const proposalsToCreate = directorCharacters.map(character => {
|
||||||
|
const knowledges = knowledgeMap.get(character.id) || [];
|
||||||
|
const avgKnowledge = knowledges.length > 0
|
||||||
|
? knowledges.reduce((sum, k) => sum + k, 0) / knowledges.length
|
||||||
|
: 0;
|
||||||
|
|
||||||
const avgKnowledge = await this.calculateAverageKnowledge(directorCharacter.id);
|
|
||||||
const proposedIncome = Math.round(
|
const proposedIncome = Math.round(
|
||||||
directorCharacter.nobleTitle.level * Math.pow(1.231, avgKnowledge / 1.5)
|
character.nobleTitle.level * Math.pow(1.231, avgKnowledge / 1.5)
|
||||||
);
|
);
|
||||||
await DirectorProposal.create({
|
|
||||||
directorCharacterId: directorCharacter.id,
|
return {
|
||||||
|
directorCharacterId: character.id,
|
||||||
employerUserId: falukantUserId,
|
employerUserId: falukantUserId,
|
||||||
proposedIncome,
|
proposedIncome,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
createdProposals++;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`[generateProposals] Created ${createdProposals} director proposals for region ${regionId}`);
|
await DirectorProposal.bulkCreate(proposalsToCreate);
|
||||||
|
|
||||||
|
console.log(`[generateProposals] Created ${proposalsToCreate.length} director proposals for region ${regionId}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[generateProposals] Error:', error.message, error.stack);
|
console.error('[generateProposals] Error:', error.message, error.stack);
|
||||||
throw new Error(error.message);
|
throw new Error(error.message);
|
||||||
|
|||||||
Reference in New Issue
Block a user