MonsterInvestigation (boss icon in map)

This commit is contained in:
Akka 2022-06-18 19:07:39 +08:00 committed by Melledy
parent d1606eb7d0
commit fe2799c1fd
10 changed files with 176 additions and 43 deletions

View File

@ -2,15 +2,11 @@ syntax = "proto3";
option java_package = "emu.grasscutter.net.proto"; option java_package = "emu.grasscutter.net.proto";
// CmdId: 1902
// EnetChannelId: 0
// EnetIsReliable: true
// IsAllowClient: true
message GetInvestigationMonsterReq { message GetInvestigationMonsterReq {
enum CmdId { repeated uint32 city_id_list = 13;
option allow_alias = true; bool ABFECCDJENJ = 11;
ENET_CHANNEL_ID = 0;
NONE = 0;
ENET_IS_RELIABLE = 1;
IS_ALLOW_CLIENT = 1;
CMD_ID = 1916;
}
repeated uint32 city_id_list = 1;
} }

View File

@ -4,16 +4,12 @@ option java_package = "emu.grasscutter.net.proto";
import "InvestigationMonster.proto"; import "InvestigationMonster.proto";
// CmdId: 1911
// EnetChannelId: 0
// EnetIsReliable: true
// IsAllowClient: true
message GetInvestigationMonsterRsp { message GetInvestigationMonsterRsp {
enum CmdId { int32 retcode = 9;
option allow_alias = true; repeated InvestigationMonster monster_list = 7;
ENET_CHANNEL_ID = 0; bool ABFECCDJENJ = 10;
NONE = 0;
ENET_IS_RELIABLE = 1;
IS_ALLOW_CLIENT = 1;
CMD_ID = 1928;
}
int32 retcode = 1;
repeated InvestigationMonster monster_list = 2;
} }

View File

@ -2,14 +2,9 @@ syntax = "proto3";
option java_package = "emu.grasscutter.net.proto"; option java_package = "emu.grasscutter.net.proto";
// CmdId: 3476
// EnetChannelId: 0
// EnetIsReliable: true
message GroupSuiteNotify { message GroupSuiteNotify {
enum CmdId { map<uint32, uint32> group_map = 11;
option allow_alias = true;
NONE = 0;
ENET_CHANNEL_ID = 0;
ENET_IS_RELIABLE = 1;
CMD_ID = 3098;
}
map<uint32, uint32> group_map = 1;
} }

View File

@ -93,6 +93,7 @@ public class GameData {
private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<FurnitureMakeConfigData> furnitureMakeConfigDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<FurnitureMakeConfigData> furnitureMakeConfigDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<CityData> cityDataMap = new Int2ObjectOpenHashMap<>();
// Cache // Cache
private static Map<Integer, List<Integer>> fetters = new HashMap<>(); private static Map<Integer, List<Integer>> fetters = new HashMap<>();
@ -411,4 +412,8 @@ public class GameData {
public static Int2ObjectMap<InvestigationMonsterData> getInvestigationMonsterDataMap() { public static Int2ObjectMap<InvestigationMonsterData> getInvestigationMonsterDataMap() {
return investigationMonsterDataMap; return investigationMonsterDataMap;
} }
public static Int2ObjectMap<CityData> getCityDataMap() {
return cityDataMap;
}
} }

View File

@ -0,0 +1,30 @@
package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
import java.util.List;
@ResourceType(name = "CityConfigData.json", loadPriority = ResourceType.LoadPriority.HIGH)
@Getter
@Setter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class CityData extends GameResource {
int cityId;
int sceneId;
List<Integer> areaIdVec;
@Override
public int getId() {
return this.cityId;
}
@Override
public void onLoad() {
super.onLoad();
}
}

View File

@ -1,22 +1,28 @@
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import lombok.AccessLevel;
import lombok.Data; import lombok.Data;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
import java.util.List; import java.util.List;
@ResourceType(name = "InvestigationMonsterConfigData.json") @ResourceType(name = "InvestigationMonsterConfigData.json", loadPriority = ResourceType.LoadPriority.LOW)
@Data @Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class InvestigationMonsterData extends GameResource { public class InvestigationMonsterData extends GameResource {
private int id; int id;
private int cityId; int cityId;
private List<Integer> monsterIdList; List<Integer> monsterIdList;
private List<Integer> groupIdList; List<Integer> groupIdList;
private int rewardPreviewId; int rewardPreviewId;
private String mapMarkCreateType; String mapMarkCreateType;
private String monsterCategory; String monsterCategory;
CityData cityData;
@Override @Override
public int getId() { public int getId() {
return this.id; return this.id;
@ -24,6 +30,6 @@ public class InvestigationMonsterData extends GameResource {
@Override @Override
public void onLoad() { public void onLoad() {
super.onLoad(); this.cityData = GameData.getCityDataMap().get(cityId);
} }
} }

View File

@ -4,10 +4,16 @@ import com.google.gson.reflect.TypeToken;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.DataLoader; import emu.grasscutter.data.DataLoader;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.InvestigationMonsterData;
import emu.grasscutter.data.excels.RewardPreviewData; import emu.grasscutter.data.excels.RewardPreviewData;
import emu.grasscutter.data.excels.WorldLevelData;
import emu.grasscutter.game.entity.gadget.chest.BossChestInteractHandler; import emu.grasscutter.game.entity.gadget.chest.BossChestInteractHandler;
import emu.grasscutter.game.entity.gadget.chest.ChestInteractHandler; import emu.grasscutter.game.entity.gadget.chest.ChestInteractHandler;
import emu.grasscutter.game.entity.gadget.chest.NormalChestInteractHandler; import emu.grasscutter.game.entity.gadget.chest.NormalChestInteractHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.proto.InvestigationMonsterOuterClass;
import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.SceneMonster;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
import java.io.InputStream; import java.io.InputStream;
@ -15,14 +21,19 @@ import java.io.InputStreamReader;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
public class WorldDataManager { public class WorldDataManager {
private final GameServer gameServer; private final GameServer gameServer;
private final Map<String, ChestInteractHandler> chestInteractHandlerMap; // chestType-Handler private final Map<String, ChestInteractHandler> chestInteractHandlerMap; // chestType-Handler
private final Map<String, SceneGroup> sceneInvestigationGroupMap; // <sceneId_groupId, Group>
public WorldDataManager(GameServer gameServer){ public WorldDataManager(GameServer gameServer){
this.gameServer = gameServer; this.gameServer = gameServer;
this.chestInteractHandlerMap = new HashMap<>(); this.chestInteractHandlerMap = new HashMap<>();
this.sceneInvestigationGroupMap = new ConcurrentHashMap<>();
loadChestConfig(); loadChestConfig();
} }
@ -59,4 +70,80 @@ public class WorldDataManager {
} }
return GameData.getRewardPreviewDataMap().get(investigationMonsterData.get().getRewardPreviewId()); return GameData.getRewardPreviewDataMap().get(investigationMonsterData.get().getRewardPreviewId());
} }
private SceneGroup getInvestigationGroup(int sceneId, int groupId){
var key = sceneId + "_" + groupId;
if(!sceneInvestigationGroupMap.containsKey(key)){
var group = SceneGroup.of(groupId).load(sceneId);
sceneInvestigationGroupMap.putIfAbsent(key, group);
return group;
}
return sceneInvestigationGroupMap.get(key);
}
public int getMonsterLevel(SceneMonster monster, World world){
// Calculate level
int level = monster.level;
WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(world.getWorldLevel());
if (worldLevelData != null) {
level = worldLevelData.getMonsterLevel();
}
return level;
}
private InvestigationMonsterOuterClass.InvestigationMonster getInvestigationMonster(Player player, InvestigationMonsterData imd) {
var groupId = imd.getGroupIdList().get(0);
var monsterId = imd.getMonsterIdList().get(0);
var sceneId = imd.getCityData().getSceneId();
var group = getInvestigationGroup(sceneId, groupId);
if(group == null || group.monsters == null){
return null;
}
var monster = group.monsters.values().stream()
.filter(x -> x.monster_id == monsterId)
.findFirst();
if(monster.isEmpty()){
return null;
}
var builder = InvestigationMonsterOuterClass.InvestigationMonster.newBuilder();
builder.setId(imd.getId())
.setCityId(imd.getCityId())
.setSceneId(imd.getCityData().getSceneId())
.setGroupId(groupId)
.setMonsterId(monsterId)
.setLevel(getMonsterLevel(monster.get(), player.getWorld()))
.setIsAlive(true)
.setNextRefreshTime(Integer.MAX_VALUE)
.setRefreshInterval(Integer.MAX_VALUE)
.setPos(monster.get().pos.toProto());
if("Boss".equals(imd.getMonsterCategory())){
var bossChest = group.searchBossChestInGroup();
if(bossChest.isPresent()){
builder.setResin(bossChest.get().resin);
builder.setBossChestNum(bossChest.get().take_num);
}
}
return builder.build();
}
public List<InvestigationMonsterOuterClass.InvestigationMonster> getInvestigationMonstersByCityId(Player player, int cityId){
var cityData = GameData.getCityDataMap().get(cityId);
if(cityData == null){
Grasscutter.getLogger().warn("City not exist {}", cityId);
return List.of();
}
return GameData.getInvestigationMonsterDataMap().values()
.parallelStream()
.filter(imd -> imd.getCityId() == cityId)
.map(imd -> this.getInvestigationMonster(player, imd))
.filter(Objects::nonNull)
.toList();
}
} }

View File

@ -16,6 +16,7 @@ import org.luaj.vm2.LuaValue;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static emu.grasscutter.Configuration.SCRIPT; import static emu.grasscutter.Configuration.SCRIPT;
@ -165,4 +166,12 @@ public class SceneGroup {
Grasscutter.getLogger().info("group {} in scene {} is loaded successfully.", id, sceneId); Grasscutter.getLogger().info("group {} in scene {} is loaded successfully.", id, sceneId);
return this; return this;
} }
public Optional<SceneBossChest> searchBossChestInGroup() {
return gadgets.values().stream()
.filter(g -> g.boss_chest != null && g.boss_chest.monster_config_id > 0)
.map(g -> g.boss_chest)
.findFirst();
}
} }

View File

@ -14,7 +14,11 @@ public class HandlerGetInvestigationMonsterReq extends PacketHandler {
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = GetInvestigationMonsterReqOuterClass.GetInvestigationMonsterReq.parseFrom(payload); var req = GetInvestigationMonsterReqOuterClass.GetInvestigationMonsterReq.parseFrom(payload);
session.send(new PacketGetInvestigationMonsterRsp(req.getCityIdListList())); session.send(new PacketGetInvestigationMonsterRsp(
session.getPlayer(),
session.getServer().getWorldDataManager(),
req.getCityIdListList()));
} }
} }

View File

@ -1,18 +1,23 @@
package emu.grasscutter.server.packet.send; package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.world.WorldDataManager;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.GetActivityInfoRspOuterClass; import emu.grasscutter.net.proto.GetActivityInfoRspOuterClass;
import emu.grasscutter.net.proto.GetInvestigationMonsterRspOuterClass;
import java.util.List; import java.util.List;
public class PacketGetInvestigationMonsterRsp extends BasePacket { public class PacketGetInvestigationMonsterRsp extends BasePacket {
public PacketGetInvestigationMonsterRsp(List<Integer> cityIdListList) { public PacketGetInvestigationMonsterRsp(Player player, WorldDataManager worldDataManager, List<Integer> cityIdListList) {
super(PacketOpcodes.GetInvestigationMonsterRsp); super(PacketOpcodes.GetInvestigationMonsterRsp);
var resp = GetActivityInfoRspOuterClass.GetActivityInfoRsp.newBuilder(); var resp = GetInvestigationMonsterRspOuterClass.GetInvestigationMonsterRsp.newBuilder();
cityIdListList.forEach(id -> resp.addAllMonsterList(worldDataManager.getInvestigationMonstersByCityId(player, id)));
this.setData(resp.build()); this.setData(resp.build());