UNPKG

@aituber-onair/kizuna

Version:

A sophisticated bond system (絆 - Kizuna) for managing relationships between users and AI characters in AITuber OnAir.

295 lines 9.89 kB
/** * PointCalculator - Point calculation class * * Manages platform-specific point rules and performs point calculations */ /** * Point calculation class */ export class PointCalculator { constructor(config) { this.cooldowns = new Map(); this.config = config; } /** * Main method for point calculation */ calculatePoints(context, user) { const result = { points: 0, appliedRules: [], breakdown: [], }; // Calculate base points const basePoints = this.calculateBasePoints(context, user); if (basePoints > 0) { result.points += basePoints; result.breakdown.push({ ruleName: "base_points", points: basePoints, description: `Base points (${context.platform})`, }); } // Apply platform-specific rules const platformRules = this.applyPlatformRules(context, user); result.points += platformRules.points; result.appliedRules.push(...platformRules.appliedRules); result.breakdown.push(...platformRules.breakdown); // Apply custom rules const customRules = this.applyCustomRules(context, user); result.points += customRules.points; result.appliedRules.push(...customRules.appliedRules); result.breakdown.push(...customRules.breakdown); // Apply owner multiplier if (user.type === "owner") { const multiplier = this.config.owner.pointMultiplier; const bonusPoints = Math.floor(result.points * (multiplier - 1)); if (bonusPoints > 0) { result.points += bonusPoints; result.breakdown.push({ ruleName: "owner_multiplier", points: bonusPoints, description: `Owner multiplier bonus (×${multiplier})`, }); } } // Check daily bonus const dailyBonus = this.checkDailyBonus(context, user); if (dailyBonus > 0) { result.points += dailyBonus; result.breakdown.push({ ruleName: "daily_bonus", points: dailyBonus, description: "Daily bonus", }); } this.log(`Points calculated for ${user.id}: ${result.points} (${result.appliedRules.length} rules applied)`); return result; } /** * Check if a specific rule can be applied */ canApplyRule(rule, context, user) { const cooldownKey = `${user.id}:${rule.id}`; if (this.config.dev.debugMode) { this.log(`[canApplyRule] Checking rule: ${rule.id} for emotion: ${context.emotion}`); } // Cooldown check if (rule.cooldown && rule.cooldown > 0) { const record = this.cooldowns.get(cooldownKey); if (record) { const timePassed = Date.now() - record.lastApplied; if (timePassed < rule.cooldown) { if (this.config.dev.debugMode) { this.log(`[canApplyRule] Rule ${rule.id} blocked by cooldown (${timePassed}ms < ${rule.cooldown}ms)`); } return false; } } } // Daily limit check if (rule.dailyLimit && rule.dailyLimit > 0) { const record = this.getCooldownRecord(cooldownKey); if (record.todayCount >= rule.dailyLimit) { if (this.config.dev.debugMode) { this.log(`[canApplyRule] Rule ${rule.id} blocked by daily limit (${record.todayCount} >= ${rule.dailyLimit})`); } return false; } } // Condition check try { const conditionResult = rule.condition(context, user); if (this.config.dev.debugMode) { this.log(`[canApplyRule] Rule ${rule.id} condition result: ${conditionResult}`); } return conditionResult; } catch (error) { this.log(`Error evaluating rule condition for ${rule.id}: ${error}`); return false; } } /** * Record rule application (cooldown management) */ recordRuleApplication(rule, userId) { const cooldownKey = `${userId}:${rule.id}`; const record = this.getCooldownRecord(cooldownKey); record.lastApplied = Date.now(); record.todayCount++; this.cooldowns.set(cooldownKey, record); } /** * Clear cooldown data */ clearCooldowns() { this.cooldowns.clear(); } /** * Reset cooldowns for specific user */ resetUserCooldowns(userId) { for (const [key] of this.cooldowns) { if (key.startsWith(`${userId}:`)) { this.cooldowns.delete(key); } } } // ============================================================================ // Private methods // ============================================================================ /** * Calculate base points */ calculateBasePoints(context, user) { const platformConfig = this.getPlatformConfig(context.platform); if (!platformConfig) { return 1; // Default points } // Platform-specific base points const actionType = this.getActionType(context); return platformConfig.basePoints[actionType] || 1; } /** * Apply platform-specific rules */ applyPlatformRules(context, user) { const result = { points: 0, appliedRules: [], breakdown: [], }; const platformConfig = this.getPlatformConfig(context.platform); if (!platformConfig?.customRules) { return result; } for (const rule of platformConfig.customRules) { if (this.canApplyRule(rule, context, user)) { result.points += rule.points; result.appliedRules.push(rule); result.breakdown.push({ ruleName: rule.id, points: rule.points, description: rule.description || rule.name, }); this.recordRuleApplication(rule, user.id); } } // Platform-specific bonus calculation if (platformConfig.bonusCalculator) { try { const bonus = platformConfig.bonusCalculator(context); if (bonus > 0) { result.points += bonus; result.breakdown.push({ ruleName: "platform_bonus", points: bonus, description: `${context.platform} platform bonus`, }); } } catch (error) { this.log(`Error in platform bonus calculator: ${error}`); } } return result; } /** * Apply custom rules */ applyCustomRules(context, user) { const result = { points: 0, appliedRules: [], breakdown: [], }; const customRules = this.config.customRules || []; for (const rule of customRules) { if (this.canApplyRule(rule, context, user)) { result.points += rule.points; result.appliedRules.push(rule); result.breakdown.push({ ruleName: rule.id, points: rule.points, description: rule.description || rule.name, }); this.recordRuleApplication(rule, user.id); } } return result; } /** * Check daily bonus */ checkDailyBonus(context, user) { // No daily bonus for non-owners if (user.type !== "owner") { return 0; } const bonusKey = `${user.id}:daily_bonus`; const record = this.getCooldownRecord(bonusKey); // If bonus already received today if (record.todayCount > 0) { return 0; } // Award daily bonus record.todayCount = 1; record.lastApplied = Date.now(); this.cooldowns.set(bonusKey, record); return this.config.owner.dailyBonus; } /** * Get platform configuration */ getPlatformConfig(platform) { return this.config.platforms[platform] || null; } /** * Get action type */ getActionType(context) { // Get action type from metadata if (context.metadata?.actionType) { return context.metadata.actionType; } // Platform-specific default actions switch (context.platform) { case "youtube": return "comment"; case "twitch": return "chat"; case "websocket": return "message"; default: return "message"; } } /** * Get or create cooldown record */ getCooldownRecord(key) { const today = new Date().toISOString().split("T")[0] || ""; // YYYY-MM-DD const existing = this.cooldowns.get(key); if (existing && existing.today === today) { return existing; } // New day or first time const newRecord = { lastApplied: 0, todayCount: 0, today: today, }; this.cooldowns.set(key, newRecord); return newRecord; } /** * Log output */ log(message) { if (this.config.dev.debugMode) { console.log(`[PointCalculator] ${message}`); } } } //# sourceMappingURL=PointCalculator.js.map