mirror of
https://github.com/Melledy/LunarCore.git
synced 2025-12-14 14:24:37 +01:00
Rewrite how scenes load entities to support spawning the correct rogue monsters
This commit is contained in:
@@ -37,6 +37,7 @@ public class GameData {
|
||||
@Getter private static Int2ObjectMap<RogueAreaExcel> rogueAreaExcelMap = new Int2ObjectOpenHashMap<>();
|
||||
@Getter private static Int2ObjectMap<RogueManagerExcel> rogueManagerExcelMap = new Int2ObjectOpenHashMap<>();
|
||||
@Getter private static Int2ObjectMap<RogueRoomExcel> rogueRoomExcelMap = new Int2ObjectOpenHashMap<>();
|
||||
@Getter private static Int2ObjectMap<RogueMonsterExcel> rogueMonsterExcelMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
private static Int2ObjectMap<AvatarPromotionExcel> avatarPromotionExcelMap = new Int2ObjectOpenHashMap<>();
|
||||
private static Int2ObjectMap<AvatarSkillTreeExcel> avatarSkillTreeExcelMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package emu.lunarcore.data.excel;
|
||||
|
||||
import emu.lunarcore.data.GameResource;
|
||||
import emu.lunarcore.data.ResourceType;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = {"RogueMonster.json"})
|
||||
public class RogueMonsterExcel extends GameResource {
|
||||
private int RogueMonsterID;
|
||||
private int NpcMonsterID;
|
||||
private int EventID;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return RogueMonsterID;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
package emu.lunarcore.data.excel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import emu.lunarcore.data.GameResource;
|
||||
import emu.lunarcore.data.ResourceType;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@@ -14,11 +12,15 @@ public class RogueRoomExcel extends GameResource {
|
||||
private int RogueRoomType;
|
||||
private int MapEntrance;
|
||||
private int GroupID;
|
||||
private Map<Integer, Integer> GroupWithContent;
|
||||
private Int2IntOpenHashMap GroupWithContent;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return RogueRoomID;
|
||||
}
|
||||
|
||||
public int getGroupContent(int id) {
|
||||
return GroupWithContent.get(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package emu.lunarcore.game.enums;
|
||||
|
||||
import emu.lunarcore.game.rogue.RogueEntityLoader;
|
||||
import emu.lunarcore.game.scene.SceneEntityLoader;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@@ -9,14 +11,20 @@ public enum PlaneType {
|
||||
Maze (2),
|
||||
Train (3),
|
||||
Challenge (4),
|
||||
Rogue (5),
|
||||
Rogue (5, new RogueEntityLoader()),
|
||||
Raid (6),
|
||||
AetherDivide (7),
|
||||
TrialActivity (8);
|
||||
|
||||
private final int val;
|
||||
private final SceneEntityLoader sceneEntityLoader;
|
||||
|
||||
private PlaneType(int value) {
|
||||
this(value, new SceneEntityLoader());
|
||||
}
|
||||
|
||||
private PlaneType(int value, SceneEntityLoader entityLoader) {
|
||||
this.val = value;
|
||||
this.sceneEntityLoader = entityLoader;
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,8 @@ public class RogueData {
|
||||
return this.rooms.get(this.getCurrentSiteId());
|
||||
}
|
||||
|
||||
// Serialization
|
||||
|
||||
public RogueCurrentInfo toProto() {
|
||||
var proto = RogueCurrentInfo.newInstance()
|
||||
.setStatus(this.getStatus())
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package emu.lunarcore.game.rogue;
|
||||
|
||||
import emu.lunarcore.data.GameData;
|
||||
import emu.lunarcore.data.config.GroupInfo;
|
||||
import emu.lunarcore.data.config.MonsterInfo;
|
||||
import emu.lunarcore.data.excel.NpcMonsterExcel;
|
||||
import emu.lunarcore.data.excel.RogueMonsterExcel;
|
||||
import emu.lunarcore.game.scene.Scene;
|
||||
import emu.lunarcore.game.scene.SceneEntityLoader;
|
||||
import emu.lunarcore.game.scene.entity.EntityMonster;
|
||||
|
||||
public class RogueEntityLoader extends SceneEntityLoader {
|
||||
|
||||
public EntityMonster loadMonster(Scene scene, GroupInfo group, MonsterInfo monsterInfo) {
|
||||
// Make sure player is in a rogue instance
|
||||
RogueData rogue = scene.getPlayer().getRogueData();
|
||||
if (rogue == null) return null;
|
||||
|
||||
// Get rogue group content
|
||||
int content = rogue.getCurrentRoom().getExcel().getGroupContent(group.getId());
|
||||
if (content <= 0) return null;
|
||||
|
||||
// Get rogue monster excel and npc monster excel
|
||||
RogueMonsterExcel rogueMonster = GameData.getRogueMonsterExcelMap().get((content * 10) + 1);
|
||||
if (rogueMonster == null) return null;
|
||||
|
||||
NpcMonsterExcel npcMonster = GameData.getNpcMonsterExcelMap().get(rogueMonster.getNpcMonsterID());
|
||||
if (npcMonster == null) return null;
|
||||
|
||||
// Actually create the monster now
|
||||
EntityMonster monster = new EntityMonster(scene, npcMonster, monsterInfo.getPos());
|
||||
monster.getRot().set(monsterInfo.getRot());
|
||||
monster.setGroupId(group.getId());
|
||||
monster.setInstId(monsterInfo.getID());
|
||||
monster.setEventId(rogueMonster.getEventID());
|
||||
monster.setOverrideStageId(rogueMonster.getEventID());
|
||||
|
||||
return monster;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,12 @@ public class RogueManager extends BasePlayerManager {
|
||||
}
|
||||
|
||||
public void startRogue(int areaId, RepeatedInt avatarIdList) {
|
||||
// Make sure player already isnt in a rogue instance
|
||||
if (getPlayer().getRogueData() != null) {
|
||||
getPlayer().sendPacket(new PacketStartRogueScRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
// Get excel
|
||||
var excel = GameData.getRogueAreaExcelMap().get(areaId);
|
||||
if (excel == null || !excel.isValid()) {
|
||||
@@ -73,11 +79,11 @@ public class RogueManager extends BasePlayerManager {
|
||||
return;
|
||||
}
|
||||
|
||||
// Load scene groups
|
||||
// Set rogue data
|
||||
getPlayer().setRogueData(data);
|
||||
|
||||
// Get room excel
|
||||
RogueRoomExcel roomExcel = data.getCurrentRoom().getExcel();
|
||||
for (var entry : roomExcel.getGroupWithContent().entrySet()) {
|
||||
getPlayer().getScene().loadGroup(entry.getKey());
|
||||
}
|
||||
|
||||
// Move player to rogue start position
|
||||
AnchorInfo anchor = getPlayer().getScene().getFloorInfo().getAnchorInfo(roomExcel.getGroupID(), 1);
|
||||
@@ -86,8 +92,12 @@ public class RogueManager extends BasePlayerManager {
|
||||
getPlayer().getRot().set(anchor.getRot());
|
||||
}
|
||||
|
||||
// Set rogue data and send packet
|
||||
getPlayer().setRogueData(data);
|
||||
// Load scene groups. THIS NEEDS TO BE LAST
|
||||
for (int key : roomExcel.getGroupWithContent().keySet()) {
|
||||
getPlayer().getScene().loadGroup(key);
|
||||
}
|
||||
|
||||
// Done
|
||||
getPlayer().sendPacket(new PacketStartRogueScRsp(getPlayer()));
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,8 @@ import emu.lunarcore.data.GameData;
|
||||
import emu.lunarcore.data.config.*;
|
||||
import emu.lunarcore.data.config.GroupInfo.GroupLoadSide;
|
||||
import emu.lunarcore.data.excel.MazePlaneExcel;
|
||||
import emu.lunarcore.data.excel.NpcMonsterExcel;
|
||||
import emu.lunarcore.data.excel.PropExcel;
|
||||
import emu.lunarcore.game.avatar.GameAvatar;
|
||||
import emu.lunarcore.game.enums.PlaneType;
|
||||
import emu.lunarcore.game.enums.PropState;
|
||||
import emu.lunarcore.game.enums.PropType;
|
||||
import emu.lunarcore.game.player.PlayerLineup;
|
||||
import emu.lunarcore.game.scene.entity.*;
|
||||
import emu.lunarcore.game.scene.triggers.PropTrigger;
|
||||
@@ -23,6 +19,7 @@ import emu.lunarcore.proto.SceneGroupStateOuterClass.SceneGroupState;
|
||||
import emu.lunarcore.proto.SceneInfoOuterClass.SceneInfo;
|
||||
import emu.lunarcore.server.packet.send.PacketActivateFarmElementScRsp;
|
||||
import emu.lunarcore.server.packet.send.PacketSceneGroupRefreshScNotify;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.*;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import lombok.Getter;
|
||||
@@ -32,6 +29,7 @@ public class Scene {
|
||||
private final Player player;
|
||||
private final MazePlaneExcel excel;
|
||||
private final FloorInfo floorInfo;
|
||||
private final SceneEntityLoader entityLoader;
|
||||
private final int planeId;
|
||||
private final int floorId;
|
||||
private int entryId;
|
||||
@@ -66,6 +64,10 @@ public class Scene {
|
||||
this.healingSprings = new ObjectArrayList<>();
|
||||
this.triggers = new ObjectArrayList<>();
|
||||
|
||||
// Use singleton to avoid allocating memory for a new entity loader everytime we create a scene
|
||||
this.entityLoader = getExcel().getPlaneType().getSceneEntityLoader();
|
||||
|
||||
// Add avatar entities
|
||||
PlayerLineup lineup = getPlayer().getCurrentLineup();
|
||||
|
||||
for (int avatarId : lineup.getAvatars()) {
|
||||
@@ -115,97 +117,36 @@ public class Scene {
|
||||
// Add monsters
|
||||
if (group.getMonsterList() != null && group.getMonsterList().size() > 0) {
|
||||
for (MonsterInfo monsterInfo : group.getMonsterList()) {
|
||||
// Don't spawn entity if they have the IsDelete flag in group info
|
||||
if (monsterInfo.isIsDelete()) continue;
|
||||
|
||||
// Get excels from game data
|
||||
NpcMonsterExcel npcMonsterExcel = GameData.getNpcMonsterExcelMap().get(monsterInfo.getNPCMonsterID());
|
||||
if (npcMonsterExcel == null) continue;
|
||||
|
||||
// Create monster with excels
|
||||
EntityMonster monster = new EntityMonster(this, npcMonsterExcel, monsterInfo.getPos());
|
||||
monster.getRot().set(monsterInfo.getRot());
|
||||
monster.setInstId(monsterInfo.getID());
|
||||
monster.setEventId(monsterInfo.getEventID());
|
||||
monster.setGroupId(group.getId());
|
||||
monster.setWorldLevel(this.getPlayer().getWorldLevel());
|
||||
|
||||
// Add to monsters
|
||||
try {
|
||||
EntityMonster monster = this.getEntityLoader().loadMonster(this, group, monsterInfo);
|
||||
this.addEntity(monster);
|
||||
} catch (Exception e) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add props
|
||||
if (group.getPropList() != null && group.getPropList().size() > 0) {
|
||||
for (PropInfo propInfo : group.getPropList()) {
|
||||
// Don't spawn entity if they have the IsDelete flag in group info
|
||||
if (propInfo.isIsDelete()) continue;
|
||||
|
||||
// Get prop excel
|
||||
PropExcel propExcel = GameData.getPropExcelMap().get(propInfo.getPropID());
|
||||
if (propExcel == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create prop from prop info
|
||||
EntityProp prop = new EntityProp(this, propExcel, propInfo.getPos());
|
||||
prop.setState(propInfo.getState());
|
||||
prop.getRot().set(propInfo.getRot());
|
||||
prop.setInstId(propInfo.getID());
|
||||
prop.setGroupId(group.getId());
|
||||
prop.setPropInfo(propInfo);
|
||||
|
||||
// Cache
|
||||
if (prop.getPropId() == 1003) {
|
||||
// Hacky fix to open simulated universe
|
||||
if (propInfo.getMappingInfoID() == 2220) {
|
||||
// Regular simulated universe is locked behind a mission requirement by default
|
||||
prop.setState(PropState.Open);
|
||||
} else {
|
||||
// Skip tutorial simulated universe
|
||||
continue;
|
||||
}
|
||||
} else if (prop.getExcel().getPropType() == PropType.PROP_SPRING) {
|
||||
// Cache teleport anchors
|
||||
this.getHealingSprings().add(prop);
|
||||
}
|
||||
|
||||
// Add trigger
|
||||
if (propInfo.getTrigger() != null) {
|
||||
this.getTriggers().add(propInfo.getTrigger());
|
||||
}
|
||||
|
||||
// Add to monsters
|
||||
try {
|
||||
EntityProp prop = this.getEntityLoader().loadNpc(this, group, propInfo);
|
||||
this.addEntity(prop);
|
||||
} catch (Exception e) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add npcs
|
||||
// Add NPCs
|
||||
if (group.getNPCList() != null && group.getNPCList().size() > 0) {
|
||||
for (NpcInfo npcInfo : group.getNPCList()) {
|
||||
// Don't spawn entity if they have the IsDelete flag in group info
|
||||
if (npcInfo.isIsDelete() || !GameData.getNpcExcelMap().containsKey(npcInfo.getNPCID())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dont spawn duplicate NPCs
|
||||
boolean haseDuplicateNpcId = false;
|
||||
for (GameEntity entity : this.getEntities().values()) {
|
||||
if (entity instanceof EntityNpc eNpc && eNpc.getNpcId() == npcInfo.getNPCID()) {
|
||||
haseDuplicateNpcId = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (haseDuplicateNpcId) continue;
|
||||
|
||||
// Create npc from npc info
|
||||
EntityNpc npc = new EntityNpc(this, npcInfo.getNPCID(), npcInfo.getPos());
|
||||
npc.getRot().set(npcInfo.getRot());
|
||||
npc.setInstId(npcInfo.getID());
|
||||
npc.setGroupId(group.getId());
|
||||
|
||||
// Add to monsters
|
||||
try {
|
||||
EntityNpc npc = this.getEntityLoader().loadNpc(this, group, npcInfo);
|
||||
this.addEntity(npc);
|
||||
} catch (Exception e) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,13 +266,18 @@ public class Scene {
|
||||
}
|
||||
|
||||
public synchronized void addEntity(GameEntity entity, boolean sendPacket) {
|
||||
// Dont add if monster id already exists
|
||||
if (entity.getEntityId() != 0) return;
|
||||
// Sanity checks - Also dont add entity if it already exists
|
||||
if (entity == null || entity.getEntityId() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set entity id and add monster to entity map
|
||||
entity.setEntityId(this.getNextEntityId());
|
||||
this.getEntities().put(entity.getEntityId(), entity);
|
||||
|
||||
// Entity add callback
|
||||
entity.onAdd();
|
||||
|
||||
// Send packet
|
||||
if (sendPacket) {
|
||||
player.sendPacket(new PacketSceneGroupRefreshScNotify(entity, null));
|
||||
@@ -346,7 +292,8 @@ public class Scene {
|
||||
GameEntity entity = this.getEntities().remove(entityId);
|
||||
|
||||
if (entity != null) {
|
||||
// Entity remove callback
|
||||
// Reset entity id and run event
|
||||
entity.setEntityId(0);
|
||||
entity.onRemove();
|
||||
// Send packet
|
||||
player.sendPacket(new PacketSceneGroupRefreshScNotify(null, entity));
|
||||
|
||||
103
src/main/java/emu/lunarcore/game/scene/SceneEntityLoader.java
Normal file
103
src/main/java/emu/lunarcore/game/scene/SceneEntityLoader.java
Normal file
@@ -0,0 +1,103 @@
|
||||
package emu.lunarcore.game.scene;
|
||||
|
||||
import emu.lunarcore.data.GameData;
|
||||
import emu.lunarcore.data.config.GroupInfo;
|
||||
import emu.lunarcore.data.config.MonsterInfo;
|
||||
import emu.lunarcore.data.config.NpcInfo;
|
||||
import emu.lunarcore.data.config.PropInfo;
|
||||
import emu.lunarcore.data.excel.NpcMonsterExcel;
|
||||
import emu.lunarcore.data.excel.PropExcel;
|
||||
import emu.lunarcore.game.enums.PropState;
|
||||
import emu.lunarcore.game.enums.PropType;
|
||||
import emu.lunarcore.game.scene.entity.EntityMonster;
|
||||
import emu.lunarcore.game.scene.entity.EntityNpc;
|
||||
import emu.lunarcore.game.scene.entity.EntityProp;
|
||||
import emu.lunarcore.game.scene.entity.GameEntity;
|
||||
|
||||
public class SceneEntityLoader {
|
||||
|
||||
public EntityMonster loadMonster(Scene scene, GroupInfo group, MonsterInfo monsterInfo) {
|
||||
// Don't spawn entity if they have the IsDelete flag in group info
|
||||
if (monsterInfo.isIsDelete()) return null;
|
||||
|
||||
// Get excels from game data
|
||||
NpcMonsterExcel npcMonsterExcel = GameData.getNpcMonsterExcelMap().get(monsterInfo.getNPCMonsterID());
|
||||
if (npcMonsterExcel == null) return null;
|
||||
|
||||
// Create monster with excels
|
||||
EntityMonster monster = new EntityMonster(scene, npcMonsterExcel, monsterInfo.getPos());
|
||||
monster.getRot().set(monsterInfo.getRot());
|
||||
monster.setGroupId(group.getId());
|
||||
monster.setInstId(monsterInfo.getID());
|
||||
monster.setEventId(monsterInfo.getEventID());
|
||||
monster.setWorldLevel(scene.getPlayer().getWorldLevel());
|
||||
|
||||
return monster;
|
||||
}
|
||||
|
||||
public EntityProp loadNpc(Scene scene, GroupInfo group, PropInfo propInfo) {
|
||||
// Don't spawn entity if they have the IsDelete flag in group info
|
||||
if (propInfo.isIsDelete()) return null;
|
||||
|
||||
// Get prop excel
|
||||
PropExcel propExcel = GameData.getPropExcelMap().get(propInfo.getPropID());
|
||||
if (propExcel == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create prop from prop info
|
||||
EntityProp prop = new EntityProp(scene, propExcel, propInfo.getPos());
|
||||
prop.setState(propInfo.getState());
|
||||
prop.getRot().set(propInfo.getRot());
|
||||
prop.setInstId(propInfo.getID());
|
||||
prop.setGroupId(group.getId());
|
||||
prop.setPropInfo(propInfo);
|
||||
|
||||
// Cache
|
||||
if (prop.getPropId() == 1003) {
|
||||
// Hacky fix to open simulated universe
|
||||
if (propInfo.getMappingInfoID() == 2220) {
|
||||
// Regular simulated universe is locked behind a mission requirement by default
|
||||
prop.setState(PropState.Open);
|
||||
} else {
|
||||
// Skip tutorial simulated universe
|
||||
return null;
|
||||
}
|
||||
} else if (prop.getExcel().getPropType() == PropType.PROP_SPRING) {
|
||||
// Cache teleport anchors
|
||||
scene.getHealingSprings().add(prop);
|
||||
}
|
||||
|
||||
// Add trigger
|
||||
if (propInfo.getTrigger() != null) {
|
||||
scene.getTriggers().add(propInfo.getTrigger());
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
public EntityNpc loadNpc(Scene scene, GroupInfo group, NpcInfo npcInfo) {
|
||||
// Don't spawn entity if they have the IsDelete flag in group info
|
||||
if (npcInfo.isIsDelete() || !GameData.getNpcExcelMap().containsKey(npcInfo.getNPCID())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Dont spawn duplicate NPCs
|
||||
boolean haseDuplicateNpcId = false;
|
||||
for (GameEntity entity : scene.getEntities().values()) {
|
||||
if (entity instanceof EntityNpc eNpc && eNpc.getNpcId() == npcInfo.getNPCID()) {
|
||||
haseDuplicateNpcId = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (haseDuplicateNpcId) return null;
|
||||
|
||||
// Create npc from npc info
|
||||
EntityNpc npc = new EntityNpc(scene, npcInfo.getNPCID(), npcInfo.getPos());
|
||||
npc.getRot().set(npcInfo.getRot());
|
||||
npc.setInstId(npcInfo.getID());
|
||||
npc.setGroupId(group.getId());
|
||||
|
||||
return npc;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user