Enhance proposal generation logic in FalukantService
- Implemented exclusion of existing proposals and active directors to avoid duplicate character selections. - Added detailed logging for SQL queries and fallback mechanisms when insufficient older characters are found. - Improved character selection process by combining excluded character IDs and ensuring a diverse set of proposals. - Streamlined the batch creation of director proposals with average knowledge calculations for better income predictions.
This commit is contained in:
@@ -2462,12 +2462,82 @@ 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;
|
||||||
for (let i = 0; i < proposalCount; i++) {
|
|
||||||
const directorCharacter = await FalukantCharacter.findOne({
|
// Hole bereits existierende Proposals, um diese Charaktere auszuschließen
|
||||||
where: {
|
const existingProposals = await DirectorProposal.findAll({
|
||||||
regionId,
|
where: { employerUserId: falukantUserId },
|
||||||
createdAt: { [Op.lt]: threeWeeksAgo },
|
attributes: ['directorCharacterId'],
|
||||||
|
raw: true
|
||||||
|
});
|
||||||
|
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}`);
|
||||||
|
|
||||||
|
// Versuche zuerst Charaktere, die mindestens 3 Wochen alt sind
|
||||||
|
let whereClause = {
|
||||||
|
regionId,
|
||||||
|
userId: null, // Nur NPCs
|
||||||
|
};
|
||||||
|
|
||||||
|
if (excludedCharacterIds.length > 0) {
|
||||||
|
whereClause.id = { [Op.notIn]: excludedCharacterIds };
|
||||||
|
}
|
||||||
|
whereClause.createdAt = { [Op.lt]: threeWeeksAgo };
|
||||||
|
|
||||||
|
// Erstelle Query-Objekt für Logging
|
||||||
|
const queryOptions = {
|
||||||
|
where: whereClause,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: TitleOfNobility,
|
||||||
|
as: 'nobleTitle',
|
||||||
|
attributes: ['level'],
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
order: sequelize.literal('RANDOM()'),
|
||||||
|
limit: proposalCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Logge die SQL-Query
|
||||||
|
try {
|
||||||
|
const query = FalukantCharacter.findAll(queryOptions);
|
||||||
|
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,
|
||||||
|
userId: null, // Nur NPCs
|
||||||
|
};
|
||||||
|
|
||||||
|
if (excludedCharacterIds.length > 0) {
|
||||||
|
fallbackWhereClause.id = { [Op.notIn]: excludedCharacterIds };
|
||||||
|
}
|
||||||
|
|
||||||
|
const fallbackQueryOptions = {
|
||||||
|
where: fallbackWhereClause,
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: TitleOfNobility,
|
model: TitleOfNobility,
|
||||||
@@ -2476,22 +2546,81 @@ class FalukantService extends BaseService {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
order: sequelize.literal('RANDOM()'),
|
order: sequelize.literal('RANDOM()'),
|
||||||
});
|
limit: proposalCount,
|
||||||
if (!directorCharacter) {
|
};
|
||||||
throw new Error('No directors available for the region');
|
|
||||||
|
// 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));
|
||||||
}
|
}
|
||||||
const avgKnowledge = await this.calculateAverageKnowledge(directorCharacter.id);
|
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 (directorCharacters.length === 0) {
|
||||||
|
console.error(`[generateProposals] No NPCs found in region ${regionId} at all`);
|
||||||
|
throw new Error('No directors available for the region');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[generateProposals] Found ${directorCharacters.length} available NPCs`);
|
||||||
|
|
||||||
|
// 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 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,
|
||||||
});
|
};
|
||||||
}
|
});
|
||||||
|
|
||||||
|
await DirectorProposal.bulkCreate(proposalsToCreate);
|
||||||
|
|
||||||
|
console.log(`[generateProposals] Created ${proposalsToCreate.length} director proposals for region ${regionId}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(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