Skip to content
Snippets Groups Projects
Commit 791b9534 authored by Akka's avatar Akka Committed by Melledy
Browse files

refactor the challenge

parent 717c2d1d
Branches
Tags
No related merge requests found
Showing
with 592 additions and 47 deletions
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,48 +50,22 @@ public class DungeonChallenge { ...@@ -113,48 +50,22 @@ 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();
......
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
...@@ -590,21 +599,21 @@ public class Scene { ...@@ -590,21 +599,21 @@ public class Scene {
if (suite == 0 || group.suites == null || group.suites.size() == 0) { if (suite == 0 || group.suites == null || group.suites.size() == 0) {
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);
entities.addAll(suiteData.sceneGadgets.stream() entities.addAll(suiteData.sceneGadgets.stream()
.map(g -> scriptManager.createGadget(group.id, group.block_id, g)).toList()); .map(g -> scriptManager.createGadget(group.id, group.block_id, g)).toList());
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) {
...@@ -205,7 +204,17 @@ public class SceneScriptManager { ...@@ -205,7 +204,17 @@ 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);
}
} }
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