feat: wire economy LC to message/voice, add LevelRoleService, improve level-up embed
- MessageListener: +1-3 LC per message - VoiceTracker: +1 LC/min periodic, +1 LC/2min on leave - LevelRoleService: auto-assigns roles (Активный/Постоянный/Ветеран/Легенда/Мастер) at levels 5/10/20/30/50 - LevelUpNotifier: progress bar, role reward display, EmbedFactory chain
This commit is contained in:
parent
fe121c8546
commit
283b30f979
5 changed files with 94 additions and 35 deletions
|
|
@ -58,8 +58,14 @@ public class LevelModule extends AbstractModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
LevelUpNotifier provideLevelUpNotifier(ConfigRepository configRepo, LevelService levelService) {
|
||||
return new LevelUpNotifier(configRepo, levelService);
|
||||
LevelRoleService provideLevelRoleService() {
|
||||
return new LevelRoleService();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
LevelUpNotifier provideLevelUpNotifier(ConfigRepository configRepo, LevelService levelService, LevelRoleService levelRoleService) {
|
||||
return new LevelUpNotifier(configRepo, levelService, levelRoleService);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
package creator.loki.feature.level;
|
||||
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class LevelRoleService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(LevelRoleService.class);
|
||||
private static final Map<Integer, String> REWARD_ROLES = Map.of(
|
||||
5, "Активный",
|
||||
10, "Постоянный",
|
||||
20, "Ветеран",
|
||||
30, "Легенда",
|
||||
50, "Мастер"
|
||||
);
|
||||
|
||||
public String assignRewardRole(Member member, int newLevel) {
|
||||
String roleName = REWARD_ROLES.get(newLevel);
|
||||
if (roleName == null) return null;
|
||||
|
||||
List<Role> roles = member.getGuild().getRolesByName(roleName, true);
|
||||
if (roles.isEmpty()) {
|
||||
logger.warn("Role '{}' not found in guild {} for level {} reward",
|
||||
roleName, member.getGuild().getId(), newLevel);
|
||||
return null;
|
||||
}
|
||||
|
||||
Role role = roles.get(0);
|
||||
if (member.getRoles().contains(role)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
member.getGuild().addRoleToMember(member, role).queue(
|
||||
success -> logger.info("Assigned role '{}' to {} for level {}",
|
||||
roleName, member.getEffectiveName(), newLevel),
|
||||
error -> logger.error("Failed to assign role '{}' to {}: {}",
|
||||
roleName, member.getEffectiveName(), error.getMessage())
|
||||
);
|
||||
|
||||
return roleName;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package creator.loki.feature.level;
|
||||
|
||||
import creator.loki.embed.EmbedFactory;
|
||||
import creator.loki.feature.config.repository.ConfigRepository;
|
||||
import creator.loki.feature.level.domain.LevelProgress;
|
||||
import creator.loki.feature.level.service.LevelService;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
|
|
@ -19,10 +19,12 @@ public class LevelUpNotifier {
|
|||
private static final Logger logger = LoggerFactory.getLogger(LevelUpNotifier.class);
|
||||
private final ConfigRepository configRepo;
|
||||
private final LevelService levelService;
|
||||
private final LevelRoleService levelRoleService;
|
||||
|
||||
public LevelUpNotifier(ConfigRepository configRepo, LevelService levelService) {
|
||||
public LevelUpNotifier(ConfigRepository configRepo, LevelService levelService, LevelRoleService levelRoleService) {
|
||||
this.configRepo = configRepo;
|
||||
this.levelService = levelService;
|
||||
this.levelRoleService = levelRoleService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -30,27 +32,26 @@ public class LevelUpNotifier {
|
|||
*/
|
||||
public void sendLevelUpNotification(Member member, int oldLevel, int newLevel, MessageChannel channel) {
|
||||
LevelProgress progress = levelService.getProgress(member.getId());
|
||||
|
||||
EmbedBuilder embed = new EmbedBuilder()
|
||||
.setTitle("🎉 Повышение уровня!")
|
||||
.setDescription(member.getAsMention() + " достиг **уровня " + newLevel + "**!")
|
||||
.addField("Предыдущий уровень", String.valueOf(oldLevel), true)
|
||||
.addField("Новый уровень", String.valueOf(newLevel), true)
|
||||
.addField("Всего XP", String.valueOf(progress.getTotalXP()), true)
|
||||
.addField("До следующего уровня",
|
||||
progress.getCurrentLevelXP() + " / " + progress.getXpForNextLevel() + " XP", false)
|
||||
.setColor(getColorForLevel(newLevel))
|
||||
.setThumbnail(member.getEffectiveAvatarUrl())
|
||||
.setFooter("Продолжай в том же духе!");
|
||||
|
||||
// Добавляем награды за уровень
|
||||
String reward = getRewardForLevel(newLevel);
|
||||
if (reward != null) {
|
||||
embed.addField("🎁 Награда", reward, false);
|
||||
String progressBar = buildProgressBar(progress.getPercentage());
|
||||
String rewardRole = levelRoleService.assignRewardRole(member, newLevel);
|
||||
|
||||
EmbedFactory embed = EmbedFactory.create()
|
||||
.withTitle("🎉 Повышение уровня!")
|
||||
.withDescription(member.getAsMention() + " достиг **" + newLevel + " уровня**!")
|
||||
.addField("Прогресс", progressBar, false)
|
||||
.addField("Всего XP", String.valueOf(progress.getTotalXP()), true)
|
||||
.addField("До следующего", progress.getCurrentLevelXP() + " / " + progress.getXpForNextLevel() + " XP", true)
|
||||
.withColor(getColorForLevel(newLevel))
|
||||
.withThumbnail(member.getEffectiveAvatarUrl())
|
||||
.withFooter("Продолжай в том же духе!");
|
||||
|
||||
if (rewardRole != null) {
|
||||
embed.addField("🎁 Награда", rewardRole, false);
|
||||
}
|
||||
|
||||
channel.sendMessageEmbeds(embed.build()).queue(
|
||||
success -> logger.info("Отправлено уведомление о level up для {}: {} -> {}",
|
||||
success -> logger.info("Отправлено уведомление о level up для {}: {} -> {}",
|
||||
member.getEffectiveName(), oldLevel, newLevel),
|
||||
error -> logger.error("Ошибка отправки уведомления о level up", error)
|
||||
);
|
||||
|
|
@ -83,17 +84,10 @@ public class LevelUpNotifier {
|
|||
return Color.decode("#2ECC71"); // Зеленый
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить награду за уровень
|
||||
*/
|
||||
private String getRewardForLevel(int level) {
|
||||
return switch (level) {
|
||||
case 5 -> "🎖️ Роль **Активный**";
|
||||
case 10 -> "⭐ Роль **Постоянный**";
|
||||
case 20 -> "💎 Роль **Ветеран**";
|
||||
case 30 -> "👑 Роль **Легенда**";
|
||||
case 50 -> "🏆 Роль **Мастер** + особый цвет ника";
|
||||
default -> null;
|
||||
};
|
||||
private String buildProgressBar(double percentage) {
|
||||
int filled = (int) (percentage / 10);
|
||||
filled = Math.min(filled, 10);
|
||||
int empty = 10 - filled;
|
||||
return "▓".repeat(filled) + "░".repeat(empty) + " " + String.format("%.0f%%", percentage);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,21 +3,26 @@ package creator.loki.feature.level;
|
|||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import creator.loki.core.EventDispatcher;
|
||||
import creator.loki.feature.economy.service.EconomyService;
|
||||
import creator.loki.feature.level.service.LevelService;
|
||||
import creator.loki.feature.level.domain.LevelUpResult;
|
||||
import creator.loki.embed.EmbedTemplates;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@Singleton
|
||||
public class MessageListener extends ListenerAdapter {
|
||||
private final EventDispatcher dispatcher;
|
||||
private final LevelService levelService;
|
||||
private final EconomyService economyService;
|
||||
|
||||
@Inject
|
||||
public MessageListener(EventDispatcher dispatcher, LevelService levelService) {
|
||||
public MessageListener(EventDispatcher dispatcher, LevelService levelService, EconomyService economyService) {
|
||||
this.dispatcher = dispatcher;
|
||||
this.levelService = levelService;
|
||||
this.economyService = economyService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -38,6 +43,9 @@ public class MessageListener extends ListenerAdapter {
|
|||
)
|
||||
).queue();
|
||||
}
|
||||
|
||||
int lcAmount = ThreadLocalRandom.current().nextInt(1, 4);
|
||||
economyService.earnCash(userId, lcAmount);
|
||||
}
|
||||
|
||||
dispatcher.handleMessage(event);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package creator.loki.feature.level;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import creator.loki.feature.economy.service.EconomyService;
|
||||
import creator.loki.feature.level.domain.LevelUpResult;
|
||||
import creator.loki.feature.level.service.LevelService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
|
|
@ -23,12 +24,14 @@ import java.util.concurrent.TimeUnit;
|
|||
public class VoiceTracker extends ListenerAdapter {
|
||||
private static final Logger logger = LoggerFactory.getLogger(VoiceTracker.class);
|
||||
private final LevelService levelService;
|
||||
private final EconomyService economyService;
|
||||
private final Map<String, Long> voiceJoinTimes = new ConcurrentHashMap<>();
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
|
||||
@Inject
|
||||
public VoiceTracker(LevelService levelService) {
|
||||
public VoiceTracker(LevelService levelService, EconomyService economyService) {
|
||||
this.levelService = levelService;
|
||||
this.economyService = economyService;
|
||||
|
||||
// Каждую минуту начисляем XP тем, кто в войсе
|
||||
scheduler.scheduleAtFixedRate(() -> Thread.startVirtualThread(this::updateVoiceTime), 1, 1, TimeUnit.MINUTES);
|
||||
|
|
@ -58,6 +61,7 @@ public class VoiceTracker extends ListenerAdapter {
|
|||
|
||||
if (minutes > 0) {
|
||||
levelService.addVoiceXP(userId, minutes);
|
||||
economyService.earnCash(userId, minutes / 2);
|
||||
logger.debug("Пользователь {} провёл в войсе {} минут", member.getEffectiveName(), minutes);
|
||||
}
|
||||
}
|
||||
|
|
@ -84,6 +88,7 @@ public class VoiceTracker extends ListenerAdapter {
|
|||
if (minutes >= 1) {
|
||||
// Начисляем XP за каждую минуту
|
||||
levelService.addVoiceXP(userId, 1);
|
||||
economyService.earnCash(userId, 1);
|
||||
// Обновляем время входа
|
||||
voiceJoinTimes.put(userId, now);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue