Fix daily dungeon flow (#2398)

* Fix dungeon entry, daily changes, replay flow; fix Mond's weapon mats domain unlock

* add note to DungeonEntryToBeExploreNotify
This commit is contained in:
longfruit 2023-10-16 22:41:04 -07:00 committed by GitHub
parent 6745d1126e
commit 770cd62370
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 278 additions and 38 deletions

View File

@ -32,9 +32,12 @@ public final class DebugCommand implements CommandHandler {
var scene = sender.getScene();
var entityId = Integer.parseInt(args.get(0));
// TODO Might want to allow groupId specification,
// because there can be more than one entity with
// the given config ID.
var entity =
args.size() > 1 && args.get(1).equals("config")
? scene.getEntityByConfigId(entityId)
? scene.getFirstEntityByConfigId(entityId)
: scene.getEntityById(entityId);
if (entity == null) {
sender.dropMessage("Entity not found.");

View File

@ -51,7 +51,10 @@ public final class EntityCommand implements CommandHandler {
}
param.scene = targetPlayer.getScene();
var entity = param.scene.getEntityByConfigId(param.configId);
// TODO Might want to allow groupId specification,
// because there can be more than one entity with
// the given config ID.
var entity = param.scene.getFirstEntityByConfigId(param.configId);
if (entity == null) {
CommandHandler.sendMessage(sender, translate(sender, "commands.entity.not_found_error"));

View File

@ -19,6 +19,7 @@ public final class PointData {
@Getter private Position size;
@Getter private boolean forbidSimpleUnlock;
@Getter private boolean unlocked;
@Getter private boolean groupLimit;
@SerializedName(
value = "dungeonIds",
@ -28,7 +29,7 @@ public final class PointData {
@SerializedName(
value = "dungeonRandomList",
alternate = {"OIBKFJNBLHO"})
alternate = {"GLEKJMEEOMH"})
@Getter
private int[] dungeonRandomList;

View File

@ -1,6 +1,8 @@
package emu.grasscutter.data.excels.dungeon;
import emu.grasscutter.game.dungeons.enums.*;
import emu.grasscutter.data.*;
import java.util.List;
import lombok.*;
@ResourceType(name = "DungeonEntryExcelConfigData.json")
@ -12,4 +14,44 @@ public class DungeonEntryData extends GameResource {
private int dungeonEntryId;
private int sceneId;
private DungunEntryType type;
private DungeonEntryCondCombType condComb;
private List<DungeonEntryCondition> satisfiedCond;
public static class DungeonEntryCondition {
private DungeonEntrySatisfiedConditionType type;
private int param1;
}
public DungunEntryType getType() {
if (type == null) {
return DungunEntryType.DUNGEN_ENTRY_TYPE_NONE;
}
return type;
}
public DungeonEntryCondCombType getCondComb() {
if (condComb == null) {
return DungeonEntryCondCombType.DUNGEON_ENTRY_COND_COMB_NONE;
}
return condComb;
}
public int getLevelCondition() {
for (var cond : satisfiedCond) {
if (cond.type != null && cond.type.equals(DungeonEntrySatisfiedConditionType.DUNGEON_ENTRY_CONDITION_LEVEL)) {
return cond.param1;
}
}
return 0;
}
public int getQuestCondition() {
for (var cond : satisfiedCond) {
if (cond.type != null && cond.type.equals(DungeonEntrySatisfiedConditionType.DUNGEON_ENTRY_CONDITION_QUEST)) {
return cond.param1;
}
}
return 0;
}
}

View File

@ -7,10 +7,14 @@ import emu.grasscutter.data.excels.dungeon.*;
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.props.EnterReason;
import emu.grasscutter.game.world.*;
import emu.grasscutter.net.packet.*;
import emu.grasscutter.server.game.*;
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
import emu.grasscutter.game.world.data.TeleportProperties;
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
import it.unimi.dsi.fastutil.ints.*;
import java.util.List;
import lombok.val;
@ -173,4 +177,25 @@ public final class DungeonSystem extends BaseGameSystem {
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
}
public void restartDungeon(Player player) {
var scene = player.getScene();
var dungeonManager = scene.getDungeonManager();
var dungeonData = dungeonManager.getDungeonData();
var sceneId = dungeonData.getSceneId();
// Forward over previous scene and scene point
var prevScene = scene.getPrevScene();
var pointId = scene.getPrevScenePoint();
// Destroy then create scene again to reinitialize script state
scene.getPlayers().forEach(scene::removePlayer);
if (player.getWorld().transferPlayerToScene(player, sceneId, dungeonData)) {
scene = player.getScene();
scene.setPrevScene(prevScene);
scene.setPrevScenePoint(pointId);
scene.setDungeonManager(new DungeonManager(scene, dungeonData));
scene.addDungeonSettleObserver(basicDungeonSettleObserver);
}
}
}

View File

@ -0,0 +1,7 @@
package emu.grasscutter.game.dungeons.enums;
public enum DungeonEntryCondCombType {
DUNGEON_ENTRY_COND_COMB_NONE,
DUNGEON_ENTRY_COND_COMB_LOGIC_OR,
DUNGEON_ENTRY_COND_COMB_LOGIC_AND
}

View File

@ -1,6 +1,6 @@
package emu.grasscutter.game.entity.gadget;
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
@ -18,7 +18,7 @@ public final class GadgetRewardStatue extends GadgetContent {
public boolean onInteract(Player player, GadgetInteractReq req) {
var dungeonManager = player.getScene().getDungeonManager();
if (player.getScene().getChallenge() instanceof DungeonChallenge) {
if (player.getScene().getChallenge() instanceof WorldChallenge) {
var useCondensed =
req.getResinCostType() == ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE;
dungeonManager.getStatueDrops(player, useCondensed, getGadget().getGroupId());

View File

@ -1530,6 +1530,31 @@ public class Player implements PlayerHook, FieldFetch {
getServer().getPlayers().values().removeIf(player1 -> player1 == this);
}
public void unfreezeUnlockedScenePoints(int sceneId) {
// Unfreeze previously unlocked scene points. For example,
// the first weapon mats domain needs some script interaction
// to unlock. It needs to be unfrozen when GetScenePointReq
// comes in to be interactable again.
GameData.getScenePointEntryMap().values().stream()
.filter(scenePointEntry ->
// Note: Only DungeonEntry scene points need to be unfrozen
scenePointEntry.getPointData().getType().equals("DungeonEntry")
// groupLimit says this scene point needs to be unfrozen
&& scenePointEntry.getPointData().isGroupLimit())
.forEach(scenePointEntry -> {
// If this is a previously unlocked scene point,
// send unfreeze packet.
val pointId = scenePointEntry.getPointData().getId();
if (unlockedScenePoints.get(sceneId).contains(pointId)) {
this.sendPacket(new PacketUnfreezeGroupLimitNotify(pointId, sceneId));
}
});
}
public void unfreezeUnlockedScenePoints() {
unlockedScenePoints.keySet().forEach(sceneId -> unfreezeUnlockedScenePoints(sceneId));
}
public int getLegendaryKey() {
return this.getProperty(PlayerProperty.PROP_PLAYER_LEGENDARY_KEY);
}

View File

@ -158,7 +158,7 @@ public class Scene {
return entity;
}
public GameEntity getEntityByConfigId(int configId) {
public GameEntity getFirstEntityByConfigId(int configId) {
return this.entities.values().stream()
.filter(x -> x.getConfigId() == configId)
.findFirst()

View File

@ -265,6 +265,10 @@ public class SceneScriptManager {
groupInstance.setActiveSuiteId(suiteIndex);
groupInstance.setLastTimeRefreshed(getScene().getWorld().getGameTime());
// Call EVENT_GROUP_REFRESH for any action trigger waiting for it
callEvent(new ScriptArgs(groupInstance.getGroupId(), EventType.EVENT_GROUP_REFRESH));
return suiteIndex;
}
@ -323,7 +327,7 @@ public class SceneScriptManager {
group.monsters.values().stream()
.filter(
m -> {
var entity = scene.getEntityByConfigId(m.config_id);
var entity = scene.getEntityByConfigId(m.config_id, groupId);
return (entity == null
|| entity.getGroupId()
!= group
@ -694,7 +698,7 @@ public class SceneScriptManager {
return suite.sceneGadgets.stream()
.filter(
m -> {
var entity = scene.getEntityByConfigId(m.config_id);
var entity = scene.getEntityByConfigId(m.config_id, group.id);
return (entity == null || entity.getGroupId() != group.id)
&& (!m.isOneoff
|| !m.persistent
@ -712,7 +716,7 @@ public class SceneScriptManager {
return suite.sceneMonsters.stream()
.filter(
m -> {
var entity = scene.getEntityByConfigId(m.config_id);
var entity = scene.getEntityByConfigId(m.config_id, group.id);
return (entity == null
|| entity.getGroupId()
!= group
@ -788,7 +792,7 @@ public class SceneScriptManager {
public void spawnMonstersByConfigId(SceneGroup group, int configId, int delayTime) {
// TODO delay
var entity = scene.getEntityByConfigId(configId);
var entity = scene.getEntityByConfigId(configId, group.id);
if (entity != null && entity.getGroupId() == group.id) {
Grasscutter.getLogger()
.debug("entity already exists failed in group {} with config {}", group.id, configId);
@ -884,9 +888,11 @@ public class SceneScriptManager {
private boolean evaluateTriggerCondition(SceneTrigger trigger, ScriptArgs params) {
Grasscutter.getLogger()
.trace(
"Call Condition Trigger {}, [{},{},{}]",
"Call Condition Trigger {}, [{},{},{}], source_eid {}, target_eid {}",
trigger.getCondition(),
params.param1,
params.param2,
params.param3,
params.source_eid,
params.target_eid);
LuaValue ret = this.callScriptFunc(trigger.getCondition(), trigger.currentGroup, params);
@ -1194,7 +1200,7 @@ public class SceneScriptManager {
return monsters.values().stream()
.noneMatch(
m -> {
val entity = scene.getEntityByConfigId(m.config_id);
val entity = scene.getEntityByConfigId(m.config_id, groupId);
return entity != null && entity.getGroupId() == groupId;
});
}

View File

@ -31,7 +31,7 @@ import static emu.grasscutter.scripts.constants.GroupKillPolicy.*;
@SuppressWarnings("unused")
public class ScriptLib {
public static final Logger logger = LoggerFactory.getLogger(ScriptLib.class);
public static final Logger logger = Grasscutter.getLogger();
private final FastThreadLocal<SceneScriptManager> sceneScriptManager;
private final FastThreadLocal<SceneGroup> currentGroup;
private final FastThreadLocal<ScriptArgs> callParams;
@ -128,7 +128,7 @@ public class ScriptLib {
// kill targets if exists
targets.forEach(o -> {
var entity = getSceneScriptManager().getScene().getEntityByConfigId(o.config_id);
var entity = getSceneScriptManager().getScene().getEntityByConfigId(o.config_id, getCurrentGroup().get().id);
if (entity == null) {
return;
}
@ -153,7 +153,7 @@ public class ScriptLib {
// kill targets if exists
for (int cfgId : targets) {
var entity = getSceneScriptManager().getScene().getEntityByConfigId(cfgId);
var entity = getSceneScriptManager().getScene().getEntityByConfigId(cfgId, getCurrentGroup().get().id);
if (entity == null || cfgId == 0) {
continue;
}
@ -402,11 +402,11 @@ public class ScriptLib {
// TODO: ChangeDeathZone
public int ChangeGroupGadget(LuaTable table) {
logger.debug("[LUA] Call ChangeGroupGadget with {}", printTable(table));
logger.debug("[LUA] Call ChangeGroupGadget with {}, current group {}", printTable(table), getCurrentGroup().get().id);
var configId = table.get("config_id").toint();
var state = table.get("state").toint();
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId);
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, getCurrentGroup().get().id);
if (entity == null) {
return 1;
}
@ -601,7 +601,7 @@ public class ScriptLib {
return 1;
}
var configId = callParams.param1;
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId);
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, getCurrentGroup().get().id);
if (!(entity instanceof EntityGadget gadget)) {
return 1;
}
@ -785,7 +785,7 @@ public class ScriptLib {
public int GetEntityIdByConfigId(int configId) {
logger.warn("[LUA] Call GetEntityIdByConfigId with {}", configId);
// TODO check
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId);
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, getCurrentGroup().get().id);
return entity != null ? entity.getId() : 0;
}
@ -811,7 +811,7 @@ public class ScriptLib {
public int GetGadgetStateByConfigId(int groupId, int configId) {
logger.debug("[LUA] Call GetGadgetStateByConfigId with {},{}", groupId, configId);
val scene = getSceneScriptManager().getScene();
val gadget = groupId == 0 ? scene.getEntityByConfigId(configId) : scene.getEntityByConfigId(configId, groupId);
val gadget = groupId == 0 ? scene.getEntityByConfigId(configId, getCurrentGroup().get().id) : scene.getEntityByConfigId(configId, groupId);
if (!(gadget instanceof EntityGadget)) {
return -1;
}
@ -833,17 +833,19 @@ public class ScriptLib {
// TODO: GetGroupLogicStateValue
public int GetGroupMonsterCount() {
logger.debug("[LUA] Call GetGroupMonsterCount ");
return (int) getSceneScriptManager().getScene().getEntities().values().stream()
int returnValue = (int) getSceneScriptManager().getScene().getEntities().values().stream()
.filter(e -> e instanceof EntityMonster && e.getGroupId() == currentGroup.get().id)
.count();
logger.debug("[LUA] Call GetGroupMonsterCount = {}", returnValue);
return returnValue;
}
public int GetGroupMonsterCountByGroupId(int groupId) {
logger.debug("[LUA] Call GetGroupMonsterCountByGroupId with {}", groupId);
return (int) getSceneScriptManager().getScene().getEntities().values().stream()
int returnValue = (int) getSceneScriptManager().getScene().getEntities().values().stream()
.filter(e -> e instanceof EntityMonster && e.getGroupId() == groupId)
.count();
logger.debug("[LUA] Call GetGroupMonsterCountByGroupId with {} = {}", groupId, returnValue);
return returnValue;
}
public int GetGroupSuite(int groupId) {
@ -860,13 +862,15 @@ public class ScriptLib {
}
public int GetGroupVariableValue(String var) {
logger.debug("[LUA] Call GetGroupVariableValue with {}", var);
return getSceneScriptManager().getVariables(currentGroup.get().id).getOrDefault(var, 0);
int returnValue = getSceneScriptManager().getVariables(currentGroup.get().id).getOrDefault(var, 0);
logger.debug("[LUA] Call GetGroupVariableValue with {} = {}", var, returnValue);
return returnValue;
}
public int GetGroupVariableValueByGroup(String var, int groupId) {
logger.debug("[LUA] Call GetGroupVariableValueByGroup with {},{}", var, groupId);
return getSceneScriptManager().getVariables(groupId).getOrDefault(var, 0);
int returnValue = getSceneScriptManager().getVariables(groupId).getOrDefault(var, 0);
logger.debug("[LUA] Call GetGroupVariableValueByGroup with {},{} = {}", var, groupId, returnValue);
return returnValue;
}
// TODO: GetHideAndSeekHunter
@ -1105,7 +1109,7 @@ public class ScriptLib {
if (configId == LuaValue.NIL) {
return 1;
}
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId.toint());
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId.toint(), getCurrentGroup().get().id);
if (entity == null) {
return 0;
}
@ -1342,7 +1346,7 @@ public class ScriptLib {
var scriptManager = this.getSceneScriptManager();
if (scriptManager == null) return 1;
var scene = scriptManager.getScene();
var entity = scene.getEntityByConfigId(cfgId);
var entity = scene.getEntityByConfigId(cfgId, getCurrentGroup().get().id);
if (entity == null) return 2;
scene.runWhenHostInitialized(() -> scene.broadcastPacket(
new PacketServerGlobalValueChangeNotify(entity, sgvName, value)));
@ -1380,8 +1384,8 @@ public class ScriptLib {
// TODO: SetGadgetHp
public int SetGadgetStateByConfigId(int configId, int gadgetState) {
logger.debug("[LUA] Call SetGadgetStateByConfigId with {},{}", configId, gadgetState);
GameEntity entity = getSceneScriptManager().getScene().getEntityByConfigId(configId);
logger.debug("[LUA] Call SetGadgetStateByConfigId with {},{}, current group {}", configId, gadgetState, getCurrentGroup().get().id);
GameEntity entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, getCurrentGroup().get().id);
if (!(entity instanceof EntityGadget gadget)) {
return 1;
}
@ -1477,7 +1481,7 @@ public class ScriptLib {
// var3 might contain the next point, sometimes is a single int, sometimes multiple ints as array
// var4 has RouteType route_type, bool turn_mode
val entity = getSceneScriptManager().getScene().getEntityByConfigId(entityConfigId);
val entity = getSceneScriptManager().getScene().getEntityByConfigId(entityConfigId, getCurrentGroup().get().id);
if (entity == null) {
return 1;
}
@ -1507,7 +1511,7 @@ public class ScriptLib {
public int SetPlatformRouteId(int entityConfigId, int routeId) {
logger.debug("[LUA] Call SetPlatformRouteId {} {}", entityConfigId, routeId);
val entity = getSceneScriptManager().getScene().getEntityByConfigId(entityConfigId);
val entity = getSceneScriptManager().getScene().getEntityByConfigId(entityConfigId, getCurrentGroup().get().id);
if (entity == null) {
return 1;
}
@ -1584,7 +1588,7 @@ public class ScriptLib {
return 1;
}
var configId = callParams.param1;
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId);
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, getCurrentGroup().get().id);
var worktopOptions = new int[table.length()];
for (int i = 1; i <= table.length(); i++) {
@ -1679,7 +1683,7 @@ public class ScriptLib {
public int StartPlatform(int configId) {
logger.debug("[LUA] Call StartPlatform {} ", configId);
val entity = sceneScriptManager.get().getScene().getEntityByConfigId(configId);
val entity = sceneScriptManager.get().getScene().getEntityByConfigId(configId, getCurrentGroup().get().id);
if (!(entity instanceof EntityGadget entityGadget)) {
return 1;
}
@ -1714,7 +1718,7 @@ public class ScriptLib {
public int StopPlatform(int configId) {
logger.debug("[LUA] Call StopPlatform {} ", configId);
val entity = sceneScriptManager.get().getScene().getEntityByConfigId(configId);
val entity = sceneScriptManager.get().getScene().getEntityByConfigId(configId, getCurrentGroup().get().id);
if (!(entity instanceof EntityGadget entityGadget)) {
return 1;
}
@ -1787,7 +1791,19 @@ public class ScriptLib {
// TODO: TryRecordActivityPushTips
// TODO: TrySetPlayerEyePoint
// TODO: UnfreezeGroupLimit
public int UnfreezeGroupLimit(int dungeonEntryId) {
// Note: dungeonEntryId is also named pointId elsewhere in GC.
logger.debug("[LUA] Call UnfreezeGroupLimit with {}", dungeonEntryId);
var scene = sceneScriptManager.get().getScene();
scene.getPlayers().get(0).sendPacket(new PacketUnfreezeGroupLimitNotify(
dungeonEntryId,
scene.getId()));
return 0;
}
// TODO: UnhideScenePoint
public int UnlockFloatSignal(int groupId, int gadgetSignalId) {

View File

@ -0,0 +1,15 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.*;
import emu.grasscutter.net.proto.DungeonRestartReqOuterClass.DungeonRestartReq;
import emu.grasscutter.net.proto.DungeonRestartRspOuterClass.DungeonRestartRsp;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.DungeonRestartReq)
public class HandlerDungeonRestartReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
session.getPlayer().getServer().getDungeonSystem().restartDungeon(session.getPlayer());
session.getPlayer().sendPacket(new BasePacket(PacketOpcodes.DungeonRestartRsp));
}
}

View File

@ -0,0 +1,27 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.net.packet.*;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketGetDungeonEntryExploreConditionRsp;
import emu.grasscutter.server.packet.send.PacketDungeonEntryToBeExploreNotify;
import emu.grasscutter.net.proto.GetDungeonEntryExploreConditionReqOuterClass.GetDungeonEntryExploreConditionReq;
@Opcodes(PacketOpcodes.GetDungeonEntryExploreConditionReq)
public class HandlerGetDungeonEntryExploreConditionReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = GetDungeonEntryExploreConditionReq.parseFrom(payload);
// TODO Send GetDungeonEntryExploreConditionRsp if condition
// (adventurer rank or quest completion) is not met. Parse
// dungeon entry conditions from DungeonEntryExcelConfigData.json.
//session.send(new PacketGetDungeonEntryExploreConditionRsp(req.getDungeonEntryConfigId()));
// For now, just unlock any domain the player touches.
session.send(new PacketDungeonEntryToBeExploreNotify(
req.getDungeonEntryScenePointId(),
req.getSceneId(),
req.getDungeonEntryConfigId()));
}
}

View File

@ -0,0 +1,20 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.*;
import emu.grasscutter.net.proto.DungeonEntryToBeExploreNotifyOuterClass.DungeonEntryToBeExploreNotify;
public class PacketDungeonEntryToBeExploreNotify extends BasePacket {
/**
* Marks the dungeon as pending exploration.
* This creates the "Unknown" text bubble above the dungeon entry in the world map.
*/
public PacketDungeonEntryToBeExploreNotify(int dungeonEntryScenePointId, int sceneId, int dungeonEntryConfigId) {
super(PacketOpcodes.DungeonEntryToBeExploreNotify);
this.setData(DungeonEntryToBeExploreNotify.newBuilder()
.setDungeonEntryScenePointId(dungeonEntryScenePointId)
.setSceneId(sceneId)
.setDungeonEntryConfigId(dungeonEntryConfigId)
);
}
}

View File

@ -0,0 +1,31 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.data.GameData;
import emu.grasscutter.net.packet.*;
import emu.grasscutter.net.proto.GetDungeonEntryExploreConditionRspOuterClass.GetDungeonEntryExploreConditionRsp;
import emu.grasscutter.net.proto.DungeonEntryCondOuterClass.DungeonEntryCond;
import emu.grasscutter.net.proto.DungeonEntryBlockReasonOuterClass.DungeonEntryBlockReason;
public class PacketGetDungeonEntryExploreConditionRsp extends BasePacket {
public PacketGetDungeonEntryExploreConditionRsp(int dungeonId) {
super(PacketOpcodes.GetDungeonEntryExploreConditionRsp);
var data = GameData.getDungeonEntryDataMap().values().stream()
.filter(d -> d.getId() == dungeonId)
.toList().get(0);
var level = data.getLevelCondition();
var quest = data.getQuestCondition();
var proto = GetDungeonEntryExploreConditionRsp.newBuilder()
.setRetcode(0)
.setDungeonEntryCond(DungeonEntryCond.newBuilder()
// There is also a DUNGEON_ENTRY_REASON_MULIPLE but only one param1
// field to put values in. Only report the required level for now, then.
.setCondReason(DungeonEntryBlockReason.DUNGEON_ENTRY_REASON_LEVEL)
.setParam1(level)
)
.build();
this.setData(proto);
}
}

View File

@ -12,6 +12,11 @@ public class PacketPostEnterSceneRsp extends BasePacket {
PostEnterSceneRsp p =
PostEnterSceneRsp.newBuilder().setEnterSceneToken(player.getEnterSceneToken()).build();
//
// On moving to new scene:
// Unfreeze dungeon entry points that have already been unlocked in this scene.
player.unfreezeUnlockedScenePoints();
this.setData(p);
}
}

View File

@ -0,0 +1,14 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.*;
import emu.grasscutter.net.proto.UnfreezeGroupLimitNotifyOuterClass.UnfreezeGroupLimitNotify;
public class PacketUnfreezeGroupLimitNotify extends BasePacket {
public PacketUnfreezeGroupLimitNotify(int pointId, int sceneId) {
super(PacketOpcodes.UnfreezeGroupLimitNotify);
this.setData(UnfreezeGroupLimitNotify.newBuilder()
.setPointId(pointId)
.setSceneId(sceneId)
);
}
}