Commit ad846355 authored by Melledy's avatar Melledy Committed by GitHub
Browse files

Merge pull request #594 from Akka0/tower

Tower Dungeons Handoff between levels
parents 8abd3ace f2231349
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import emu.grasscutter.utils.Utils;
public class BasicDungeonSettleListener implements DungeonSettleListener {
@Override
public void onDungeonSettle(Scene scene) {
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
scene.broadcastPacket(new PacketDungeonSettleNotify(scene.getChallenge()));
}
}
package emu.grasscutter.game.dungeons; package emu.grasscutter.game.dungeons;
import java.util.ArrayList;
import java.util.List;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.def.DungeonData; import emu.grasscutter.data.def.DungeonData;
import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.game.entity.EntityMonster; import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.SceneMonster;
import emu.grasscutter.scripts.data.ScriptArgs; import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify; import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify; import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify; import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify; import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.ArrayList;
import java.util.List;
public class DungeonChallenge { public class DungeonChallenge {
private final Scene scene; private final Scene scene;
private final SceneGroup group; private final SceneGroup group;
...@@ -40,7 +32,7 @@ public class DungeonChallenge { ...@@ -40,7 +32,7 @@ public class DungeonChallenge {
private int score; private int score;
private int objective = 0; private int objective = 0;
private IntSet rewardedPlayers; private IntSet rewardedPlayers;
public DungeonChallenge(Scene scene, SceneGroup group) { public DungeonChallenge(Scene scene, SceneGroup group) {
this.scene = scene; this.scene = scene;
this.group = group; this.group = group;
...@@ -129,8 +121,7 @@ public class DungeonChallenge { ...@@ -129,8 +121,7 @@ public class DungeonChallenge {
} }
private void settle() { private void settle() {
getScene().setAutoCloseTime(Utils.getCurrentSeconds() + 1000); getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene()));
getScene().broadcastPacket(new PacketDungeonSettleNotify(this));
getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, new ScriptArgs(this.isSuccess() ? 1 : 0)); getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, new ScriptArgs(this.isSuccess() ? 1 : 0));
} }
......
...@@ -14,9 +14,11 @@ import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp; ...@@ -14,9 +14,11 @@ import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp; import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.List;
public class DungeonManager { public class DungeonManager {
private final GameServer server; private final GameServer server;
private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener();
public DungeonManager(GameServer server) { public DungeonManager(GameServer server) {
this.server = server; this.server = server;
} }
...@@ -49,13 +51,32 @@ public class DungeonManager { ...@@ -49,13 +51,32 @@ public class DungeonManager {
int sceneId = data.getSceneId(); int sceneId = data.getSceneId();
player.getScene().setPrevScene(sceneId); player.getScene().setPrevScene(sceneId);
player.getWorld().transferPlayerToScene(player, sceneId, data); if(player.getWorld().transferPlayerToScene(player, sceneId, data)){
player.getScene().addDungeonSettleObserver(basicDungeonSettleObserver);
}
player.getScene().setPrevScenePoint(pointId); player.getScene().setPrevScenePoint(pointId);
player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId)); player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId));
return true; return true;
} }
/**
* used in tower dungeons handoff
*/
public boolean handoffDungeon(Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
if (data == null) {
return false;
}
Grasscutter.getLogger().info(player.getNickname() + " is trying to enter tower dungeon " + dungeonId);
if(player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)){
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
}
return true;
}
public void exitDungeon(Player player) { public void exitDungeon(Player player) {
if (player.getScene().getSceneType() != SceneType.SCENE_DUNGEON) { if (player.getScene().getSceneType() != SceneType.SCENE_DUNGEON) {
return; return;
...@@ -77,6 +98,8 @@ public class DungeonManager { ...@@ -77,6 +98,8 @@ public class DungeonManager {
} }
// clean temp team if it has // clean temp team if it has
player.getTeamManager().cleanTemporaryTeam(); player.getTeamManager().cleanTemporaryTeam();
player.getTowerManager().clearEntry();
// Transfer player back to world // Transfer player back to world
player.getWorld().transferPlayerToScene(player, prevScene, prevPos); player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp)); player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
......
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.world.Scene;
public interface DungeonSettleListener {
void onDungeonSettle(Scene scene);
}
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import emu.grasscutter.server.packet.send.PacketTowerFloorRecordChangeNotify;
import emu.grasscutter.utils.Utils;
public class TowerDungeonSettleListener implements DungeonSettleListener {
@Override
public void onDungeonSettle(Scene scene) {
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
var towerManager = scene.getPlayers().get(0).getTowerManager();
towerManager.notifyCurLevelRecordChangeWhenDone();
scene.broadcastPacket(new PacketTowerFloorRecordChangeNotify(towerManager.getCurrentFloorId()));
scene.broadcastPacket(new PacketDungeonSettleNotify(scene.getChallenge(),
true,
towerManager.hasNextLevel(),
towerManager.getNextFloorId()
));
}
}
...@@ -27,6 +27,7 @@ import emu.grasscutter.game.managers.SotSManager.SotSManager; ...@@ -27,6 +27,7 @@ import emu.grasscutter.game.managers.SotSManager.SotSManager;
import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.EntityType; import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.shop.ShopLimit; import emu.grasscutter.game.shop.ShopLimit;
import emu.grasscutter.game.managers.MapMarkManager.*; import emu.grasscutter.game.managers.MapMarkManager.*;
import emu.grasscutter.game.tower.TowerManager; import emu.grasscutter.game.tower.TowerManager;
...@@ -1083,6 +1084,7 @@ public class Player { ...@@ -1083,6 +1084,7 @@ public class Player {
@PostLoad @PostLoad
private void onLoad() { private void onLoad() {
this.getTeamManager().setPlayer(this); this.getTeamManager().setPlayer(this);
this.getTowerManager().setPlayer(this);
} }
public void save() { public void save() {
...@@ -1152,6 +1154,10 @@ public class Player { ...@@ -1152,6 +1154,10 @@ public class Player {
} }
public void onLogout() { public void onLogout() {
// force to leave the dungeon
if(getScene().getSceneType() == SceneType.SCENE_DUNGEON){
this.getServer().getDungeonManager().exitDungeon(this);
}
// Leave world // Leave world
if (this.getWorld() != null) { if (this.getWorld() != null) {
this.getWorld().removePlayer(this); this.getWorld().removePlayer(this);
......
...@@ -3,40 +3,100 @@ package emu.grasscutter.game.tower; ...@@ -3,40 +3,100 @@ package emu.grasscutter.game.tower;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Transient; import dev.morphia.annotations.Transient;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.def.TowerLevelData;
import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.dungeons.TowerDungeonSettleListener;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketTowerCurLevelRecordChangeNotify;
import emu.grasscutter.server.packet.send.PacketTowerEnterLevelRsp; import emu.grasscutter.server.packet.send.PacketTowerEnterLevelRsp;
import java.util.List; import java.util.List;
@Entity @Entity
public class TowerManager { public class TowerManager {
@Transient private final Player player; @Transient private Player player;
public TowerManager(Player player) { public TowerManager(Player player) {
this.player = player; this.player = player;
} }
public void setPlayer(Player player) {
this.player = player;
}
private int currentFloorId;
private int currentLevel; private int currentLevel;
private int currentFloor; @Transient
private int currentLevelId;
@Transient
private int entryScene;
public int getCurrentFloorId() {
return currentFloorId;
}
private static final List<DungeonSettleListener> towerDungeonSettleListener = List.of(new TowerDungeonSettleListener());
public void teamSelect(int floor, List<List<Long>> towerTeams) { public void teamSelect(int floor, List<List<Long>> towerTeams) {
var floorData = GameData.getTowerFloorDataMap().get(floor); var floorData = GameData.getTowerFloorDataMap().get(floor);
this.currentFloor = floorData.getFloorId(); this.currentFloorId = floorData.getFloorId();
this.currentLevel = floorData.getLevelId(); this.currentLevel = 0;
this.currentLevelId = GameData.getTowerLevelDataMap().values().stream()
.filter(x -> x.getLevelId() == floorData.getLevelId() && x.getLevelIndex() == 1)
.findFirst()
.map(TowerLevelData::getID)
.orElse(0);
if (entryScene == 0){
entryScene = player.getSceneId();
}
player.getTeamManager().setupTemporaryTeam(towerTeams); player.getTeamManager().setupTemporaryTeam(towerTeams);
} }
public void enterLevel(int enterPointId) { public void enterLevel(int enterPointId) {
var levelData = GameData.getTowerLevelDataMap().get(currentLevel); var levelData = GameData.getTowerLevelDataMap().get(currentLevelId + currentLevel);
this.currentLevel++;
var id = levelData.getDungeonId(); var id = levelData.getDungeonId();
notifyCurLevelRecordChange();
// use team user choose // use team user choose
player.getTeamManager().useTemporaryTeam(0); player.getTeamManager().useTemporaryTeam(0);
player.getServer().getDungeonManager() player.getServer().getDungeonManager().handoffDungeon(player, id,
.enterDungeon(player, enterPointId, id); towerDungeonSettleListener);
// make sure user can exit dungeon correctly
player.getScene().setPrevScene(entryScene);
player.getScene().setPrevScenePoint(enterPointId);
player.getSession().send(new PacketTowerEnterLevelRsp(currentFloorId, currentLevel));
}
public void notifyCurLevelRecordChange(){
player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(currentFloorId, currentLevel));
}
public void notifyCurLevelRecordChangeWhenDone(){
player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(currentFloorId, currentLevel + 1));
}
public boolean hasNextLevel(){
return this.currentLevel < 3;
}
public int getNextFloorId() {
if(hasNextLevel()){
return 0;
}
this.currentFloorId++;
return this.currentFloorId;
}
player.getSession().send(new PacketTowerEnterLevelRsp(currentFloor, currentLevel)); public void clearEntry() {
this.entryScene = 0;
} }
} }
package emu.grasscutter.game.world; package emu.grasscutter.game.world;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameDepot; import emu.grasscutter.data.GameDepot;
import emu.grasscutter.data.def.DungeonData; import emu.grasscutter.data.def.DungeonData;
...@@ -8,6 +7,7 @@ import emu.grasscutter.data.def.MonsterData; ...@@ -8,6 +7,7 @@ import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.data.def.SceneData; import emu.grasscutter.data.def.SceneData;
import emu.grasscutter.data.def.WorldLevelData; import emu.grasscutter.data.def.WorldLevelData;
import emu.grasscutter.game.dungeons.DungeonChallenge; import emu.grasscutter.game.dungeons.DungeonChallenge;
import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.entity.*; import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.TeamInfo; import emu.grasscutter.game.player.TeamInfo;
...@@ -20,11 +20,8 @@ import emu.grasscutter.net.packet.BasePacket; ...@@ -20,11 +20,8 @@ import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
import emu.grasscutter.scripts.SceneScriptManager; import emu.grasscutter.scripts.SceneScriptManager;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneBlock; import emu.grasscutter.scripts.data.SceneBlock;
import emu.grasscutter.scripts.data.SceneGadget;
import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketAvatarSkillInfoNotify; import emu.grasscutter.server.packet.send.PacketAvatarSkillInfoNotify;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify; import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
...@@ -56,6 +53,7 @@ public class Scene { ...@@ -56,6 +53,7 @@ public class Scene {
private SceneScriptManager scriptManager; private SceneScriptManager scriptManager;
private DungeonChallenge challenge; private DungeonChallenge challenge;
private List<DungeonSettleListener> dungeonSettleListeners;
private DungeonData dungeonData; private DungeonData dungeonData;
private int prevScene; // Id of the previous scene private int prevScene; // Id of the previous scene
private int prevScenePoint; private int prevScenePoint;
...@@ -205,6 +203,17 @@ public class Scene { ...@@ -205,6 +203,17 @@ public class Scene {
this.challenge = challenge; this.challenge = challenge;
} }
public void addDungeonSettleObserver(DungeonSettleListener dungeonSettleListener){
if(dungeonSettleListeners == null){
dungeonSettleListeners = new ArrayList<>();
}
dungeonSettleListeners.add(dungeonSettleListener);
}
public List<DungeonSettleListener> getDungeonSettleObservers() {
return dungeonSettleListeners;
}
public boolean isInScene(GameEntity entity) { public boolean isInScene(GameEntity entity) {
return this.entities.containsKey(entity.getId()); return this.entities.containsKey(entity.getId());
} }
......
...@@ -207,4 +207,19 @@ public class ScriptLib { ...@@ -207,4 +207,19 @@ public class ScriptLib {
public void PrintContextLog(String msg) { public void PrintContextLog(String msg) {
Grasscutter.getLogger().info("[LUA] " + msg); Grasscutter.getLogger().info("[LUA] " + msg);
} }
public int TowerCountTimeStatus(int var1, int var2){
return 0;
}
public int GetGroupMonsterCount(int var1){
// Maybe...
return GetGroupMonsterCountByGroupId(var1);
}
public int SetMonsterBattleByGroup(int var1, int var2, int var3){
return 0;
}
public int CauseDungeonFail(int var1){
return 0;
}
} }
...@@ -4,6 +4,8 @@ import emu.grasscutter.game.dungeons.DungeonChallenge; ...@@ -4,6 +4,8 @@ import emu.grasscutter.game.dungeons.DungeonChallenge;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass.DungeonSettleNotify; import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass.DungeonSettleNotify;
import emu.grasscutter.net.proto.ItemParamOuterClass;
import emu.grasscutter.net.proto.TowerLevelEndNotifyOuterClass.TowerLevelEndNotify;
public class PacketDungeonSettleNotify extends BasePacket { public class PacketDungeonSettleNotify extends BasePacket {
...@@ -19,4 +21,43 @@ public class PacketDungeonSettleNotify extends BasePacket { ...@@ -19,4 +21,43 @@ public class PacketDungeonSettleNotify extends BasePacket {
this.setData(proto); this.setData(proto);
} }
public PacketDungeonSettleNotify(DungeonChallenge challenge,
boolean canJump,
boolean hasNextLevel,
int nextFloorId
) {
super(PacketOpcodes.DungeonSettleNotify);
var continueStatus = TowerLevelEndNotify.ContinueStateType.CONTINUE_STATE_CAN_NOT_CONTINUE_VALUE;
if(challenge.isSuccess() && canJump){
continueStatus = hasNextLevel ? TowerLevelEndNotify.ContinueStateType.CONTINUE_STATE_CAN_ENTER_NEXT_LEVEL_VALUE
: TowerLevelEndNotify.ContinueStateType.CONTINUE_STATE_CAN_ENTER_NEXT_FLOOR_VALUE;
}
var towerLevelEndNotify = TowerLevelEndNotify.newBuilder()
.setIsSuccess(challenge.isSuccess())
.setContinueState(continueStatus)
.addFinishedStarCondList(1)
.addFinishedStarCondList(2)
.addFinishedStarCondList(3)
.addRewardItemList(ItemParamOuterClass.ItemParam.newBuilder()
.setItemId(201)
.setCount(1000)
.build())
;
if(nextFloorId > 0){
towerLevelEndNotify.setNextFloorId(nextFloorId);
}
DungeonSettleNotify proto = DungeonSettleNotify.newBuilder()
.setDungeonId(challenge.getScene().getDungeonData().getId())
.setIsSuccess(challenge.isSuccess())
.setCloseTime(challenge.getScene().getAutoCloseTime())
.setResult(challenge.isSuccess() ? 1 : 0)
.setTowerLevelEndNotify(towerLevelEndNotify.build())
.build();
this.setData(proto);
}
} }
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.TowerCurLevelRecordChangeNotifyOuterClass.TowerCurLevelRecordChangeNotify;
import emu.grasscutter.net.proto.TowerCurLevelRecordOuterClass.TowerCurLevelRecord;
public class PacketTowerCurLevelRecordChangeNotify extends BasePacket {
public PacketTowerCurLevelRecordChangeNotify(int curFloorId, int curLevelIndex) {
super(PacketOpcodes.TowerCurLevelRecordChangeNotify);
TowerCurLevelRecordChangeNotify proto = TowerCurLevelRecordChangeNotify.newBuilder()
.setCurLevelRecord(TowerCurLevelRecord.newBuilder()
.setCurFloorId(curFloorId)
.setCurLevelIndex(curLevelIndex)
// TODO team info
.build())
.build();
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.TowerFloorRecordChangeNotifyOuterClass.TowerFloorRecordChangeNotify;
import emu.grasscutter.net.proto.TowerFloorRecordOuterClass.TowerFloorRecord;
import emu.grasscutter.net.proto.TowerLevelRecordOuterClass.TowerLevelRecord;
public class PacketTowerFloorRecordChangeNotify extends BasePacket {
public PacketTowerFloorRecordChangeNotify(int floorId) {
super(PacketOpcodes.TowerFloorRecordChangeNotify);
TowerFloorRecordChangeNotify proto = TowerFloorRecordChangeNotify.newBuilder()
.addTowerFloorRecordList(TowerFloorRecord.newBuilder()
.setFloorId(floorId)
.setFloorStarRewardProgress(3)
.addPassedLevelRecordList(TowerLevelRecord.newBuilder()
.setLevelId(1)
.addSatisfiedCondList(1)
.addSatisfiedCondList(2)
.addSatisfiedCondList(3)
.build())
.build())
.setIsFinishedEntranceFloor(true)
.build();
this.setData(proto);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment