Choose Avatar & Enter Tower

This commit is contained in:
Akka 2022-05-06 14:10:23 +08:00 committed by Melledy
parent 744aa478a9
commit 696f629080
22 changed files with 495 additions and 13 deletions

View File

@ -0,0 +1,16 @@
syntax = "proto3";
option java_package = "emu.grasscutter.net.proto";
message TowerBuffSelectReq {
enum CmdId {
option allow_alias = true;
ENET_CHANNEL_ID = 0;
NONE = 0;
ENET_IS_RELIABLE = 1;
IS_ALLOW_CLIENT = 1;
CMD_ID = 2424;
}
uint32 tower_buff_id = 1;
}

View File

@ -0,0 +1,16 @@
syntax = "proto3";
option java_package = "emu.grasscutter.net.proto";
message TowerBuffSelectRsp {
enum CmdId {
option allow_alias = true;
NONE = 0;
ENET_CHANNEL_ID = 0;
ENET_IS_RELIABLE = 1;
CMD_ID = 2491;
}
int32 retcode = 1;
uint32 tower_buff_id = 2;
}

View File

@ -0,0 +1,17 @@
syntax = "proto3";
option java_package = "emu.grasscutter.net.proto";
import "TowerCurLevelRecord.proto";
message TowerCurLevelRecordChangeNotify {
enum CmdId {
option allow_alias = true;
NONE = 0;
ENET_CHANNEL_ID = 0;
ENET_IS_RELIABLE = 1;
CMD_ID = 2489;
}
TowerCurLevelRecord cur_level_record = 1;
}

View File

@ -0,0 +1,16 @@
syntax = "proto3";
option java_package = "emu.grasscutter.net.proto";
message TowerEnterLevelReq {
enum CmdId {
option allow_alias = true;
ENET_CHANNEL_ID = 0;
NONE = 0;
ENET_IS_RELIABLE = 1;
IS_ALLOW_CLIENT = 1;
CMD_ID = 2412;
}
uint32 enter_point_id = 1;
}

View File

@ -0,0 +1,18 @@
syntax = "proto3";
option java_package = "emu.grasscutter.net.proto";
message TowerEnterLevelRsp {
enum CmdId {
option allow_alias = true;
NONE = 0;
ENET_CHANNEL_ID = 0;
ENET_IS_RELIABLE = 1;
CMD_ID = 2426;
}
int32 retcode = 1;
uint32 floor_id = 2;
uint32 level_index = 3;
repeated uint32 tower_buff_id_list = 4;
}

View File

@ -0,0 +1,9 @@
syntax = "proto3";
option java_package = "emu.grasscutter.net.proto";
message TowerLevelStarCondData {
uint32 star_cond_index = 3;
uint32 cond_value = 4;
bool is_pause = 5;
}

View File

@ -0,0 +1,19 @@
syntax = "proto3";
option java_package = "emu.grasscutter.net.proto";
import "TowerLevelStarCondData.proto";
message TowerLevelStarCondNotify {
enum CmdId {
option allow_alias = true;
NONE = 0;
ENET_CHANNEL_ID = 0;
ENET_IS_RELIABLE = 1;
CMD_ID = 2492;
}
uint32 floor_id = 1;
uint32 level_index = 2;
repeated TowerLevelStarCondData cond_data_list = 3;
}

View File

@ -0,0 +1,19 @@
syntax = "proto3";
option java_package = "emu.grasscutter.net.proto";
import "TowerTeam.proto";
message TowerTeamSelectReq {
enum CmdId {
option allow_alias = true;
ENET_CHANNEL_ID = 0;
NONE = 0;
ENET_IS_RELIABLE = 1;
IS_ALLOW_CLIENT = 1;
CMD_ID = 2401;
}
uint32 floor_id = 1;
repeated TowerTeam tower_team_list = 2;
}

View File

@ -0,0 +1,15 @@
syntax = "proto3";
option java_package = "emu.grasscutter.net.proto";
message TowerTeamSelectRsp {
enum CmdId {
option allow_alias = true;
NONE = 0;
ENET_CHANNEL_ID = 0;
ENET_IS_RELIABLE = 1;
CMD_ID = 2494;
}
int32 retcode = 1;
}

View File

@ -68,6 +68,8 @@ public class GameData {
private static final Int2ObjectMap<ShopGoodsData> shopGoodsDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<CombineData> combineDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<RewardPreviewData> rewardPreviewDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<TowerFloorData> towerFloorDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<TowerLevelData> towerLevelDataMap = new Int2ObjectOpenHashMap<>();
// Cache
private static Map<Integer, List<Integer>> fetters = new HashMap<>();
@ -311,4 +313,11 @@ public class GameData {
public static Int2ObjectMap<CombineData> getCombineDataMap() {
return combineDataMap;
}
public static Int2ObjectMap<TowerFloorData> getTowerFloorDataMap(){
return towerFloorDataMap;
}
public static Int2ObjectMap<TowerLevelData> getTowerLevelDataMap(){
return towerLevelDataMap;
}
}

View File

@ -0,0 +1,73 @@
package emu.grasscutter.data.def;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
@ResourceType(name = "TowerFloorExcelConfigData.json")
public class TowerFloorData extends GameResource {
private int FloorId;
private int FloorIndex;
private int LevelId;
private int OverrideMonsterLevel;
private int TeamNum;
private int FloorLevelConfigId;
@Override
public int getId() {
return this.FloorId;
}
@Override
public void onLoad() {
super.onLoad();
}
public int getFloorId() {
return FloorId;
}
public void setFloorId(int floorId) {
FloorId = floorId;
}
public int getFloorIndex() {
return FloorIndex;
}
public void setFloorIndex(int floorIndex) {
FloorIndex = floorIndex;
}
public int getLevelId() {
return LevelId;
}
public void setLevelId(int levelId) {
LevelId = levelId;
}
public int getOverrideMonsterLevel() {
return OverrideMonsterLevel;
}
public void setOverrideMonsterLevel(int overrideMonsterLevel) {
OverrideMonsterLevel = overrideMonsterLevel;
}
public int getTeamNum() {
return TeamNum;
}
public void setTeamNum(int teamNum) {
TeamNum = teamNum;
}
public int getFloorLevelConfigId() {
return FloorLevelConfigId;
}
public void setFloorLevelConfigId(int floorLevelConfigId) {
FloorLevelConfigId = floorLevelConfigId;
}
}

View File

@ -0,0 +1,55 @@
package emu.grasscutter.data.def;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
@ResourceType(name = "TowerLevelExcelConfigData.json")
public class TowerLevelData extends GameResource {
private int ID;
private int LevelId;
private int LevelIndex;
private int DungeonId;
@Override
public int getId() {
return this.ID;
}
@Override
public void onLoad() {
super.onLoad();
}
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
public int getLevelId() {
return LevelId;
}
public void setLevelId(int levelId) {
LevelId = levelId;
}
public int getLevelIndex() {
return LevelIndex;
}
public void setLevelIndex(int levelIndex) {
LevelIndex = levelIndex;
}
public int getDungeonId() {
return DungeonId;
}
public void setDungeonId(int dungeonId) {
DungeonId = dungeonId;
}
}

View File

@ -75,7 +75,8 @@ public class DungeonManager {
prevPos.set(entry.getPointData().getTranPos());
}
}
// clean temp team if it has
player.getTeamManager().cleanTemporaryTeam();
// Transfer player back to world
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));

View File

@ -27,6 +27,7 @@ import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.shop.ShopLimit;
import emu.grasscutter.game.managers.MapMarkManager.*;
import emu.grasscutter.game.tower.TowerManager;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.world.World;
import emu.grasscutter.net.packet.BasePacket;
@ -89,6 +90,8 @@ public class Player {
@Transient private MessageHandler messageHandler;
private TeamManager teamManager;
private TowerManager towerManager;
private PlayerGachaInfo gachaInfo;
private PlayerProfile playerProfile;
private boolean showAvatar;
@ -176,6 +179,7 @@ public class Player {
this.nickname = "Traveler";
this.signature = "";
this.teamManager = new TeamManager(this);
this.towerManager = new TowerManager(this);
this.birthday = new PlayerBirthday();
this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, 1);
this.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, 1);
@ -389,6 +393,10 @@ public class Player {
return this.teamManager;
}
public TowerManager getTowerManager() {
return towerManager;
}
public PlayerGachaInfo getGachaInfo() {
return gachaInfo;
}
@ -1030,6 +1038,9 @@ public class Player {
if (this.getProfile().getUid() == 0) {
this.getProfile().syncWithCharacter(this);
}
if (this.getTowerManager() == null) {
this.towerManager = new TowerManager(this);
}
// Check if player object exists in server
// TODO - optimize

View File

@ -18,6 +18,11 @@ public class TeamInfo {
this.avatars = new ArrayList<>(Grasscutter.getConfig().getGameServerOptions().MaxAvatarsInTeam);
}
public TeamInfo(List<Integer> avatars) {
this.name = "";
this.avatars = avatars;
}
public String getName() {
return name;
}

View File

@ -1,12 +1,6 @@
package emu.grasscutter.game.player;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Transient;
@ -60,6 +54,12 @@ public class TeamManager {
@Transient private final IntSet teamResonances;
@Transient private final IntSet teamResonancesConfig;
private int useTemporarilyTeamIndex = -1;
/**
* Temporary Team for tower
*/
private List<TeamInfo> temporaryTeam;
public TeamManager() {
this.mpTeam = new TeamInfo();
this.avatars = new ArrayList<>();
@ -125,6 +125,10 @@ public class TeamManager {
}
public TeamInfo getCurrentTeamInfo() {
if (useTemporarilyTeamIndex >= 0 &&
useTemporarilyTeamIndex < temporaryTeam.size()){
return temporaryTeam.get(useTemporarilyTeamIndex);
}
if (this.getPlayer().isInMultiplayer()) {
return this.getMpTeam();
}
@ -353,6 +357,50 @@ public class TeamManager {
this.updateTeamEntities(new PacketChangeMpTeamAvatarRsp(getPlayer(), teamInfo));
}
public void setupTemporaryTeam(List<List<Long>> guidList) {
var team = guidList.stream().map(list -> {
// Sanity checks
if (list.size() == 0 || list.size() > getMaxTeamSize()) {
return null;
}
// Set team data
LinkedHashSet<Avatar> newTeam = new LinkedHashSet<>();
for (int i = 0; i < list.size(); i++) {
Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(list.get(i));
if (avatar == null || newTeam.contains(avatar)) {
// Should never happen
return null;
}
newTeam.add(avatar);
}
// convert to avatar ids
return newTeam.stream()
.map(Avatar::getAvatarId)
.toList();
})
.filter(Objects::nonNull)
.map(TeamInfo::new)
.toList();
this.temporaryTeam = team;
}
public void useTemporaryTeam(int index) {
this.useTemporarilyTeamIndex = index;
updateTeamEntities(null);
}
public void cleanTemporaryTeam() {
// check if using temporary team
if(useTemporarilyTeamIndex < 0){
return;
}
this.useTemporarilyTeamIndex = -1;
this.temporaryTeam = null;
updateTeamEntities(null);
}
public synchronized void setCurrentTeam(int teamId) {
//
if (getPlayer().isInMultiplayer()) {

View File

@ -0,0 +1,40 @@
package emu.grasscutter.game.tower;
import dev.morphia.annotations.Entity;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketTowerEnterLevelRsp;
import java.util.List;
@Entity
public class TowerManager {
private final Player player;
public TowerManager(Player player) {
this.player = player;
}
private int currentLevel;
private int currentFloor;
public void teamSelect(int floor, List<List<Long>> towerTeams) {
var floorData = GameData.getTowerFloorDataMap().get(floor);
this.currentFloor = floorData.getFloorId();
this.currentLevel = floorData.getLevelId();
player.getTeamManager().setupTemporaryTeam(towerTeams);
}
public void enterLevel(int enterPointId) {
var levelData = GameData.getTowerLevelDataMap().get(currentLevel);
var id = levelData.getDungeonId();
// use team user choose
player.getTeamManager().useTemporaryTeam(0);
player.getServer().getDungeonManager()
.enterDungeon(player, enterPointId, id);
player.getSession().send(new PacketTowerEnterLevelRsp(currentFloor, currentLevel));
}
}

View File

@ -0,0 +1,21 @@
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.TowerEnterLevelReqOuterClass.TowerEnterLevelReq;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.TowerEnterLevelReq)
public class HandlerTowerEnterLevelReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
TowerEnterLevelReq req = TowerEnterLevelReq.parseFrom(payload);
//session.send(new PacketTowerCurLevelRecordChangeNotify());
session.getPlayer().getTowerManager().enterLevel(req.getEnterPointId());
//session.send(new PacketTowerLevelStarCondNotify());
}
}

View File

@ -0,0 +1,26 @@
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.TowerTeamOuterClass;
import emu.grasscutter.net.proto.TowerTeamSelectReqOuterClass.TowerTeamSelectReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketTowerTeamSelectRsp;
@Opcodes(PacketOpcodes.TowerTeamSelectReq)
public class HandlerTowerTeamSelectReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
TowerTeamSelectReq req = TowerTeamSelectReq.parseFrom(payload);
var towerTeams = req.getTowerTeamListList().stream()
.map(TowerTeamOuterClass.TowerTeam::getAvatarGuidListList)
.toList();
session.getPlayer().getTowerManager().teamSelect(req.getFloorId(), towerTeams);
session.send(new PacketTowerTeamSelectRsp());
}
}

View File

@ -1,19 +1,28 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.def.TowerFloorData;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.TowerAllDataRspOuterClass.TowerAllDataRsp;
import emu.grasscutter.net.proto.TowerCurLevelRecordOuterClass.TowerCurLevelRecord;
import emu.grasscutter.net.proto.TowerFloorRecordOuterClass.TowerFloorRecord;
import java.util.stream.Collectors;
public class PacketTowerAllDataRsp extends BasePacket {
public PacketTowerAllDataRsp() {
super(PacketOpcodes.TowerAllDataRsp);
var list = GameData.getTowerFloorDataMap().values().stream()
.map(TowerFloorData::getFloorId)
.map(id -> TowerFloorRecord.newBuilder().setFloorId(id).build())
.collect(Collectors.toList());
TowerAllDataRsp proto = TowerAllDataRsp.newBuilder()
.setTowerScheduleId(29)
.addTowerFloorRecordList(TowerFloorRecord.newBuilder().setFloorId(1001))
.addAllTowerFloorRecordList(list)
.setCurLevelRecord(TowerCurLevelRecord.newBuilder().setIsEmpty(true))
.setNextScheduleChangeTime(Integer.MAX_VALUE)
.putFloorOpenTimeMap(1024, 1630486800)

View File

@ -0,0 +1,22 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.TowerEnterLevelRspOuterClass.TowerEnterLevelRsp;
public class PacketTowerEnterLevelRsp extends BasePacket {
public PacketTowerEnterLevelRsp(int floorId, int levelIndex) {
super(PacketOpcodes.TowerEnterLevelRsp);
TowerEnterLevelRsp proto = TowerEnterLevelRsp.newBuilder()
.setFloorId(floorId)
.setLevelIndex(levelIndex)
.addTowerBuffIdList(4)
.addTowerBuffIdList(28)
.addTowerBuffIdList(18)
.build();
this.setData(proto);
}
}

View File

@ -0,0 +1,17 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.TowerTeamSelectRspOuterClass.TowerTeamSelectRsp;
public class PacketTowerTeamSelectRsp extends BasePacket {
public PacketTowerTeamSelectRsp() {
super(PacketOpcodes.TowerTeamSelectRsp);
TowerTeamSelectRsp proto = TowerTeamSelectRsp.newBuilder()
.build();
this.setData(proto);
}
}