Commit 791b9534 authored by Akka's avatar Akka Committed by Melledy
Browse files

refactor the challenge

parent 717c2d1d
package emu.grasscutter.game.dungeons; package emu.grasscutter.game.dungeons.challenge;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.def.DungeonData; import emu.grasscutter.data.def.DungeonData;
import emu.grasscutter.game.entity.EntityMonster; import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.ActionReason;
...@@ -10,9 +10,6 @@ import emu.grasscutter.game.world.Scene; ...@@ -10,9 +10,6 @@ import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.ScriptArgs; import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify; import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
...@@ -20,79 +17,23 @@ import it.unimi.dsi.fastutil.ints.IntSet; ...@@ -20,79 +17,23 @@ import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class DungeonChallenge { public class DungeonChallenge extends WorldChallenge {
private final Scene scene;
private final SceneGroup group;
private int challengeIndex;
private int challengeId;
private boolean success;
private boolean progress;
/** /**
* has more challenge * has more challenge
*/ */
private boolean stage; private boolean stage;
private int score;
private int objective = 0;
private IntSet rewardedPlayers; private IntSet rewardedPlayers;
public DungeonChallenge(Scene scene, SceneGroup group, int challengeId, int challengeIndex, int objective) { public DungeonChallenge(Scene scene, SceneGroup group,
this.scene = scene; int challengeId, int challengeIndex,
this.group = group; List<Integer> paramList,
this.challengeId = challengeId; int timeLimit, int goal,
this.challengeIndex = challengeIndex; List<ChallengeTrigger> challengeTriggers) {
this.objective = objective; super(scene, group, challengeId, challengeIndex, paramList, timeLimit, goal, challengeTriggers);
this.setRewardedPlayers(new IntOpenHashSet()); this.setRewardedPlayers(new IntOpenHashSet());
} }
public Scene getScene() {
return scene;
}
public SceneGroup getGroup() {
return group;
}
public int getChallengeIndex() {
return challengeIndex;
}
public void setChallengeIndex(int challengeIndex) {
this.challengeIndex = challengeIndex;
}
public int getChallengeId() {
return challengeId;
}
public void setChallengeId(int challengeId) {
this.challengeId = challengeId;
}
public int getObjective() {
return objective;
}
public void setObjective(int objective) {
this.objective = objective;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean isSuccess) {
this.success = isSuccess;
}
public boolean inProgress() {
return progress;
}
public int getScore() {
return score;
}
public boolean isStage() { public boolean isStage() {
return stage; return stage;
} }
...@@ -101,10 +42,6 @@ public class DungeonChallenge { ...@@ -101,10 +42,6 @@ public class DungeonChallenge {
this.stage = stage; this.stage = stage;
} }
public int getTimeLimit() {
return 600;
}
public IntSet getRewardedPlayers() { public IntSet getRewardedPlayers() {
return rewardedPlayers; return rewardedPlayers;
} }
...@@ -113,49 +50,23 @@ public class DungeonChallenge { ...@@ -113,49 +50,23 @@ public class DungeonChallenge {
this.rewardedPlayers = rewardedPlayers; this.rewardedPlayers = rewardedPlayers;
} }
public void start() { @Override
this.progress = true; public void done() {
getScene().broadcastPacket(new PacketDungeonChallengeBeginNotify(this)); super.done();
}
public void finish() {
this.progress = false;
getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this));
if (this.isSuccess()) { if (this.isSuccess()) {
// Call success script event
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_SUCCESS,
// TODO record the time in PARAM2 and used in action
new ScriptArgs().setParam2(100));
// Settle // Settle
settle(); settle();
} else {
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_FAIL, null);
} }
} }
private void settle() { private void settle() {
getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene()));
if(!stage){ if(!stage){
getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene()));
getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE,
new ScriptArgs(this.isSuccess() ? 1 : 0)); new ScriptArgs(this.isSuccess() ? 1 : 0));
} }
} }
public void onMonsterDie(EntityMonster entity) {
score = getScore() + 1;
getScene().broadcastPacket(new PacketChallengeDataNotify(this, 1, getScore()));
if (getScore() >= getObjective() && this.progress) {
this.setSuccess(true);
finish();
}
}
public void getStatueDrops(Player player) { public void getStatueDrops(Player player) {
DungeonData dungeonData = getScene().getDungeonData(); DungeonData dungeonData = getScene().getDungeonData();
if (!isSuccess() || dungeonData == null || dungeonData.getRewardPreview() == null || dungeonData.getRewardPreview().getPreviewItems().length == 0) { if (!isSuccess() || dungeonData == null || dungeonData.getRewardPreview() == null || dungeonData.getRewardPreview().getPreviewItems().length == 0) {
......
package emu.grasscutter.game.dungeons.challenge;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Getter
@Setter
public class WorldChallenge {
private final Scene scene;
private final SceneGroup group;
private final int challengeId;
private final int challengeIndex;
private final List<Integer> paramList;
private final int timeLimit;
private final List<ChallengeTrigger> challengeTriggers;
private boolean progress;
private boolean success;
private long startedAt;
private int finishedTime;
private final int goal;
private final AtomicInteger score;
public WorldChallenge(Scene scene, SceneGroup group,
int challengeId, int challengeIndex, List<Integer> paramList,
int timeLimit, int goal,
List<ChallengeTrigger> challengeTriggers){
this.scene = scene;
this.group = group;
this.challengeId = challengeId;
this.challengeIndex = challengeIndex;
this.paramList = paramList;
this.timeLimit = timeLimit;
this.challengeTriggers = challengeTriggers;
this.goal = goal;
this.score = new AtomicInteger(0);
}
public boolean inProgress(){
return this.progress;
}
public void onCheckTimeOut(){
if(!inProgress()){
return;
}
if(timeLimit <= 0){
return;
}
challengeTriggers.forEach(t -> t.onCheckTimeout(this));
}
public void start(){
if(inProgress()){
Grasscutter.getLogger().info("Could not start a in progress challenge.");
return;
}
this.progress = true;
this.startedAt = System.currentTimeMillis();
getScene().broadcastPacket(new PacketDungeonChallengeBeginNotify(this));
challengeTriggers.forEach(t -> t.onBegin(this));
}
public void done(){
if(!inProgress()){
return;
}
finish(true);
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_SUCCESS,
// TODO record the time in PARAM2 and used in action
new ScriptArgs().setParam2(finishedTime));
challengeTriggers.forEach(t -> t.onFinish(this));
}
public void fail(){
if(!inProgress()){
return;
}
finish(false);
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_FAIL, null);
challengeTriggers.forEach(t -> t.onFinish(this));
}
private void finish(boolean success){
this.progress = false;
this.success = success;
this.finishedTime = (int)((System.currentTimeMillis() - this.startedAt) / 1000L);
getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this));
}
public int increaseScore(){
return score.incrementAndGet();
}
public void onMonsterDeath(EntityMonster monster){
if(!inProgress()){
return;
}
if(monster.getGroupId() != getGroup().id){
return;
}
this.challengeTriggers.forEach(t -> t.onMonsterDeath(this, monster));
}
public void onGadgetDeath(EntityGadget gadget){
if(!inProgress()){
return;
}
if(gadget.getGroupId() != getGroup().id){
return;
}
this.challengeTriggers.forEach(t -> t.onGadgetDeath(this, gadget));
}
public void onGadgetDamage(EntityGadget gadget){
if(!inProgress()){
return;
}
if(gadget.getGroupId() != getGroup().id){
return;
}
this.challengeTriggers.forEach(t -> t.onGadgetDamage(this, gadget));
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.ArrayList;
import java.util.List;
public class ChallengeFactory {
private static final List<ChallengeFactoryHandler> challengeFactoryHandlers = new ArrayList<>();
static {
challengeFactoryHandlers.add(new DungeonChallengeFactoryHandler());
challengeFactoryHandlers.add(new DungeonGuardChallengeFactoryHandler());
challengeFactoryHandlers.add(new KillGadgetChallengeFactoryHandler());
challengeFactoryHandlers.add(new KillMonsterChallengeFactoryHandler());
}
public static WorldChallenge getChallenge(int param1, int param2, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group){
for(var handler : challengeFactoryHandlers){
if(!handler.isThisType(param1, param2, param3, param4, param5, param6, scene, group)){
continue;
}
return handler.build(param1, param2, param3, param4, param5, param6, scene, group);
}
return null;
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
public interface ChallengeFactoryHandler {
boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group);
WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group);
}
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
public class DungeonChallengeFactoryHandler implements ChallengeFactoryHandler{
@Override
public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
// ActiveChallenge with 1,1000,300,233101003,15,0
return scene.getSceneType() == SceneType.SCENE_DUNGEON
&& param4 == group.id;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
var realGroup = scene.getScriptManager().getGroupById(param4);
return new DungeonChallenge(
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(param5, param3),
param3, // Limit
param5, // Goal
List.of(new InTimeTrigger(), new KillMonsterTrigger()));
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.trigger.GuardTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
public class DungeonGuardChallengeFactoryHandler implements ChallengeFactoryHandler{
@Override
public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
// ActiveChallenge with 1,188,234101003,12,3030,0
return scene.getSceneType() == SceneType.SCENE_DUNGEON
&& param3 == group.id;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
var realGroup = scene.getScriptManager().getGroupById(param3);
return new DungeonChallenge(
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(param4, 0),
0, // Limit
param5, // Goal
List.of(new GuardTrigger()));
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.factory.ChallengeFactoryHandler;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillGadgetTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
public class KillGadgetChallengeFactoryHandler implements ChallengeFactoryHandler {
@Override
public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
// kill gadgets(explosive barrel) in time
// ActiveChallenge with 56,201,20,2,201,4
// open chest in time
// ActiveChallenge with 666,202,30,7,202,1
return challengeId == 201 || challengeId == 202;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
return new WorldChallenge(
scene, group,
challengeId, // Id
challengeIndex, // Index
List.of(param3, param6, 0),
param3, // Limit
param6, // Goal
List.of(new InTimeTrigger(), new KillGadgetTrigger())
);
}
}
package emu.grasscutter.game.dungeons.challenge.factory;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.scripts.data.SceneGroup;
import java.util.List;
public class KillMonsterChallengeFactoryHandler implements ChallengeFactoryHandler{
@Override
public boolean isThisType(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
// ActiveChallenge with 180,180,45,133108061,1,0
return challengeId == 180;
}
@Override
public WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group) {
var realGroup = scene.getScriptManager().getGroupById(param4);
return new WorldChallenge(
scene, realGroup,
challengeId, // Id
challengeIndex, // Index
List.of(param5, param3),
param3, // Limit
param5, // Goal
List.of(new KillMonsterTrigger(), new InTimeTrigger())
);
}
}
package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityMonster;
public abstract class ChallengeTrigger {
public void onBegin(WorldChallenge challenge){}
public void onFinish(WorldChallenge challenge){}
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster){}
public void onGadgetDeath(WorldChallenge challenge, EntityGadget gadget){}
public void onCheckTimeout(WorldChallenge challenge){}
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget){}
}
package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
public class GuardTrigger extends KillMonsterTrigger{
@Override
public void onBegin(WorldChallenge challenge) {
super.onBegin(challenge);
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, 100));
}
@Override
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) {
var curHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_CUR_HP.getId());
var maxHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_BASE_HP.getId());
int percent = (int) (curHp / maxHp);
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, percent));
if(percent <= 0){
challenge.fail();
}
}
}
package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
public class InTimeTrigger extends ChallengeTrigger{
@Override
public void onCheckTimeout(WorldChallenge challenge) {
var current = System.currentTimeMillis();
if(current - challenge.getStartedAt() > challenge.getTimeLimit() * 1000L){
challenge.fail();
}
}
}
package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
public class KillGadgetTrigger extends ChallengeTrigger{
@Override
public void onBegin(WorldChallenge challenge) {
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, challenge.getScore().get()));
}
@Override
public void onGadgetDeath(WorldChallenge challenge, EntityGadget gadget) {
var newScore = challenge.increaseScore();
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, newScore));
if(newScore >= challenge.getGoal()){
challenge.done();
}
}
}
package emu.grasscutter.game.dungeons.challenge.trigger;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
public class KillMonsterTrigger extends ChallengeTrigger{
@Override
public void onBegin(WorldChallenge challenge) {
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 1, challenge.getScore().get()));
}
@Override
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) {
var newScore = challenge.increaseScore();
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 1, newScore));
if(newScore >= challenge.getGoal()){
challenge.done();
}
}
}
package emu.grasscutter.game.entity; package emu.grasscutter.game.entity;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.def.GadgetData; import emu.grasscutter.data.def.GadgetData;
import emu.grasscutter.game.entity.gadget.GadgetChest; import emu.grasscutter.data.def.GadgetPropData;
import emu.grasscutter.game.entity.gadget.GadgetContent; import emu.grasscutter.game.entity.gadget.*;
import emu.grasscutter.game.entity.gadget.GadgetGatherPoint; import emu.grasscutter.game.props.*;
import emu.grasscutter.game.entity.gadget.GadgetRewardStatue;
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
...@@ -32,6 +24,7 @@ import emu.grasscutter.scripts.constants.EventType; ...@@ -32,6 +24,7 @@ import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneGadget; import emu.grasscutter.scripts.data.SceneGadget;
import emu.grasscutter.scripts.data.ScriptArgs; import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify; import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.ProtoHelper; import emu.grasscutter.utils.ProtoHelper;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
...@@ -160,7 +153,10 @@ public class EntityGadget extends EntityBaseGadget { ...@@ -160,7 +153,10 @@ public class EntityGadget extends EntityBaseGadget {
@Override @Override
public void onDeath(int killerId) { public void onDeath(int killerId) {
if(getScene().getChallenge() != null){
getScene().getChallenge().onGadgetDeath(this);
}
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_GADGET_DIE, new ScriptArgs(this.getConfigId()));
} }
@Override @Override
...@@ -203,4 +199,8 @@ public class EntityGadget extends EntityBaseGadget { ...@@ -203,4 +199,8 @@ public class EntityGadget extends EntityBaseGadget {
return entityInfo.build(); return entityInfo.build();
} }
public void die() {
getScene().broadcastPacket(new PacketLifeStateChangeNotify(this, LifeState.LIFE_DEAD));
this.onDeath(0);
}
} }
...@@ -122,8 +122,8 @@ public class EntityMonster extends GameEntity { ...@@ -122,8 +122,8 @@ public class EntityMonster extends GameEntity {
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry()); this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
} }
// first set the challenge data // first set the challenge data
if (getScene().getChallenge() != null && getScene().getChallenge().getGroup().id == this.getGroupId()) { if (getScene().getChallenge() != null) {
getScene().getChallenge().onMonsterDie(this); getScene().getChallenge().onMonsterDeath(this);
} }
if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) { if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) {
if(getScene().getScriptManager().getScriptMonsterSpawnService() != null){ if(getScene().getScriptManager().getScriptMonsterSpawnService() != null){
......
...@@ -38,6 +38,8 @@ public class GadgetChest extends GadgetContent { ...@@ -38,6 +38,8 @@ public class GadgetChest extends GadgetContent {
getGadget().updateState(ScriptGadgetState.ChestOpened); getGadget().updateState(ScriptGadgetState.ChestOpened);
player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_OPEN_CHEST)); player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_OPEN_CHEST));
// let the chest disappear
getGadget().die();
return true; return true;
} }
} }
......
package emu.grasscutter.game.entity.gadget; package emu.grasscutter.game.entity.gadget;
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
import emu.grasscutter.game.entity.EntityGadget; import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.InterOpTypeOuterClass; import emu.grasscutter.net.proto.InterOpTypeOuterClass;
...@@ -14,8 +15,8 @@ public class GadgetRewardStatue extends GadgetContent { ...@@ -14,8 +15,8 @@ public class GadgetRewardStatue extends GadgetContent {
} }
public boolean onInteract(Player player, InterOpTypeOuterClass.InterOpType opType) { public boolean onInteract(Player player, InterOpTypeOuterClass.InterOpType opType) {
if (player.getScene().getChallenge() != null) { if (player.getScene().getChallenge() != null && player.getScene().getChallenge() instanceof DungeonChallenge dungeonChallenge) {
player.getScene().getChallenge().getStatueDrops(player); dungeonChallenge.getStatueDrops(player);
} }
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_OPEN_STATUE)); player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_OPEN_STATUE));
......
package emu.grasscutter.game.entity.gadget.chest; package emu.grasscutter.game.entity.gadget.chest;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.game.entity.gadget.GadgetChest; import emu.grasscutter.game.entity.gadget.GadgetChest;
import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.GameItem;
...@@ -22,6 +23,10 @@ public class BossChestInteractHandler implements ChestInteractHandler{ ...@@ -22,6 +23,10 @@ public class BossChestInteractHandler implements ChestInteractHandler{
var monster = chest.getGadget().getMetaGadget().group.monsters.get(chest.getGadget().getMetaGadget().boss_chest.monster_config_id); var monster = chest.getGadget().getMetaGadget().group.monsters.get(chest.getGadget().getMetaGadget().boss_chest.monster_config_id);
var reward = worldDataManager.getRewardByBossId(monster.monster_id); var reward = worldDataManager.getRewardByBossId(monster.monster_id);
if(reward == null){
Grasscutter.getLogger().warn("Could not found the reward of boss monster {}", monster.monster_id);
return false;
}
List<GameItem> rewards = new ArrayList<>(); List<GameItem> rewards = new ArrayList<>();
for (ItemParamData param : reward.getPreviewItems()) { for (ItemParamData param : reward.getPreviewItems()) {
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1))); rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
......
...@@ -4,7 +4,6 @@ import emu.grasscutter.Grasscutter; ...@@ -4,7 +4,6 @@ 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.*; import emu.grasscutter.data.def.*;
import emu.grasscutter.game.dungeons.DungeonChallenge;
import emu.grasscutter.game.dungeons.DungeonSettleListener; import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.entity.*; import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
...@@ -14,6 +13,7 @@ import emu.grasscutter.game.props.FightProperty; ...@@ -14,6 +13,7 @@ import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.LifeState; import emu.grasscutter.game.props.LifeState;
import emu.grasscutter.game.props.SceneType; import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry; import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
...@@ -32,8 +32,6 @@ import org.danilopianini.util.SpatialIndex; ...@@ -32,8 +32,6 @@ import org.danilopianini.util.SpatialIndex;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static emu.grasscutter.utils.Language.translate;
public class Scene { public class Scene {
private final World world; private final World world;
private final SceneData sceneData; private final SceneData sceneData;
...@@ -51,7 +49,7 @@ public class Scene { ...@@ -51,7 +49,7 @@ public class Scene {
private int weather; private int weather;
private SceneScriptManager scriptManager; private SceneScriptManager scriptManager;
private DungeonChallenge challenge; private WorldChallenge challenge;
private List<DungeonSettleListener> dungeonSettleListeners; private List<DungeonSettleListener> dungeonSettleListeners;
private DungeonData dungeonData; private DungeonData dungeonData;
private int prevScene; // Id of the previous scene private int prevScene; // Id of the previous scene
...@@ -199,11 +197,11 @@ public class Scene { ...@@ -199,11 +197,11 @@ public class Scene {
this.dungeonData = dungeonData; this.dungeonData = dungeonData;
} }
public DungeonChallenge getChallenge() { public WorldChallenge getChallenge() {
return challenge; return challenge;
} }
public void setChallenge(DungeonChallenge challenge) { public void setChallenge(WorldChallenge challenge) {
this.challenge = challenge; this.challenge = challenge;
} }
...@@ -353,7 +351,14 @@ public class Scene { ...@@ -353,7 +351,14 @@ public class Scene {
this.broadcastPacket(new PacketSceneEntityDisappearNotify(removed, visionType)); this.broadcastPacket(new PacketSceneEntityDisappearNotify(removed, visionType));
} }
} }
public synchronized void removeEntities(List<GameEntity> entity, VisionType visionType) {
var toRemove = entity.stream()
.map(this::removeEntityDirectly)
.toList();
if (toRemove.size() > 0) {
this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, visionType));
}
}
public synchronized void replaceEntity(EntityAvatar oldEntity, EntityAvatar newEntity) { public synchronized void replaceEntity(EntityAvatar oldEntity, EntityAvatar newEntity) {
this.removeEntityDirectly(oldEntity); this.removeEntityDirectly(oldEntity);
this.addEntityDirectly(newEntity); this.addEntityDirectly(newEntity);
...@@ -418,6 +423,10 @@ public class Scene { ...@@ -418,6 +423,10 @@ public class Scene {
} }
// Triggers // Triggers
this.scriptManager.checkRegions(); this.scriptManager.checkRegions();
if(challenge != null){
challenge.onCheckTimeOut();
}
} }
// TODO - Test // TODO - Test
...@@ -591,7 +600,7 @@ public class Scene { ...@@ -591,7 +600,7 @@ public class Scene {
continue; continue;
} }
do { // just load the 'init' suite, avoid spawn the suite added by AddExtraGroupSuite etc.
var suiteData = group.getSuiteByIndex(suite); var suiteData = group.getSuiteByIndex(suite);
suiteData.sceneTriggers.forEach(getScriptManager()::registerTrigger); suiteData.sceneTriggers.forEach(getScriptManager()::registerTrigger);
...@@ -600,11 +609,11 @@ public class Scene { ...@@ -600,11 +609,11 @@ public class Scene {
entities.addAll(suiteData.sceneMonsters.stream() entities.addAll(suiteData.sceneMonsters.stream()
.map(mob -> scriptManager.createMonster(group.id, group.block_id, mob)).toList()); .map(mob -> scriptManager.createMonster(group.id, group.block_id, mob)).toList());
suite++;
} while (suite < group.init_config.end_suite);
} }
scriptManager.meetEntities(entities); scriptManager.meetEntities(entities);
//scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null);
//groups.forEach(g -> scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null));
Grasscutter.getLogger().info("Scene {} loaded {} group(s)", this.getId(), groups.size()); Grasscutter.getLogger().info("Scene {} loaded {} group(s)", this.getId(), groups.size());
} }
......
...@@ -26,16 +26,13 @@ import java.util.concurrent.ExecutorService; ...@@ -26,16 +26,13 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class SceneScriptManager { public class SceneScriptManager {
private final Scene scene; private final Scene scene;
private final Map<String, Integer> variables; private final Map<String, Integer> variables;
private SceneMeta meta; private SceneMeta meta;
private boolean isInit; private boolean isInit;
/**
* SceneTrigger Set
*/
private final Map<String, SceneTrigger> triggers;
/** /**
* current triggers controlled by RefreshGroup * current triggers controlled by RefreshGroup
*/ */
...@@ -51,12 +48,11 @@ public class SceneScriptManager { ...@@ -51,12 +48,11 @@ public class SceneScriptManager {
public static final ExecutorService eventExecutor; public static final ExecutorService eventExecutor;
static { static {
eventExecutor = new ThreadPoolExecutor(4, 4, eventExecutor = new ThreadPoolExecutor(4, 4,
60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100), 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000),
FastThreadLocalThread::new, new ThreadPoolExecutor.AbortPolicy()); FastThreadLocalThread::new, new ThreadPoolExecutor.AbortPolicy());
} }
public SceneScriptManager(Scene scene) { public SceneScriptManager(Scene scene) {
this.scene = scene; this.scene = scene;
this.triggers = new HashMap<>();
this.currentTriggers = new Int2ObjectOpenHashMap<>(); this.currentTriggers = new Int2ObjectOpenHashMap<>();
this.regions = new Int2ObjectOpenHashMap<>(); this.regions = new Int2ObjectOpenHashMap<>();
...@@ -96,13 +92,16 @@ public class SceneScriptManager { ...@@ -96,13 +92,16 @@ public class SceneScriptManager {
public Set<SceneTrigger> getTriggersByEvent(int eventId) { public Set<SceneTrigger> getTriggersByEvent(int eventId) {
return currentTriggers.computeIfAbsent(eventId, e -> new HashSet<>()); return currentTriggers.computeIfAbsent(eventId, e -> new HashSet<>());
} }
public void registerTrigger(List<SceneTrigger> triggers) {
triggers.forEach(this::registerTrigger);
}
public void registerTrigger(SceneTrigger trigger) { public void registerTrigger(SceneTrigger trigger) {
this.triggers.put(trigger.name, trigger);
getTriggersByEvent(trigger.event).add(trigger); getTriggersByEvent(trigger.event).add(trigger);
} }
public void deregisterTrigger(List<SceneTrigger> triggers) {
triggers.forEach(this::deregisterTrigger);
}
public void deregisterTrigger(SceneTrigger trigger) { public void deregisterTrigger(SceneTrigger trigger) {
this.triggers.remove(trigger.name);
getTriggersByEvent(trigger.event).remove(trigger); getTriggersByEvent(trigger.event).remove(trigger);
} }
public void resetTriggers(int eventId) { public void resetTriggers(int eventId) {
...@@ -206,6 +205,16 @@ public class SceneScriptManager { ...@@ -206,6 +205,16 @@ public class SceneScriptManager {
} }
} }
public void addGroupSuite(SceneGroup group, SceneSuite suite){
spawnMonstersInGroup(group, suite);
spawnGadgetsInGroup(group, suite);
registerTrigger(suite.sceneTriggers);
}
public void removeGroupSuite(SceneGroup group, SceneSuite suite){
removeMonstersInGroup(group, suite);
removeGadgetsInGroup(group, suite);
deregisterTrigger(suite.sceneTriggers);
}
public void spawnGadgetsInGroup(SceneGroup group, int suiteIndex) { public void spawnGadgetsInGroup(SceneGroup group, int suiteIndex) {
spawnGadgetsInGroup(group, group.getSuiteByIndex(suiteIndex)); spawnGadgetsInGroup(group, group.getSuiteByIndex(suiteIndex));
} }
...@@ -241,7 +250,6 @@ public class SceneScriptManager { ...@@ -241,7 +250,6 @@ public class SceneScriptManager {
} }
this.addEntities(suite.sceneMonsters.stream() this.addEntities(suite.sceneMonsters.stream()
.map(mob -> createMonster(group.id, group.block_id, mob)).toList()); .map(mob -> createMonster(group.id, group.block_id, mob)).toList());
} }
public void spawnMonstersInGroup(SceneGroup group) { public void spawnMonstersInGroup(SceneGroup group) {
...@@ -326,7 +334,7 @@ public class SceneScriptManager { ...@@ -326,7 +334,7 @@ public class SceneScriptManager {
try{ try{
return func.call(ScriptLoader.getScriptLibLua(), args); return func.call(ScriptLoader.getScriptLibLua(), args);
}catch (LuaError error){ }catch (LuaError error){
ScriptLib.logger.error("[LUA] call trigger failed {},{},{}",name,args,error.getMessage()); ScriptLib.logger.error("[LUA] call trigger failed {},{}",name,args,error);
return LuaValue.valueOf(-1); return LuaValue.valueOf(-1);
} }
} }
...@@ -388,6 +396,7 @@ public class SceneScriptManager { ...@@ -388,6 +396,7 @@ public class SceneScriptManager {
entity.setGroupId(groupId); entity.setGroupId(groupId);
entity.setBlockId(blockId); entity.setBlockId(blockId);
entity.setConfigId(monster.config_id); entity.setConfigId(monster.config_id);
entity.setPoseId(monster.pose_id);
this.getScriptMonsterSpawnService() this.getScriptMonsterSpawnService()
.onMonsterCreatedListener.forEach(action -> action.onNotify(entity)); .onMonsterCreatedListener.forEach(action -> action.onNotify(entity));
...@@ -410,4 +419,28 @@ public class SceneScriptManager { ...@@ -410,4 +419,28 @@ public class SceneScriptManager {
public PhTree<SceneBlock> getBlocksIndex() { public PhTree<SceneBlock> getBlocksIndex() {
return meta.sceneBlockIndex; return meta.sceneBlockIndex;
} }
public void removeMonstersInGroup(SceneGroup group, SceneSuite suite) {
var configSet = suite.sceneMonsters.stream()
.map(m -> m.config_id)
.collect(Collectors.toSet());
var toRemove = getScene().getEntities().values().stream()
.filter(e -> e instanceof EntityMonster)
.filter(e -> e.getGroupId() == group.id)
.filter(e -> configSet.contains(e.getConfigId()))
.toList();
getScene().removeEntities(toRemove, VisionTypeOuterClass.VisionType.VISION_MISS);
}
public void removeGadgetsInGroup(SceneGroup group, SceneSuite suite) {
var configSet = suite.sceneGadgets.stream()
.map(m -> m.config_id)
.collect(Collectors.toSet());
var toRemove = getScene().getEntities().values().stream()
.filter(e -> e instanceof EntityGadget)
.filter(e -> e.getGroupId() == group.id)
.filter(e -> configSet.contains(e.getConfigId()))
.toList();
getScene().removeEntities(toRemove, VisionTypeOuterClass.VisionType.VISION_MISS);
}
} }
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