mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-26 20:05:19 +00:00
Support Boss Chest
This commit is contained in:
parent
5429469852
commit
717c2d1dd7
@ -79,6 +79,7 @@ public class GameData {
|
||||
private static final Int2ObjectMap<TowerFloorData> towerFloorDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<TowerLevelData> towerLevelDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<TowerScheduleData> towerScheduleDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
// Cache
|
||||
private static Map<Integer, List<Integer>> fetters = new HashMap<>();
|
||||
@ -352,4 +353,8 @@ public class GameData {
|
||||
public static Int2ObjectMap<GatherData> getGatherDataMap() {
|
||||
return gatherDataMap;
|
||||
}
|
||||
public static Int2ObjectMap<InvestigationMonsterData> getInvestigationMonsterDataMap() {
|
||||
return investigationMonsterDataMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ResourceType(name = "InvestigationMonsterConfigData.json")
|
||||
@Data
|
||||
public class InvestigationMonsterData extends GameResource {
|
||||
private int Id;
|
||||
private int CityId;
|
||||
private List<Integer> MonsterIdList;
|
||||
private List<Integer> GroupIdList;
|
||||
private int RewardPreviewId;
|
||||
private String MapMarkCreateType;
|
||||
private String MonsterCategory;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
super.onLoad();
|
||||
}
|
||||
}
|
@ -125,7 +125,9 @@ public class DungeonChallenge {
|
||||
|
||||
if (this.isSuccess()) {
|
||||
// Call success script event
|
||||
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_SUCCESS, null);
|
||||
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_SUCCESS,
|
||||
// TODO record the time in PARAM2 and used in action
|
||||
new ScriptArgs().setParam2(100));
|
||||
|
||||
// Settle
|
||||
settle();
|
||||
@ -139,8 +141,7 @@ public class DungeonChallenge {
|
||||
|
||||
if(!stage){
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE,
|
||||
// TODO record the time in PARAM2 and used in action
|
||||
new ScriptArgs(this.isSuccess() ? 1 : 0, 100));
|
||||
new ScriptArgs(this.isSuccess() ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.SceneGadget;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
|
||||
import emu.grasscutter.utils.Position;
|
||||
@ -51,6 +52,7 @@ public class EntityGadget extends EntityBaseGadget {
|
||||
private int state;
|
||||
private int pointType;
|
||||
private GadgetContent content;
|
||||
private SceneGadget metaGadget;
|
||||
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
||||
super(scene);
|
||||
@ -99,6 +101,7 @@ public class EntityGadget extends EntityBaseGadget {
|
||||
public void updateState(int state){
|
||||
this.setState(state);
|
||||
this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state));
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_STATE_CHANGE, new ScriptArgs(state, this.getConfigId()));
|
||||
}
|
||||
|
||||
public int getPointType() {
|
||||
@ -117,7 +120,15 @@ public class EntityGadget extends EntityBaseGadget {
|
||||
public void setContent(GadgetContent content) {
|
||||
this.content = this.content == null ? content : this.content;
|
||||
}
|
||||
|
||||
|
||||
public SceneGadget getMetaGadget() {
|
||||
return metaGadget;
|
||||
}
|
||||
|
||||
public void setMetaGadget(SceneGadget metaGadget) {
|
||||
this.metaGadget = metaGadget;
|
||||
}
|
||||
|
||||
// TODO refactor
|
||||
public void buildContent() {
|
||||
if (getContent() != null || getGadgetData() == null || getGadgetData().getType() == null) {
|
||||
|
@ -1,53 +1,63 @@
|
||||
package emu.grasscutter.game.entity.gadget;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.proto.BossChestInfoOuterClass.BossChestInfo;
|
||||
import emu.grasscutter.net.proto.InterOpTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.InteractTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.scripts.constants.ScriptGadgetState;
|
||||
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
||||
|
||||
import static emu.grasscutter.net.proto.InterOpTypeOuterClass.InterOpType.INTER_OP_START;
|
||||
|
||||
public class GadgetChest extends GadgetContent {
|
||||
|
||||
public GadgetChest(EntityGadget gadget) {
|
||||
super(gadget);
|
||||
}
|
||||
|
||||
public boolean onInteract(Player player) {
|
||||
var chestRewardMap = getGadget().getScene().getWorld().getServer().getWorldDataManager().getChestRewardMap();
|
||||
var chestReward = chestRewardMap.get(getGadget().getGadgetData().getJsonName());
|
||||
if (chestReward == null) {
|
||||
Grasscutter.getLogger().warn("Could not found the config of this type of Chests {}", getGadget().getGadgetData().getJsonName());
|
||||
public boolean onInteract(Player player, InterOpTypeOuterClass.InterOpType opType) {
|
||||
var chestInteractHandlerMap = getGadget().getScene().getWorld().getServer().getWorldDataManager().getChestInteractHandlerMap();
|
||||
var handler = chestInteractHandlerMap.get(getGadget().getGadgetData().getJsonName());
|
||||
if(handler == null){
|
||||
Grasscutter.getLogger().warn("Could not found the handler of this type of Chests {}", getGadget().getGadgetData().getJsonName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(opType == INTER_OP_START && handler.isTwoStep()){
|
||||
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_OPEN_CHEST, INTER_OP_START));
|
||||
return false;
|
||||
}else{
|
||||
var success = handler.onInteract(this, player);
|
||||
if (!success){
|
||||
return false;
|
||||
}
|
||||
|
||||
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
||||
player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_OPEN_CHEST));
|
||||
return true;
|
||||
}
|
||||
|
||||
player.earnExp(chestReward.getAdvExp());
|
||||
player.getInventory().addItem(201, chestReward.getResin());
|
||||
|
||||
var mora = chestReward.getMora() * (1 + (player.getWorldLevel() - 1) * 0.5);
|
||||
player.getInventory().addItem(202, (int)mora);
|
||||
|
||||
for(int i=0;i<chestReward.getContent().size();i++){
|
||||
getGadget().getScene().addItemEntity(chestReward.getContent().get(i).getItemId(), chestReward.getContent().get(i).getCount(), getGadget());
|
||||
}
|
||||
|
||||
var random = new Random(System.currentTimeMillis());
|
||||
for(int i=0;i<chestReward.getRandomCount();i++){
|
||||
var index = random.nextInt(chestReward.getRandomContent().size());
|
||||
var item = chestReward.getRandomContent().get(index);
|
||||
getGadget().getScene().addItemEntity(item.getItemId(), item.getCount(), getGadget());
|
||||
}
|
||||
|
||||
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
||||
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_OPEN_CHEST));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {
|
||||
if(getGadget().getMetaGadget() == null){
|
||||
return;
|
||||
}
|
||||
|
||||
var bossChest = getGadget().getMetaGadget().boss_chest;
|
||||
if(bossChest != null){
|
||||
var players = getGadget().getScene().getPlayers().stream().map(Player::getUid).toList();
|
||||
|
||||
gadgetInfo.setBossChest(BossChestInfo.newBuilder()
|
||||
.setMonsterConfigId(bossChest.monster_config_id)
|
||||
.setResin(bossChest.resin)
|
||||
.addAllQualifyUidList(players)
|
||||
.addAllRemainUidList(players)
|
||||
.build());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package emu.grasscutter.game.entity.gadget;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.proto.InterOpTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
|
||||
public abstract class GadgetContent {
|
||||
@ -15,7 +16,7 @@ public abstract class GadgetContent {
|
||||
return gadget;
|
||||
}
|
||||
|
||||
public abstract boolean onInteract(Player player);
|
||||
public abstract boolean onInteract(Player player, InterOpTypeOuterClass.InterOpType opType);
|
||||
|
||||
public abstract void onBuildProto(SceneGadgetInfo.Builder gadgetInfo);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.net.proto.GatherGadgetInfoOuterClass.GatherGadgetInfo;
|
||||
import emu.grasscutter.net.proto.InterOpTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
|
||||
public class GadgetGatherPoint extends GadgetContent {
|
||||
@ -25,7 +26,7 @@ public class GadgetGatherPoint extends GadgetContent {
|
||||
return getGatherData().getItemId();
|
||||
}
|
||||
|
||||
public boolean onInteract(Player player) {
|
||||
public boolean onInteract(Player player, InterOpTypeOuterClass.InterOpType opType) {
|
||||
GameItem item = new GameItem(gatherData.getItemId(), 1);
|
||||
|
||||
player.getInventory().addItem(item, ActionReason.Gather);
|
||||
|
@ -2,6 +2,7 @@ package emu.grasscutter.game.entity.gadget;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.proto.InterOpTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
||||
@ -12,7 +13,7 @@ public class GadgetRewardStatue extends GadgetContent {
|
||||
super(gadget);
|
||||
}
|
||||
|
||||
public boolean onInteract(Player player) {
|
||||
public boolean onInteract(Player player, InterOpTypeOuterClass.InterOpType opType) {
|
||||
if (player.getScene().getChallenge() != null) {
|
||||
player.getScene().getChallenge().getStatueDrops(player);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import java.util.Arrays;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.proto.InterOpTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
@ -34,7 +35,7 @@ public class GadgetWorktop extends GadgetContent {
|
||||
this.worktopOptions.remove(option);
|
||||
}
|
||||
|
||||
public boolean onInteract(Player player) {
|
||||
public boolean onInteract(Player player, InterOpTypeOuterClass.InterOpType opType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,35 @@
|
||||
package emu.grasscutter.game.entity.gadget.chest;
|
||||
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.game.entity.gadget.GadgetChest;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BossChestInteractHandler implements ChestInteractHandler{
|
||||
@Override
|
||||
public boolean isTwoStep() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInteract(GadgetChest chest, Player player) {
|
||||
var worldDataManager = chest.getGadget().getScene().getWorld().getServer().getWorldDataManager();
|
||||
var monster = chest.getGadget().getMetaGadget().group.monsters.get(chest.getGadget().getMetaGadget().boss_chest.monster_config_id);
|
||||
var reward = worldDataManager.getRewardByBossId(monster.monster_id);
|
||||
|
||||
List<GameItem> rewards = new ArrayList<>();
|
||||
for (ItemParamData param : reward.getPreviewItems()) {
|
||||
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
|
||||
}
|
||||
|
||||
player.getInventory().addItems(rewards, ActionReason.OpenWorldBossChest);
|
||||
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package emu.grasscutter.game.entity.gadget.chest;
|
||||
|
||||
import emu.grasscutter.game.entity.gadget.GadgetChest;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
public interface ChestInteractHandler {
|
||||
|
||||
boolean isTwoStep();
|
||||
|
||||
boolean onInteract(GadgetChest chest, Player player);
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package emu.grasscutter.game.entity.gadget.chest;
|
||||
|
||||
import emu.grasscutter.game.entity.gadget.GadgetChest;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.world.ChestReward;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class NormalChestInteractHandler implements ChestInteractHandler {
|
||||
private final ChestReward chestReward;
|
||||
|
||||
public NormalChestInteractHandler(ChestReward rewardData){
|
||||
this.chestReward = rewardData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTwoStep() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInteract(GadgetChest chest, Player player) {
|
||||
player.earnExp(chestReward.getAdvExp());
|
||||
player.getInventory().addItem(201, chestReward.getResin());
|
||||
|
||||
var mora = chestReward.getMora() * (1 + (player.getWorldLevel() - 1) * 0.5);
|
||||
player.getInventory().addItem(202, (int)mora);
|
||||
|
||||
for(int i=0;i<chestReward.getContent().size();i++){
|
||||
chest.getGadget().getScene().addItemEntity(chestReward.getContent().get(i).getItemId(), chestReward.getContent().get(i).getCount(), chest.getGadget());
|
||||
}
|
||||
|
||||
var random = new Random(System.currentTimeMillis());
|
||||
for(int i=0;i<chestReward.getRandomCount();i++){
|
||||
var index = random.nextInt(chestReward.getRandomContent().size());
|
||||
var item = chestReward.getRandomContent().get(index);
|
||||
chest.getGadget().getScene().addItemEntity(item.getItemId(), item.getCount(), chest.getGadget());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -25,11 +25,8 @@ import emu.grasscutter.game.mail.MailHandler;
|
||||
import emu.grasscutter.game.managers.StaminaManager.StaminaManager;
|
||||
import emu.grasscutter.game.managers.SotSManager;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.EntityType;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
import emu.grasscutter.game.quest.GameMainQuest;
|
||||
import emu.grasscutter.game.quest.GameQuest;
|
||||
import emu.grasscutter.game.quest.QuestManager;
|
||||
import emu.grasscutter.game.shop.ShopLimit;
|
||||
import emu.grasscutter.game.managers.MapMarkManager.*;
|
||||
@ -47,7 +44,6 @@ import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo;
|
||||
import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo;
|
||||
import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
|
||||
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
|
||||
import emu.grasscutter.scripts.constants.ScriptGadgetState;
|
||||
import emu.grasscutter.server.event.player.PlayerJoinEvent;
|
||||
import emu.grasscutter.server.event.player.PlayerQuitEvent;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
@ -890,7 +886,7 @@ public class Player {
|
||||
return this.getMailHandler().replaceMailByIndex(index, message);
|
||||
}
|
||||
|
||||
public void interactWith(int gadgetEntityId) {
|
||||
public void interactWith(int gadgetEntityId, InterOpTypeOuterClass.InterOpType opType) {
|
||||
GameEntity entity = getScene().getEntityById(gadgetEntityId);
|
||||
|
||||
if (entity == null) {
|
||||
@ -923,7 +919,7 @@ public class Player {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean shouldDelete = gadget.getContent().onInteract(this);
|
||||
boolean shouldDelete = gadget.getContent().onInteract(this, opType);
|
||||
|
||||
if (shouldDelete) {
|
||||
entity.getScene().removeEntity(entity);
|
||||
|
@ -3,42 +3,60 @@ package emu.grasscutter.game.world;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.DataLoader;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.RewardPreviewData;
|
||||
import emu.grasscutter.game.entity.gadget.chest.BossChestInteractHandler;
|
||||
import emu.grasscutter.game.entity.gadget.chest.ChestInteractHandler;
|
||||
import emu.grasscutter.game.entity.gadget.chest.NormalChestInteractHandler;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static emu.grasscutter.Configuration.DATA;
|
||||
|
||||
public class WorldDataManager {
|
||||
private final GameServer gameServer;
|
||||
private final Map<String, ChestReward> chestRewardMap;
|
||||
private final Map<String, ChestInteractHandler> chestInteractHandlerMap; // chestType-Handler
|
||||
|
||||
public WorldDataManager(GameServer gameServer){
|
||||
this.gameServer = gameServer;
|
||||
this.chestRewardMap = new HashMap<>();
|
||||
load();
|
||||
this.chestInteractHandlerMap = new HashMap<>();
|
||||
loadChestConfig();
|
||||
}
|
||||
|
||||
public synchronized void load(){
|
||||
public synchronized void loadChestConfig(){
|
||||
// set the special chest first
|
||||
chestInteractHandlerMap.put("SceneObj_Chest_Flora", new BossChestInteractHandler());
|
||||
|
||||
try(InputStream is = DataLoader.load("ChestReward.json"); InputStreamReader isr = new InputStreamReader(is)) {
|
||||
List<ChestReward> chestReward = Grasscutter.getGsonFactory().fromJson(
|
||||
isr,
|
||||
TypeToken.getParameterized(List.class, ChestReward.class).getType());
|
||||
|
||||
chestReward.forEach(reward ->
|
||||
reward.getObjNames().forEach(name -> chestRewardMap.put(name, reward)));
|
||||
reward.getObjNames().forEach(
|
||||
name -> chestInteractHandlerMap.putIfAbsent(name, new NormalChestInteractHandler(reward))));
|
||||
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error("Unable to load chest reward config.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, ChestReward> getChestRewardMap() {
|
||||
return chestRewardMap;
|
||||
public Map<String, ChestInteractHandler> getChestInteractHandlerMap() {
|
||||
return chestInteractHandlerMap;
|
||||
}
|
||||
|
||||
public RewardPreviewData getRewardByBossId(int monsterId){
|
||||
var investigationMonsterData = GameData.getInvestigationMonsterDataMap().values().parallelStream()
|
||||
.filter(imd -> imd.getMonsterIdList() != null && !imd.getMonsterIdList().isEmpty())
|
||||
.filter(imd -> imd.getMonsterIdList().get(0) == monsterId)
|
||||
.findFirst();
|
||||
|
||||
if(investigationMonsterData.isEmpty()){
|
||||
return null;
|
||||
}
|
||||
return GameData.getRewardPreviewDataMap().get(investigationMonsterData.get().getRewardPreviewId());
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.*;
|
||||
import emu.grasscutter.scripts.service.ScriptMonsterSpawnService;
|
||||
import emu.grasscutter.scripts.service.ScriptMonsterTideService;
|
||||
import io.netty.util.concurrent.FastThreadLocalThread;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.luaj.vm2.LuaError;
|
||||
@ -21,6 +22,10 @@ import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class SceneScriptManager {
|
||||
private final Scene scene;
|
||||
@ -43,6 +48,12 @@ public class SceneScriptManager {
|
||||
* blockid - loaded groupSet
|
||||
*/
|
||||
private Int2ObjectMap<Set<SceneGroup>> loadedGroupSetPerBlock;
|
||||
public static final ExecutorService eventExecutor;
|
||||
static {
|
||||
eventExecutor = new ThreadPoolExecutor(4, 4,
|
||||
60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100),
|
||||
FastThreadLocalThread::new, new ThreadPoolExecutor.AbortPolicy());
|
||||
}
|
||||
public SceneScriptManager(Scene scene) {
|
||||
this.scene = scene;
|
||||
this.triggers = new HashMap<>();
|
||||
@ -211,7 +222,7 @@ public class SceneScriptManager {
|
||||
}
|
||||
|
||||
var toCreate = gadgets.stream()
|
||||
.map(g -> createGadget(g.groupId, group.block_id, g))
|
||||
.map(g -> createGadget(g.group.id, group.block_id, g))
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
this.addEntities(toCreate);
|
||||
@ -254,8 +265,17 @@ public class SceneScriptManager {
|
||||
getScene().addEntity(createMonster(group.id, group.block_id, group.monsters.get(configId)));
|
||||
}
|
||||
// Events
|
||||
|
||||
public void callEvent(int eventType, ScriptArgs params) {
|
||||
public void callEvent(int eventType, ScriptArgs params){
|
||||
/**
|
||||
* We use ThreadLocal to trans SceneScriptManager context to ScriptLib, to avoid eval script for every groups' trigger in every scene instances.
|
||||
* But when callEvent is called in a ScriptLib func, it may cause NPE because the inner call cleans the ThreadLocal so that outer call could not get it.
|
||||
* e.g. CallEvent -> set -> ScriptLib.xxx -> CallEvent -> set -> remove -> NPE -> (remove)
|
||||
* So we use thread pool to clean the stack to avoid this new issue.
|
||||
*/
|
||||
eventExecutor.submit(() -> this.realCallEvent(eventType, params));
|
||||
}
|
||||
|
||||
private void realCallEvent(int eventType, ScriptArgs params) {
|
||||
try{
|
||||
ScriptLoader.getScriptLib().setSceneScriptManager(this);
|
||||
for (SceneTrigger trigger : this.getTriggersByEvent(eventType)) {
|
||||
@ -282,7 +302,7 @@ public class SceneScriptManager {
|
||||
}
|
||||
}
|
||||
|
||||
public LuaValue callScriptFunc(String funcName, SceneGroup group, ScriptArgs params){
|
||||
private LuaValue callScriptFunc(String funcName, SceneGroup group, ScriptArgs params){
|
||||
LuaValue funcLua = null;
|
||||
if (funcName != null && !funcName.isEmpty()) {
|
||||
funcLua = (LuaValue) group.getBindings().get(funcName);
|
||||
@ -332,10 +352,8 @@ public class SceneScriptManager {
|
||||
entity.getRotation().set(g.rot);
|
||||
entity.setState(g.state);
|
||||
entity.setPointType(g.point_type);
|
||||
entity.setMetaGadget(g);
|
||||
entity.buildContent();
|
||||
|
||||
// Lua event
|
||||
this.callEvent(EventType.EVENT_GADGET_CREATE, new ScriptArgs(entity.getConfigId()));
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import emu.grasscutter.game.entity.gadget.GadgetWorktop;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.SceneRegion;
|
||||
import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify;
|
||||
import io.netty.util.concurrent.FastThreadLocal;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
@ -16,7 +15,6 @@ import org.luaj.vm2.LuaValue;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ScriptLib {
|
||||
@ -68,34 +66,24 @@ public class ScriptLib {
|
||||
if (entity.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(entity.get() instanceof EntityGadget)) {
|
||||
return 1;
|
||||
|
||||
if (entity.get() instanceof EntityGadget entityGadget) {
|
||||
entityGadget.updateState(gadgetState);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EntityGadget gadget = (EntityGadget) entity.get();
|
||||
gadget.setState(gadgetState);
|
||||
|
||||
getSceneScriptManager().getScene().broadcastPacket(new PacketGadgetStateNotify(gadget, gadgetState));
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int SetGroupGadgetStateByConfigId(int groupId, int configId, int gadgetState) {
|
||||
logger.debug("[LUA] Call SetGroupGadgetStateByConfigId with {},{},{}",
|
||||
groupId,configId,gadgetState);
|
||||
List<GameEntity> list = getSceneScriptManager().getScene().getEntities().values().stream()
|
||||
.filter(e -> e.getGroupId() == groupId).toList();
|
||||
|
||||
for (GameEntity entity : list) {
|
||||
if (!(entity instanceof EntityGadget)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityGadget gadget = (EntityGadget) entity;
|
||||
gadget.setState(gadgetState);
|
||||
|
||||
getSceneScriptManager().getScene().broadcastPacket(new PacketGadgetStateNotify(gadget, gadgetState));
|
||||
}
|
||||
|
||||
getSceneScriptManager().getScene().getEntities().values().stream()
|
||||
.filter(e -> e.getGroupId() == groupId)
|
||||
.filter(e -> e instanceof EntityGadget)
|
||||
.map(e -> (EntityGadget)e)
|
||||
.forEach(e -> e.updateState(gadgetState));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -450,8 +438,9 @@ public class ScriptLib {
|
||||
|
||||
if (entity instanceof EntityGadget entityGadget) {
|
||||
entityGadget.updateState(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Setter
|
||||
@ToString
|
||||
public class SceneBossChest {
|
||||
public int life_time;
|
||||
public int monster_config_id;
|
||||
public int resin;
|
||||
public int take_num;
|
||||
}
|
@ -9,4 +9,5 @@ public class SceneGadget extends SceneObject{
|
||||
public int gadget_id;
|
||||
public int state;
|
||||
public int point_type;
|
||||
public SceneBossChest boss_chest;
|
||||
}
|
||||
|
@ -98,11 +98,11 @@ public class SceneGroup {
|
||||
// Set
|
||||
monsters = ScriptLoader.getSerializer().toList(SceneMonster.class, bindings.get("monsters")).stream()
|
||||
.collect(Collectors.toMap(x -> x.config_id, y -> y));
|
||||
monsters.values().forEach(m -> m.groupId = id);
|
||||
monsters.values().forEach(m -> m.group = this);
|
||||
|
||||
gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, bindings.get("gadgets")).stream()
|
||||
.collect(Collectors.toMap(x -> x.config_id, y -> y));
|
||||
gadgets.values().forEach(m -> m.groupId = id);
|
||||
gadgets.values().forEach(m -> m.group = this);
|
||||
|
||||
triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, bindings.get("triggers")).stream()
|
||||
.collect(Collectors.toMap(x -> x.name, y -> y));
|
||||
|
@ -16,5 +16,5 @@ public class SceneObject {
|
||||
/**
|
||||
* not set by lua
|
||||
*/
|
||||
public transient int groupId;
|
||||
public transient SceneGroup group;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ public class HandlerGadgetInteractReq extends PacketHandler {
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
GadgetInteractReq req = GadgetInteractReq.parseFrom(payload);
|
||||
|
||||
session.getPlayer().interactWith(req.getGadgetEntityId());
|
||||
session.getPlayer().interactWith(req.getGadgetEntityId(), req.getOpType());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.GetInvestigationMonsterReqOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketGetInvestigationMonsterRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.GetInvestigationMonsterReq)
|
||||
public class HandlerGetInvestigationMonsterReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req = GetInvestigationMonsterReqOuterClass.GetInvestigationMonsterReq.parseFrom(payload);
|
||||
|
||||
session.send(new PacketGetInvestigationMonsterRsp(req.getCityIdListList()));
|
||||
}
|
||||
|
||||
}
|
@ -4,20 +4,27 @@ import emu.grasscutter.game.entity.EntityBaseGadget;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.GadgetInteractRspOuterClass.GadgetInteractRsp;
|
||||
import emu.grasscutter.net.proto.InterOpTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||
|
||||
public class PacketGadgetInteractRsp extends BasePacket {
|
||||
public PacketGadgetInteractRsp(EntityBaseGadget gadget, InteractType interact) {
|
||||
this(gadget, interact, null);
|
||||
}
|
||||
public PacketGadgetInteractRsp(EntityBaseGadget gadget, InteractType interact, InterOpTypeOuterClass.InterOpType opType) {
|
||||
super(PacketOpcodes.GadgetInteractRsp);
|
||||
|
||||
GadgetInteractRsp proto = GadgetInteractRsp.newBuilder()
|
||||
var proto = GadgetInteractRsp.newBuilder()
|
||||
.setGadgetEntityId(gadget.getId())
|
||||
.setInteractType(interact)
|
||||
.setGadgetId(gadget.getGadgetId())
|
||||
.build();
|
||||
.setGadgetId(gadget.getGadgetId());
|
||||
|
||||
if(opType != null){
|
||||
proto.setOpType(opType);
|
||||
}
|
||||
|
||||
this.setData(proto);
|
||||
this.setData(proto.build());
|
||||
}
|
||||
|
||||
public PacketGadgetInteractRsp() {
|
||||
|
@ -0,0 +1,20 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.GetActivityInfoRspOuterClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PacketGetInvestigationMonsterRsp extends BasePacket {
|
||||
|
||||
public PacketGetInvestigationMonsterRsp(List<Integer> cityIdListList) {
|
||||
super(PacketOpcodes.GetInvestigationMonsterRsp);
|
||||
|
||||
var resp = GetActivityInfoRspOuterClass.GetActivityInfoRsp.newBuilder();
|
||||
|
||||
|
||||
|
||||
this.setData(resp.build());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user