Rewrite how scenes load entities to support spawning the correct rogue monsters

This commit is contained in:
Melledy
2023-10-25 08:53:16 -07:00
parent fb902c2b8a
commit c38cf693ba
9 changed files with 240 additions and 107 deletions

View File

@@ -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<>();

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -1,22 +1,30 @@
package emu.lunarcore.game.enums;
import emu.lunarcore.game.rogue.RogueEntityLoader;
import emu.lunarcore.game.scene.SceneEntityLoader;
import lombok.Getter;
@Getter
public enum PlaneType {
Unknown (0),
Town (1),
Maze (2),
Train (3),
Challenge (4),
Rogue (5),
Raid (6),
AetherDivide (7),
TrialActivity (8);
Unknown (0),
Town (1),
Maze (2),
Train (3),
Challenge (4),
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;
}
}

View File

@@ -59,6 +59,8 @@ public class RogueData {
return this.rooms.get(this.getCurrentSiteId());
}
// Serialization
public RogueCurrentInfo toProto() {
var proto = RogueCurrentInfo.newInstance()
.setStatus(this.getStatus())

View File

@@ -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;
}
}

View File

@@ -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()));
}

View File

@@ -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
this.addEntity(monster);
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;
try {
EntityProp prop = this.getEntityLoader().loadNpc(this, group, propInfo);
this.addEntity(prop);
} catch (Exception e) {
// Ignored
}
// 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
this.addEntity(prop);
}
}
// 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;
try {
EntityNpc npc = this.getEntityLoader().loadNpc(this, group, npcInfo);
this.addEntity(npc);
} catch (Exception e) {
// Ignored
}
// 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
this.addEntity(npc);
}
}
}
@@ -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));

View 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;
}
}