diff --git a/src/main/java/com/alterdekim/javabot/Constants.java b/src/main/java/com/alterdekim/javabot/Constants.java index 7d4b5c5..f785276 100644 --- a/src/main/java/com/alterdekim/javabot/Constants.java +++ b/src/main/java/com/alterdekim/javabot/Constants.java @@ -1,6 +1,7 @@ package com.alterdekim.javabot; public interface Constants { + String SCRIPT_MESSAGE = "Вам доступны карты действий:\n"; String REMOVE_PLAYER = "Игрок %s покидает бункер."; String ENDVOTE = "Голосование окончено."; String DRAW = "Ничья. Никто не уходит из игры."; @@ -35,6 +36,7 @@ public interface Constants { String LUGG_MESSAGE = "%s - багаж: %s (%s)"; String DAY_MESSAGE_UPPER = "Следующий раунд начался!\nВероятность выжить \uD83D\uDCC8: %d%% (увеличилась на %f%%)"; String PRESSED_NIGHT = "%s нажал(а)"; + String PRESSED_SCRIPT_NIGHT = "%s использовал(а) карту действий"; String DAY_MESSAGE_DOWN = "Следующий раунд начался!\nВероятность выжить \uD83D\uDCC9: %d%% (уменьшилась на %f%%)"; String DAY_MESSAGE = "Следующий раунд начался!\nВероятность выжить: %f%%"; String END_GAME = "Конец игры.\nВероятность выжить: %f%%"; diff --git a/src/main/java/com/alterdekim/javabot/bot/Player.java b/src/main/java/com/alterdekim/javabot/bot/Player.java index c567aea..da00e94 100644 --- a/src/main/java/com/alterdekim/javabot/bot/Player.java +++ b/src/main/java/com/alterdekim/javabot/bot/Player.java @@ -5,6 +5,8 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; +import java.util.List; + @Getter @Setter @AllArgsConstructor @@ -20,6 +22,8 @@ public class Player { private String firstName; private InfoSections infoSections; private Boolean isVoted = false; + private List scripts; + private Integer scriptMessageId; public Player(Long telegramId, String name) { this.telegramId = telegramId; diff --git a/src/main/java/com/alterdekim/javabot/components/BunkerBot.java b/src/main/java/com/alterdekim/javabot/components/BunkerBot.java index f28c7fb..703c34a 100644 --- a/src/main/java/com/alterdekim/javabot/components/BunkerBot.java +++ b/src/main/java/com/alterdekim/javabot/components/BunkerBot.java @@ -9,8 +9,12 @@ import com.alterdekim.javabot.service.*; import com.alterdekim.javabot.util.BotUtils; import com.alterdekim.javabot.util.GameState; import com.alterdekim.javabot.util.HashUtils; +import com.alterdekim.javabot.util.LuaSerializer; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; +import org.luaj.vm2.Globals; +import org.luaj.vm2.LuaValue; +import org.luaj.vm2.lib.jse.JsePlatform; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.telegram.telegrambots.bots.TelegramLongPollingBot; @@ -27,10 +31,12 @@ import org.telegram.telegrambots.meta.api.objects.User; import org.telegram.telegrambots.meta.api.objects.chatmember.ChatMember; import org.telegram.telegrambots.meta.exceptions.TelegramApiException; +import javax.swing.*; import java.io.Serializable; import java.util.*; import java.util.concurrent.*; import java.util.stream.Collectors; +import java.util.stream.IntStream; @Component @Slf4j @@ -52,6 +58,7 @@ public class BunkerBot extends TelegramLongPollingBot { private final TextDataValService textDataValService; private final DisasterService disasterService; private final SynergyService synergyService; + private final ActionScriptsServiceImpl scriptsService; private final Random random; @@ -68,7 +75,8 @@ public class BunkerBot extends TelegramLongPollingBot { WorkService workService, TextDataValService textDataValService, DisasterService disasterService, - SynergyService synergyService) { + SynergyService synergyService, + ActionScriptsServiceImpl scriptsService) { this.telegramConfig = telegramConfig; this.players = new ArrayList<>(); this.gameState = GameState.NONE; @@ -80,12 +88,13 @@ public class BunkerBot extends TelegramLongPollingBot { this.textDataValService = textDataValService; this.disasterService = disasterService; this.synergyService = synergyService; + this.scriptsService = scriptsService; this.random = new Random(); this.dayNightFields = new DayNightFields(); this.linkedQueue = new ConcurrentLinkedQueue<>(); } - @Scheduled(fixedRate = 100) + @Scheduled(fixedRate = 150) private void executeApi() { if( !this.linkedQueue.isEmpty() ) sendApiMethodAsync(this.linkedQueue.poll()); @@ -183,6 +192,7 @@ public class BunkerBot extends TelegramLongPollingBot { List luggs = luggageService.getAllLuggages(); List hobbies = hobbyService.getAllHobbies(); List healths = healthService.getAllHealth(); + List scripts = scriptsService.getAllActionScripts(); for( Player p : players ) { p.setAge(random.nextInt(57)+18); p.setGender((Bio) BotUtils.getRandomFromList(bios, random)); @@ -190,7 +200,11 @@ public class BunkerBot extends TelegramLongPollingBot { p.setLuggage((Luggage) BotUtils.getRandomFromList(luggs, random)); p.setHobby((Hobby) BotUtils.getRandomFromList(hobbies, random)); p.setHealth((Health) BotUtils.getRandomFromList(healths, random)); - + if( random.nextBoolean() ) { + p.setScripts(Arrays.asList((ActionScript) BotUtils.getRandomFromList(scripts, random))); + } else { + p.setScripts(new ArrayList<>()); + } SendMessage sendMessage = new SendMessage(p.getTelegramId()+"", BotAccountProfileGenerator.build(textDataValService, p)); sendApi(sendMessage); } @@ -206,13 +220,49 @@ public class BunkerBot extends TelegramLongPollingBot { SendMessage sendMessage = new SendMessage(p.getTelegramId()+"", Constants.SHOW_TIME); sendMessage.setReplyMarkup(BotUtils.getShowKeyboard(p.getInfoSections())); sendApi(sendMessage); + sendMessage = new SendMessage(p.getTelegramId()+"", Constants.SCRIPT_MESSAGE); + sendMessage.setReplyMarkup(BotUtils.getScriptKeyboard(p.getScripts(), textDataValService)); + try { + setScriptMessageId(p, sendApiMethod(sendMessage).getMessageId()); + } catch (Exception e) { + log.error(e.getMessage(), e); + } } } + private void setScriptMessageId(Player p, Integer messageId) { + IntStream.range(0, players.size()).forEach(i -> { + if( players.get(i).getTelegramId().longValue() == p.getTelegramId().longValue() ) { + players.get(i).setScriptMessageId(messageId); + } + }); + } + private String getStringById(Long id) { return textDataValService.getTextDataValById(id).getText(); } + private void processNightScriptButton(Player p, CallbackQuery callbackQuery, String data) { + ActionScript script = p.getScripts().stream() + .filter(s -> textDataValService.getTextDataValById(s.getTextNameId()).getText().equals(data)) + .findFirst() + .orElse(null); + if( script == null ) return; + sendApi(new DeleteMessage(callbackQuery.getMessage().getChatId()+"", p.getScriptMessageId())); + sendApi(new SendMessage(groupId, String.format(Constants.PRESSED_SCRIPT_NIGHT, callbackQuery.getFrom().getFirstName()))); + sendApi(new SendMessage(callbackQuery.getMessage().getChatId()+"", Constants.THANK_YOU)); + p.getScripts().removeIf(s -> s.getId().longValue() == script.getId().longValue()); + executeLuaScript(script, p); + } + + private void executeLuaScript(ActionScript script, Player p) { + Globals globals = JsePlatform.standardGlobals(); + globals.set("players", LuaSerializer.serializeObjectList(players)); + globals.set("player", LuaSerializer.serializeObject(p)); + LuaValue chunk = globals.load(script.getScriptBody()); + chunk.call(); + } + private void processNightButton(CallbackQuery callbackQuery) { if( this.hasPlayerWithId(callbackQuery.getFrom().getId()) && !getPlayerById(callbackQuery.getFrom().getId()).getIsAnswered() ) { @@ -254,11 +304,15 @@ public class BunkerBot extends TelegramLongPollingBot { getStringById(p.getWork().getTextDescId())) + "\n"); ins.setIsWorkShowed(true); break; + default: + processNightScriptButton(p, callbackQuery, new String(HashUtils.decodeHexString(callbackQuery.getData()))); + return; } setIsAnswered(callbackQuery.getFrom().getId()); updateInfoSections(p, ins); sendApi(new SendMessage(callbackQuery.getMessage().getChatId()+"", Constants.THANK_YOU)); sendApi(new DeleteMessage(callbackQuery.getMessage().getChatId()+"", callbackQuery.getMessage().getMessageId())); + sendApi(new DeleteMessage(callbackQuery.getMessage().getChatId()+"", p.getScriptMessageId())); sendApi(new SendMessage(groupId, String.format(Constants.PRESSED_NIGHT, callbackQuery.getFrom().getFirstName()))); if( isAllAnswered() ) doDay(); } diff --git a/src/main/java/com/alterdekim/javabot/util/BotUtils.java b/src/main/java/com/alterdekim/javabot/util/BotUtils.java index 133f324..6978275 100644 --- a/src/main/java/com/alterdekim/javabot/util/BotUtils.java +++ b/src/main/java/com/alterdekim/javabot/util/BotUtils.java @@ -2,10 +2,14 @@ package com.alterdekim.javabot.util; import com.alterdekim.javabot.Constants; import com.alterdekim.javabot.bot.InfoSections; +import com.alterdekim.javabot.entities.ActionScript; +import com.alterdekim.javabot.service.TextDataValService; +import com.alterdekim.javabot.service.TextDataValServiceImpl; import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup; import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton; import java.util.*; +import java.util.stream.Collectors; public class BotUtils { public static InlineKeyboardMarkup getJoinKeyboard() { @@ -70,6 +74,18 @@ public class BotUtils { return inlineKeyboardMarkup; } + public static InlineKeyboardMarkup getScriptKeyboard(List scripts, TextDataValService textDataValService) { + InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup(); + inlineKeyboardMarkup.setKeyboard(scripts.stream() + .map(s -> { + InlineKeyboardButton inlineKeyboardButton = new InlineKeyboardButton(); + inlineKeyboardButton.setText(textDataValService.getTextDataValById(s.getTextNameId()).getText()); + inlineKeyboardButton.setCallbackData(HashUtils.bytesToHex(textDataValService.getTextDataValById(s.getTextNameId()).getText().getBytes())); + return Collections.singletonList(inlineKeyboardButton); + }).collect(Collectors.toList())); + return inlineKeyboardMarkup; + } + public static InlineKeyboardMarkup getGameTypeKeyboard() { InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup(); List> columns = new ArrayList<>(); diff --git a/src/main/java/com/alterdekim/javabot/util/LuaSerializer.java b/src/main/java/com/alterdekim/javabot/util/LuaSerializer.java new file mode 100644 index 0000000..055557a --- /dev/null +++ b/src/main/java/com/alterdekim/javabot/util/LuaSerializer.java @@ -0,0 +1,90 @@ +package com.alterdekim.javabot.util; + +import com.alterdekim.javabot.bot.Player; +import com.alterdekim.javabot.entities.Bio; +import lombok.extern.slf4j.Slf4j; +import org.luaj.vm2.LuaTable; +import org.luaj.vm2.LuaValue; +import org.luaj.vm2.lib.jse.CoerceJavaToLua; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +public class LuaSerializer { + + public static LuaTable serializeObjectList(List list) { + LuaTable table = new LuaTable(); + list.forEach(o -> table.set(table.length() + 1, serializeObject(o))); + return table; + } + + public static LuaValue serializeObject(Object o) { + Map map = new HashMap<>(); + getPrivateFields(o.getClass()).stream() + .forEach(f -> { + try { + f.setAccessible(true); + String type_name = ((Class) f.getType()).getName(); + String name = f.getName(); + switch (type_name) { + case "java.lang.Long": + map.put(name, ((Long) f.get(o)).longValue()); + break; + case "long": + map.put(name, f.getLong(o)); + break; + case "int": + map.put(name, f.getInt(o)); + break; + case "java.lang.Integer": + map.put(name, ((Integer) f.get(o)).intValue()); + break; + case "boolean": + map.put(name, f.getBoolean(o)); + break; + case "java.lang.Boolean": + map.put(name, ((Boolean) f.get(o)).booleanValue()); + break; + case "java.lang.String": + map.put(name, (String) f.get(o)); + break; + default: + map.put(name, serializeObject(f.get(o))); + break; + } + } catch (Exception e) { + //log.error(e.getMessage(), e); + } + }); + return convert(map); + } + + private static LuaValue convert(Map map) { + LuaTable luaTable = new LuaTable(); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + + // Convert Java object to LuaValue (handle different data types) + LuaValue luaValue = CoerceJavaToLua.coerce(value); + luaTable.set(key, luaValue); + } + return luaTable; + } + + private static List getPrivateFields(Class theClass) { + List privateFields = new ArrayList(); + Field[] fields = theClass.getDeclaredFields(); + for(Field field : fields){ + if(Modifier.isPrivate(field.getModifiers())) { + privateFields.add(field); + } + } + return privateFields; + } +}