Added group state handler and improved interaction handling

This commit is contained in:
Melledy
2024-01-01 03:47:55 -08:00
parent 40cf8e8935
commit 5b1218d09d
21 changed files with 1701 additions and 551 deletions

View File

@@ -33,6 +33,7 @@ public class GameData {
@Getter private static Int2ObjectMap<HeroExcel> heroExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<ShopExcel> shopExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<RewardExcel> rewardExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<InteractExcel> interactExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<PlayerIconExcel> playerIconExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<ItemComposeExcel> itemComposeExcelMap = new Int2ObjectOpenHashMap<>();
@Getter private static Int2ObjectMap<ActivityPanelExcel> activityPanelExcelMap = new Int2ObjectOpenHashMap<>();

View File

@@ -72,10 +72,12 @@ public class FloorInfo {
// Hacky way to setup prop triggers
if (json.contains("Maze_GroupProp_OpenTreasure_WhenMonsterDie")) {
prop.setTrigger(new TriggerOpenTreasureWhenMonsterDie(group.getId()));
} else if (json.contains("Maze_Chap02_X201_Event_PuzzleCompass_WayPoint_Controller_01")) {
prop.setTrigger(new TriggerPuzzleCompassWayPointController(prop.getSharedValueByKey("PuzzleCompass_Prop"), prop.getSharedValueByKey("PuzzleChest_Prop")));
} else if (json.contains("Maze_Chap02_X201_Event_PuzzleCompass_WayPoint_Controller")) {
prop.setTrigger(new TriggerPuzzleCompassWayPointController(group.getId()));
}
// Clear for garbage collection
prop.setValueSource(null);
prop.setInitLevelGraph(null);
}
}

View File

@@ -25,8 +25,8 @@ public class PropInfo extends ObjectInfo {
private int CocoonID;
private int FarmElementID;
private boolean IsClientOnly;
private PropValueSource ValueSource;
@Setter private PropValueSource ValueSource;
@Setter private String InitLevelGraph;
@Setter private PropState State = PropState.Closed;

View File

@@ -0,0 +1,27 @@
package emu.lunarcore.data.excel;
import emu.lunarcore.data.GameResource;
import emu.lunarcore.data.ResourceType;
import emu.lunarcore.game.enums.PropState;
import lombok.Getter;
@Getter
@ResourceType(name = {"InteractConfig.json"})
public class InteractExcel extends GameResource {
private int InteractID;
private PropState SrcState;
private PropState TargetState = PropState.Closed;
@Override
public int getId() {
return InteractID;
}
@Override
public void onLoad() {
// Just in case we forget to update the prop state enum
if (this.TargetState == null) {
this.TargetState = PropState.Closed;
}
}
}

View File

@@ -1,7 +1,10 @@
package emu.lunarcore.data.excel;
import java.util.Set;
import emu.lunarcore.data.GameResource;
import emu.lunarcore.data.ResourceType;
import emu.lunarcore.game.enums.PropState;
import emu.lunarcore.game.enums.PropType;
import lombok.Getter;
@@ -12,6 +15,7 @@ public class PropExcel extends GameResource {
private long PropName;
private String JsonPath;
private PropType PropType;
private Set<PropState> PropStateList;
private transient boolean recoverHp;
private transient boolean recoverMp;
@@ -34,6 +38,11 @@ public class PropExcel extends GameResource {
this.isDoor = true;
}
}
// Sanity
if (this.PropStateList == null) {
this.PropStateList = Set.of();
}
// Clear for optimization
this.JsonPath = null;

View File

@@ -12,6 +12,7 @@ import emu.lunarcore.data.GameData;
import emu.lunarcore.data.config.AnchorInfo;
import emu.lunarcore.data.config.FloorInfo;
import emu.lunarcore.data.config.PropInfo;
import emu.lunarcore.data.excel.InteractExcel;
import emu.lunarcore.data.excel.ItemUseExcel;
import emu.lunarcore.data.excel.MapEntranceExcel;
import emu.lunarcore.data.excel.MazePlaneExcel;
@@ -578,7 +579,7 @@ public class Player implements Tickable {
return true;
}
public EntityProp interactWithProp(int propEntityId) {
public EntityProp interactWithProp(int interactId, int propEntityId) {
// Sanity
if (this.getScene() == null) return null;
@@ -592,33 +593,44 @@ public class Player implements Tickable {
return null;
}
// Handle prop interaction action
// Get interact handler
InteractExcel interactExcel = GameData.getInteractExcelMap().get(interactId);
if (interactExcel == null) {
return prop;
}
// Validate
if (interactExcel.getSrcState() != null && prop.getState() != interactExcel.getSrcState()) {
return prop;
}
// Save old state
PropState oldState = prop.getState();
// Set group and prop state
this.sendPacket(new PacketGroupStateChangeScNotify(getEntryId(), prop.getGroupId(), interactExcel.getTargetState()));
prop.setState(interactExcel.getTargetState());
// Handle any extra interaction actions
switch (prop.getExcel().getPropType()) {
case PROP_TREASURE_CHEST -> {
if (prop.getState() == PropState.ChestClosed) {
// Open chest
prop.setState(PropState.ChestUsed);
if (oldState == PropState.ChestClosed && prop.getState() == PropState.ChestUsed) {
// Handle drops
var drops = this.getServer().getDropService().calculateDropsFromProp(prop.getPropId());
this.getInventory().addItems(drops, true);
// Done
return prop;
} else {
return null;
}
}
case PROP_MAZE_PUZZLE -> {
// Finish puzzle
prop.setState(PropState.Locked);
// Trigger event
this.getScene().invokePropTrigger(PropTriggerType.PUZZLE_FINISH, prop.getGroupId(), prop.getInstId());
//
return prop;
}
default -> {
return null;
}
}
// Return prop when we are done
return prop;
}
public void onMove() {

View File

@@ -155,6 +155,14 @@ public class Scene implements Tickable {
public synchronized GameEntity getEntityById(int id) {
return this.getEntities().get(id);
}
public synchronized <T extends GameEntity> List<T> getEntitiesByGroup(Class<T> entityType, int groupId) {
return this.getEntities().values()
.stream()
.filter(e -> entityType.isInstance(e) && e.getGroupId() == groupId)
.map(entityType::cast)
.toList();
}
public void syncLineup() {
// Get current lineup

View File

@@ -54,17 +54,30 @@ public class EntityProp implements GameEntity {
return excel.getId();
}
public void setState(PropState state) {
this.setState(state, this.getScene().isLoaded());
public boolean setState(PropState state) {
return this.setState(state, this.getScene().isLoaded());
}
public void setState(PropState state, boolean sendPacket) {
public boolean setState(PropState state, boolean sendPacket) {
// Only set state if its been changed
PropState oldState = this.getState();
if (oldState == state) return false;
// Sanity check
if (!this.getExcel().getPropStateList().contains(state)) {
return false;
}
// Set state
this.state = state;
// Sync state update to client
if (sendPacket) {
this.getScene().getPlayer().sendPacket(new PacketSceneGroupRefreshScNotify(this, null));
}
// Success
return true;
}
@Override
@@ -98,6 +111,10 @@ public class EntityProp implements GameEntity {
@Override
public String toString() {
return "Prop: " + this.getEntityId() + ", Group: " + this.groupId + ", Inst: " + this.getInstId();
return "[Prop] EntityId: " + this.getEntityId() +
", PropId: " + this.getExcel().getId() +
" (" + this.getExcel().getPropType() + ")" +
", Group: " + this.groupId +
", ConfigId: " + this.getInstId();
}
}

View File

@@ -4,7 +4,6 @@ import emu.lunarcore.game.enums.PropState;
import emu.lunarcore.game.enums.PropType;
import emu.lunarcore.game.scene.Scene;
import emu.lunarcore.game.scene.entity.EntityProp;
import emu.lunarcore.game.scene.entity.GameEntity;
import lombok.Getter;
@Getter
@@ -27,17 +26,10 @@ public class TriggerOpenTreasureWhenMonsterDie extends PropTrigger {
@Override
public void run(Scene scene) {
synchronized (scene) {
for (GameEntity entity : scene.getEntities().values()) {
if (entity.getGroupId() != this.groupId) {
continue;
}
if (entity instanceof EntityProp prop) {
if (prop.getExcel().getPropType() == PropType.PROP_TREASURE_CHEST) {
prop.setState(PropState.ChestClosed);
}
}
// Open trigger
for (var prop : scene.getEntitiesByGroup(EntityProp.class, this.getGroupId())) {
if (prop.getExcel().getPropType() == PropType.PROP_TREASURE_CHEST) {
prop.setState(PropState.ChestClosed);
}
}
}

View File

@@ -3,23 +3,14 @@ package emu.lunarcore.game.scene.triggers;
import emu.lunarcore.game.enums.PropState;
import emu.lunarcore.game.scene.Scene;
import emu.lunarcore.game.scene.entity.EntityProp;
import emu.lunarcore.game.scene.entity.GameEntity;
import emu.lunarcore.util.Utils;
import lombok.Getter;
@Getter
public class TriggerPuzzleCompassWayPointController extends PropTrigger {
private int groupId;
private int puzzleInstId;
private int chestInstId;
public TriggerPuzzleCompassWayPointController(String compassKey, String chestKey) {
String[] compass = compassKey.split(",");
String[] chest = chestKey.split(",");
this.groupId = Utils.parseSafeInt(compass[0]);
this.puzzleInstId = Utils.parseSafeInt(compass[1]);
this.chestInstId = Utils.parseSafeInt(chest[1]);
public TriggerPuzzleCompassWayPointController(int groupId) {
this.groupId = groupId;
}
@Override
@@ -29,23 +20,13 @@ public class TriggerPuzzleCompassWayPointController extends PropTrigger {
@Override
public boolean shouldRun(int groupId, int instId) {
return this.groupId == groupId && this.puzzleInstId == instId;
return this.groupId == groupId;
}
@Override
public void run(Scene scene) {
synchronized (scene) {
for (GameEntity entity : scene.getEntities().values()) {
if (entity.getGroupId() != this.groupId) {
continue;
}
if (entity instanceof EntityProp prop) {
if (prop.getInstId() == chestInstId) {
prop.setState(PropState.ChestClosed);
}
}
}
for (var prop : scene.getEntitiesByGroup(EntityProp.class, groupId)) {
prop.setState(PropState.Open);
}
}
}

View File

@@ -0,0 +1,23 @@
package emu.lunarcore.server.packet.recv;
import emu.lunarcore.proto.GroupStateChangeCsReqOuterClass.GroupStateChangeCsReq;
import emu.lunarcore.server.game.GameSession;
import emu.lunarcore.server.packet.CmdId;
import emu.lunarcore.server.packet.Opcodes;
import emu.lunarcore.server.packet.PacketHandler;
import emu.lunarcore.server.packet.send.PacketGroupStateChangeScNotify;
import emu.lunarcore.server.packet.send.PacketGroupStateChangeScRsp;
@Opcodes(CmdId.GroupStateChangeCsReq)
public class HandlerGroupStateChangeCsReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] data) throws Exception {
var req = GroupStateChangeCsReq.parseFrom(data);
var groupInfo = req.getMutableGroupInfo();
session.send(new PacketGroupStateChangeScNotify(groupInfo));
session.send(new PacketGroupStateChangeScRsp(groupInfo));
}
}

View File

@@ -15,7 +15,7 @@ public class HandlerInteractPropCsReq extends PacketHandler {
public void handle(GameSession session, byte[] data) throws Exception {
var req = InteractPropCsReq.parseFrom(data);
EntityProp prop = session.getPlayer().interactWithProp(req.getPropEntityId());
EntityProp prop = session.getPlayer().interactWithProp(req.getInteractId(), req.getPropEntityId());
session.send(new PacketInteractPropScRsp(prop));
}

View File

@@ -0,0 +1,32 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.game.enums.PropState;
import emu.lunarcore.proto.GroupStateChangeScNotifyOuterClass.GroupStateChangeScNotify;
import emu.lunarcore.proto.GroupStateInfoOuterClass.GroupStateInfo;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
public class PacketGroupStateChangeScNotify extends BasePacket {
public PacketGroupStateChangeScNotify(GroupStateInfo groupInfo) {
super(CmdId.GroupStateChangeScNotify);
var data = GroupStateChangeScNotify.newInstance();
data.setGroupInfo(groupInfo);
this.setData(data);
}
public PacketGroupStateChangeScNotify(int entryId, int groupId, PropState state) {
super(CmdId.GroupStateChangeScNotify);
var data = GroupStateChangeScNotify.newInstance();
data.getMutableGroupInfo()
.setEntryId(entryId)
.setGroupId(groupId)
.setGroupState(state.getVal());
this.setData(data);
}
}

View File

@@ -0,0 +1,18 @@
package emu.lunarcore.server.packet.send;
import emu.lunarcore.proto.GroupStateChangeScNotifyOuterClass.GroupStateChangeScNotify;
import emu.lunarcore.proto.GroupStateInfoOuterClass.GroupStateInfo;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
public class PacketGroupStateChangeScRsp extends BasePacket {
public PacketGroupStateChangeScRsp(GroupStateInfo groupInfo) {
super(CmdId.GroupStateChangeScRsp);
var data = GroupStateChangeScNotify.newInstance();
data.setGroupInfo(groupInfo);
this.setData(data);
}
}

View File

@@ -35,12 +35,16 @@ public class PacketSceneGroupRefreshScNotify extends BasePacket {
var group = SceneGroupRefreshInfo.newInstance();
for (var entity : toAdd) {
group.addRefreshEntity(SceneEntityRefreshInfo.newInstance().setAddEntity(entity.toSceneEntityProto()));
if (toAdd != null) {
for (var entity : toAdd) {
group.addRefreshEntity(SceneEntityRefreshInfo.newInstance().setAddEntity(entity.toSceneEntityProto()));
}
}
for (var entity : toRemove) {
group.addRefreshEntity(SceneEntityRefreshInfo.newInstance().setDelEntity(entity.getEntityId()));
if (toRemove != null) {
for (var entity : toRemove) {
group.addRefreshEntity(SceneEntityRefreshInfo.newInstance().setDelEntity(entity.getEntityId()));
}
}
var data = SceneGroupRefreshScNotify.newInstance()