package emu.grasscutter.game.dungeons; import emu.grasscutter.GameConstants; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.ScenePointEntry; import emu.grasscutter.data.excels.dungeon.DungeonData; import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData; import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.SceneType; import emu.grasscutter.game.world.Scene; import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp; import emu.grasscutter.utils.Position; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import java.util.List; import lombok.val; import org.reflections.Reflections; public class DungeonSystem extends BaseGameSystem { private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener(); private final Int2ObjectMap passCondHandlers; public DungeonSystem(GameServer server) { super(server); this.passCondHandlers = new Int2ObjectOpenHashMap<>(); registerHandlers(); } public void registerHandlers() { this.registerHandlers( this.passCondHandlers, "emu.grasscutter.game.dungeons.pass_condition", DungeonBaseHandler.class); } public void registerHandlers(Int2ObjectMap map, String packageName, Class clazz) { Reflections reflections = new Reflections(packageName); var handlerClasses = reflections.getSubTypesOf(clazz); for (var obj : handlerClasses) { this.registerPacketHandler(map, obj); } } public void registerPacketHandler(Int2ObjectMap map, Class handlerClass) { try { DungeonValue opcode = handlerClass.getAnnotation(DungeonValue.class); if (opcode == null || opcode.value() == null) { return; } map.put(opcode.value().ordinal(), handlerClass.getDeclaredConstructor().newInstance()); } catch (Exception e) { e.printStackTrace(); } } public void getEntryInfo(Player player, int pointId) { ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId); if (entry == null) { // Error player.sendPacket(new PacketDungeonEntryInfoRsp()); return; } player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData())); } public boolean triggerCondition( DungeonPassConfigData.DungeonPassCondition condition, int... params) { var handler = passCondHandlers.get(condition.getCondType().ordinal()); if (handler == null) { Grasscutter.getLogger() .debug("Could not trigger condition {} at {}", condition.getCondType(), params); return false; } return handler.execute(condition, params); } public boolean enterDungeon(Player player, int pointId, int dungeonId) { DungeonData data = GameData.getDungeonDataMap().get(dungeonId); if (data == null) { return false; } Grasscutter.getLogger() .info( "{}({}) is trying to enter dungeon {}", player.getNickname(), player.getUid(), dungeonId); int sceneId = data.getSceneId(); var scene = player.getScene(); scene.setPrevScene(sceneId); if (player.getWorld().transferPlayerToScene(player, sceneId, data)) { scene = player.getScene(); scene.addDungeonSettleObserver(basicDungeonSettleObserver); } scene.setPrevScenePoint(pointId); return true; } /** used in tower dungeons handoff */ public boolean handoffDungeon( Player player, int dungeonId, List dungeonSettleListeners) { DungeonData data = GameData.getDungeonDataMap().get(dungeonId); if (data == null) { return false; } Grasscutter.getLogger() .info( "{}({}) is trying to enter tower dungeon {}", player.getNickname(), player.getUid(), dungeonId); if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) { dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver); } return true; } public void exitDungeon(Player player) { Scene scene = player.getScene(); if (scene == null || scene.getSceneType() != SceneType.SCENE_DUNGEON) { return; } // Get previous scene int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3; // Get previous position val dungeonManager = scene.getDungeonManager(); DungeonData dungeonData = dungeonManager != null ? dungeonManager.getDungeonData() : null; Position prevPos = new Position(GameConstants.START_POSITION); if (dungeonData != null) { ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint()); if (entry != null) { prevPos.set(entry.getPointData().getTranPos()); } if (!dungeonManager.isFinishedSuccessfully()) { dungeonManager.quitDungeon(); } dungeonManager.unsetTrialTeam(player); } // clean temp team if it has player.getTeamManager().cleanTemporaryTeam(); player.getTowerManager().clearEntry(); // Transfer player back to world player.getWorld().transferPlayerToScene(player, prevScene, prevPos); } }