Commit 53cc1822 authored by Melledy's avatar Melledy
Browse files

Implement dungeon entry

parent fc9aa8ec
...@@ -61,6 +61,7 @@ public class GameData { ...@@ -61,6 +61,7 @@ public class GameData {
private static final Int2ObjectMap<FetterCharacterCardData> fetterCharacterCardDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<FetterCharacterCardData> fetterCharacterCardDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<RewardData> rewardDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<RewardData> rewardDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<WorldLevelData> worldLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<WorldLevelData> worldLevelDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>();
// Cache // Cache
private static Map<Integer, List<Integer>> fetters = new HashMap<>(); private static Map<Integer, List<Integer>> fetters = new HashMap<>();
...@@ -98,6 +99,11 @@ public class GameData { ...@@ -98,6 +99,11 @@ public class GameData {
return scenePointEntries; return scenePointEntries;
} }
// TODO optimize
public static ScenePointEntry getScenePointEntryById(int sceneId, int pointId) {
return getScenePointEntries().get(sceneId + "_" + pointId);
}
public static Int2ObjectMap<AvatarData> getAvatarDataMap() { public static Int2ObjectMap<AvatarData> getAvatarDataMap() {
return avatarDataMap; return avatarDataMap;
} }
...@@ -265,4 +271,8 @@ public class GameData { ...@@ -265,4 +271,8 @@ public class GameData {
public static Int2ObjectMap<WorldLevelData> getWorldLevelDataMap() { public static Int2ObjectMap<WorldLevelData> getWorldLevelDataMap() {
return worldLevelDataMap; return worldLevelDataMap;
} }
public static Int2ObjectMap<DungeonData> getDungeonDataMap() {
return dungeonDataMap;
}
} }
...@@ -164,6 +164,7 @@ public class ResourceLoader { ...@@ -164,6 +164,7 @@ public class ResourceLoader {
for (Map.Entry<String, JsonElement> entry : config.points.entrySet()) { for (Map.Entry<String, JsonElement> entry : config.points.entrySet()) {
PointData pointData = Grasscutter.getGsonFactory().fromJson(entry.getValue(), PointData.class); PointData pointData = Grasscutter.getGsonFactory().fromJson(entry.getValue(), PointData.class);
pointData.setId(Integer.parseInt(entry.getKey()));
ScenePointEntry sl = new ScenePointEntry(sceneId + "_" + entry.getKey(), pointData); ScenePointEntry sl = new ScenePointEntry(sceneId + "_" + entry.getKey(), pointData);
scenePointList.add(sl); scenePointList.add(sl);
......
package emu.grasscutter.data.common; package emu.grasscutter.data.common;
public class PointData { import emu.grasscutter.utils.Position;
private pos tranPos;
public pos getTranPos() {
return tranPos;
}
public void setTranPos(pos tranPos) {
this.tranPos = tranPos;
}
public class pos { public class PointData {
private float x; private int id;
private float y; private String $type;
private float z; private Position tranPos;
private int[] dungeonIds;
public float getX() {
return x;
}
public void setX(float x) { public int getId() {
this.x = x; return id;
} }
public float getY() { public void setId(int id) {
return y; this.id = id;
} }
public void setY(float y) { public String getType() {
this.y = y; return $type;
} }
public float getZ() { public Position getTranPos() {
return z; return tranPos;
} }
public void setZ(float z) { public int[] getDungeonIds() {
this.z = z; return dungeonIds;
}
} }
} }
package emu.grasscutter.data.def;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.SceneType;
@ResourceType(name = "DungeonExcelConfigData.json")
public class DungeonData extends GameResource {
private int Id;
private int SceneId;
private String InvolveType; // TODO enum
@Override
public int getId() {
return this.Id;
}
public int getSceneId() {
return SceneId;
}
@Override
public void onLoad() {
}
}
...@@ -9,16 +9,17 @@ import emu.grasscutter.game.props.SceneType; ...@@ -9,16 +9,17 @@ import emu.grasscutter.game.props.SceneType;
@ResourceType(name = "SceneExcelConfigData.json") @ResourceType(name = "SceneExcelConfigData.json")
public class SceneData extends GameResource { public class SceneData extends GameResource {
private int Id; private int Id;
private SceneType SceneType; private SceneType Type;
private String ScriptData; private String ScriptData;
@Override @Override
public int getId() { public int getId() {
return this.Id; return this.Id;
} }
public SceneType getSceneType() { public SceneType getSceneType() {
return SceneType; return Type;
} }
public String getScriptData() { public String getScriptData() {
......
package emu.grasscutter.game.dungeons; package emu.grasscutter.game.dungeons;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.custom.ScenePointEntry;
import emu.grasscutter.data.def.DungeonData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp;
import emu.grasscutter.utils.Position;
public class DungeonManager { public class DungeonManager {
private final GameServer server; private final GameServer server;
...@@ -12,4 +24,55 @@ public class DungeonManager { ...@@ -12,4 +24,55 @@ public class DungeonManager {
public GameServer getServer() { public GameServer getServer() {
return server; return server;
} }
public void getEntryInfo(Player player, int pointId) {
ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
if (entry == null || entry.getPointData().getDungeonIds() == null) {
// Error
player.sendPacket(new PacketDungeonEntryInfoRsp());
return;
}
player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData()));
}
public void enterDungeon(Player player, int pointId, int dungeonId) {
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
if (data == null) {
return;
}
int sceneId = data.getSceneId();
player.getWorld().transferPlayerToScene(player, sceneId, data);
player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId));
}
public void exitDungeon(Player player) {
if (player.getScene().getSceneType() != SceneType.SCENE_DUNGEON) {
return;
}
// Get previous scene
int prevScene = player.getScene().getPrevScene() > 0 ? player.getScene().getPrevScene() : 3;
// Get previous position
DungeonData dungeonData = player.getScene().getDungeonData();
Position prevPos = new Position(GameConstants.START_POSITION);
if (dungeonData != null) {
ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, dungeonData.getId());
if (entry != null) {
prevPos.set(entry.getPointData().getTranPos());
}
}
// Transfer player back to world
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
}
} }
...@@ -3,6 +3,7 @@ package emu.grasscutter.game.world; ...@@ -3,6 +3,7 @@ package emu.grasscutter.game.world;
import emu.grasscutter.Grasscutter; 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.MonsterData; 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;
...@@ -42,6 +43,9 @@ public class Scene { ...@@ -42,6 +43,9 @@ public class Scene {
private ClimateType climate; private ClimateType climate;
private int weather; private int weather;
private DungeonData dungeonData;
private int prevScene; // Id of the previous scene
public Scene(World world, SceneData sceneData) { public Scene(World world, SceneData sceneData) {
this.world = world; this.world = world;
this.sceneData = sceneData; this.sceneData = sceneData;
...@@ -50,6 +54,7 @@ public class Scene { ...@@ -50,6 +54,7 @@ public class Scene {
this.time = 8 * 60; this.time = 8 * 60;
this.climate = ClimateType.CLIMATE_SUNNY; this.climate = ClimateType.CLIMATE_SUNNY;
this.prevScene = 3;
this.spawnedEntities = new HashSet<>(); this.spawnedEntities = new HashSet<>();
this.deadSpawnedEntities = new HashSet<>(); this.deadSpawnedEntities = new HashSet<>();
...@@ -111,6 +116,14 @@ public class Scene { ...@@ -111,6 +116,14 @@ public class Scene {
this.weather = weather; this.weather = weather;
} }
public int getPrevScene() {
return prevScene;
}
public void setPrevScene(int prevScene) {
this.prevScene = prevScene;
}
public boolean dontDestroyWhenEmpty() { public boolean dontDestroyWhenEmpty() {
return dontDestroyWhenEmpty; return dontDestroyWhenEmpty;
} }
...@@ -127,6 +140,17 @@ public class Scene { ...@@ -127,6 +140,17 @@ public class Scene {
return deadSpawnedEntities; return deadSpawnedEntities;
} }
public DungeonData getDungeonData() {
return dungeonData;
}
public void setDungeonData(DungeonData dungeonData) {
if (this.dungeonData != null || this.getSceneType() != SceneType.SCENE_DUNGEON || dungeonData.getSceneId() != this.getId()) {
return;
}
this.dungeonData = dungeonData;
}
public boolean isInScene(GameEntity entity) { public boolean isInScene(GameEntity entity) {
return this.entities.containsKey(entity.getId()); return this.entities.containsKey(entity.getId());
} }
......
...@@ -17,6 +17,7 @@ import emu.grasscutter.game.props.EntityIdType; ...@@ -17,6 +17,7 @@ import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.LifeState; import emu.grasscutter.game.props.LifeState;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.def.DungeonData;
import emu.grasscutter.data.def.SceneData; import emu.grasscutter.data.def.SceneData;
import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.entity.EntityClientGadget; import emu.grasscutter.game.entity.EntityClientGadget;
...@@ -212,6 +213,14 @@ public class World implements Iterable<Player> { ...@@ -212,6 +213,14 @@ public class World implements Iterable<Player> {
} }
public boolean transferPlayerToScene(Player player, int sceneId, Position pos) { public boolean transferPlayerToScene(Player player, int sceneId, Position pos) {
return transferPlayerToScene(player, sceneId, null, pos);
}
public boolean transferPlayerToScene(Player player, int sceneId, DungeonData data) {
return transferPlayerToScene(player, sceneId, data, null);
}
public boolean transferPlayerToScene(Player player, int sceneId, DungeonData dungeonData, Position pos) {
if (GameData.getSceneDataMap().get(sceneId) == null) { if (GameData.getSceneDataMap().get(sceneId) == null) {
return false; return false;
} }
...@@ -230,19 +239,39 @@ public class World implements Iterable<Player> { ...@@ -230,19 +239,39 @@ public class World implements Iterable<Player> {
} }
Scene newScene = this.getSceneById(sceneId); Scene newScene = this.getSceneById(sceneId);
newScene.setDungeonData(dungeonData);
newScene.addPlayer(player); newScene.addPlayer(player);
// Dungeon
if (dungeonData != null) {
// TODO set position
}
// Set player position
if (pos != null) {
player.getPos().set(pos); player.getPos().set(pos);
} else {
pos = player.getPos();
}
if (oldScene != null) { if (oldScene != null) {
newScene.setPrevScene(oldScene.getId());
oldScene.setDontDestroyWhenEmpty(false); oldScene.setDontDestroyWhenEmpty(false);
} }
// Teleport packet // Get enter types
if (oldScene == newScene) { EnterType enterType = EnterType.ENTER_JUMP;
player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_GOTO, EnterReason.TransPoint, sceneId, pos)); EnterReason enterReason = EnterReason.TransPoint;
} else {
player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_JUMP, EnterReason.TransPoint, sceneId, pos)); if (dungeonData != null) {
enterType = EnterType.ENTER_DUNGEON;
enterReason = EnterReason.DungeonEnter;
} else if (oldScene == newScene) {
enterType = EnterType.ENTER_GOTO;
} }
// Teleport packet
player.sendPacket(new PacketPlayerEnterSceneNotify(player, enterType, enterReason, sceneId, pos));
return true; return true;
} }
......
...@@ -2,6 +2,7 @@ package emu.grasscutter.server.packet.recv; ...@@ -2,6 +2,7 @@ package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DungeonEntryInfoReqOuterClass.DungeonEntryInfoReq;
import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
...@@ -10,7 +11,9 @@ public class HandlerDungeonEntryInfoReq extends PacketHandler { ...@@ -10,7 +11,9 @@ public class HandlerDungeonEntryInfoReq extends PacketHandler {
@Override @Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
DungeonEntryInfoReq req = DungeonEntryInfoReq.parseFrom(payload);
session.getServer().getDungeonManager().getEntryInfo(session.getPlayer(), req.getPointId());
} }
} }
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PlayerEnterDungeonReqOuterClass.PlayerEnterDungeonReq;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.PlayerEnterDungeonReq)
public class HandlerPlayerEnterDungeonReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
// Auto template
PlayerEnterDungeonReq req = PlayerEnterDungeonReq.parseFrom(payload);
session.getServer().getDungeonManager().enterDungeon(session.getPlayer(), req.getPointId(), req.getDungeonId());
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.PlayerQuitDungeonReq)
public class HandlerPlayerQuitDungeonReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
session.getPlayer().getServer().getDungeonManager().exitDungeon(session.getPlayer());
}
}
package emu.grasscutter.server.packet.send;
import java.util.Arrays;
import emu.grasscutter.data.common.PointData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DungeonEntryInfoOuterClass.DungeonEntryInfo;
import emu.grasscutter.net.proto.DungeonEntryInfoRspOuterClass.DungeonEntryInfoRsp;
public class PacketDungeonEntryInfoRsp extends BasePacket {
public PacketDungeonEntryInfoRsp(Player player, PointData pointData) {
super(PacketOpcodes.DungeonEntryInfoRsp);
DungeonEntryInfoRsp.Builder proto = DungeonEntryInfoRsp.newBuilder()
.setPointId(pointData.getId());
for (int dungeonId : pointData.getDungeonIds()) {
DungeonEntryInfo info = DungeonEntryInfo.newBuilder().setDungeonId(dungeonId).build();
proto.addDungeonEntryList(info);
}
this.setData(proto);
}
public PacketDungeonEntryInfoRsp() {
super(PacketOpcodes.DungeonEntryInfoRsp);
DungeonEntryInfoRsp proto = DungeonEntryInfoRsp.newBuilder()
.setRetcode(1)
.build();
this.setData(proto);
}
}
...@@ -7,7 +7,5 @@ public class PacketPathfindingEnterSceneRsp extends BasePacket { ...@@ -7,7 +7,5 @@ public class PacketPathfindingEnterSceneRsp extends BasePacket {
public PacketPathfindingEnterSceneRsp(int clientSequence) { public PacketPathfindingEnterSceneRsp(int clientSequence) {
super(PacketOpcodes.PathfindingEnterSceneRsp); super(PacketOpcodes.PathfindingEnterSceneRsp);
this.buildHeader(clientSequence);
} }
} }
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PlayerEnterDungeonRspOuterClass.PlayerEnterDungeonRsp;
public class PacketPlayerEnterDungeonRsp extends BasePacket {
public PacketPlayerEnterDungeonRsp(int pointId, int dungeonId) {
super(PacketOpcodes.PlayerEnterDungeonRsp);
PlayerEnterDungeonRsp proto = PlayerEnterDungeonRsp.newBuilder()
.setPointId(pointId)
.setDungeonId(dungeonId)
.build();
this.setData(proto);
}
}
...@@ -65,6 +65,7 @@ public final class Utils { ...@@ -65,6 +65,7 @@ public final class Utils {
private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray(); private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();
public static String bytesToHex(byte[] bytes) { public static String bytesToHex(byte[] bytes) {
if (bytes == null) return "";
char[] hexChars = new char[bytes.length * 2]; char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) { for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF; int v = bytes[j] & 0xFF;
......
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