mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-27 12:05:52 +00:00
Merge branch 'development' of github.com:Grasscutters/Grasscutter into development
This commit is contained in:
commit
613366516d
16
proto/TowerBuffSelectReq.proto
Normal file
16
proto/TowerBuffSelectReq.proto
Normal 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;
|
||||
}
|
16
proto/TowerBuffSelectRsp.proto
Normal file
16
proto/TowerBuffSelectRsp.proto
Normal 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;
|
||||
}
|
17
proto/TowerCurLevelRecordChangeNotify.proto
Normal file
17
proto/TowerCurLevelRecordChangeNotify.proto
Normal 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;
|
||||
}
|
16
proto/TowerEnterLevelReq.proto
Normal file
16
proto/TowerEnterLevelReq.proto
Normal 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;
|
||||
}
|
18
proto/TowerEnterLevelRsp.proto
Normal file
18
proto/TowerEnterLevelRsp.proto
Normal 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;
|
||||
}
|
9
proto/TowerLevelStarCondData.proto
Normal file
9
proto/TowerLevelStarCondData.proto
Normal 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;
|
||||
}
|
19
proto/TowerLevelStarCondNotify.proto
Normal file
19
proto/TowerLevelStarCondNotify.proto
Normal 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;
|
||||
}
|
19
proto/TowerTeamSelectReq.proto
Normal file
19
proto/TowerTeamSelectReq.proto
Normal 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;
|
||||
}
|
15
proto/TowerTeamSelectRsp.proto
Normal file
15
proto/TowerTeamSelectRsp.proto
Normal 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;
|
||||
}
|
@ -68,7 +68,9 @@ 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<>();
|
||||
private static Map<Integer, List<ShopGoodsData>> shopGoods = 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;
|
||||
}
|
||||
}
|
||||
|
73
src/main/java/emu/grasscutter/data/def/TowerFloorData.java
Normal file
73
src/main/java/emu/grasscutter/data/def/TowerFloorData.java
Normal 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;
|
||||
}
|
||||
}
|
55
src/main/java/emu/grasscutter/data/def/TowerLevelData.java
Normal file
55
src/main/java/emu/grasscutter/data/def/TowerLevelData.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
|
@ -0,0 +1,147 @@
|
||||
package emu.grasscutter.game.managers.SotSManager;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.net.proto.ChangeHpReasonOuterClass;
|
||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// Statue of the Seven Manager
|
||||
public class SotSManager {
|
||||
|
||||
// NOTE: Spring volume balance *1 = fight prop HP *100
|
||||
|
||||
private final Player player;
|
||||
|
||||
public SotSManager(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public boolean getIsAutoRecoveryEnabled() {
|
||||
return player.getProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE) == 1;
|
||||
}
|
||||
|
||||
public void setIsAutoRecoveryEnabled(boolean enabled) {
|
||||
player.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, enabled ? 1 : 0);
|
||||
}
|
||||
|
||||
public int getAutoRecoveryPercentage() {
|
||||
return player.getProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT);
|
||||
}
|
||||
|
||||
public void setAutoRecoveryPercentage(int percentage) {
|
||||
player.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, percentage);
|
||||
}
|
||||
|
||||
// autoRevive automatically revives all team members.
|
||||
public void autoRevive(GameSession session) {
|
||||
player.getTeamManager().getActiveTeam().forEach(entity -> {
|
||||
boolean isAlive = entity.isAlive();
|
||||
if (!isAlive) {
|
||||
float maxHP = entity.getAvatar().getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
float newHP = (float)(maxHP * 0.3);
|
||||
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
|
||||
entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void scheduleAutoRecover(GameSession session) {
|
||||
// TODO: play audio effects? possibly client side? - client automatically plays.
|
||||
// delay 2.5 seconds
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(2500);
|
||||
autoRecover(session);
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error(e.getMessage());
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void refillSpringVolume() {
|
||||
// TODO: max spring volume depends on level of the statues in Mondstadt and Liyue.
|
||||
// https://genshin-impact.fandom.com/wiki/Statue_of_The_Seven#:~:text=region%20of%20Inazuma.-,Statue%20Levels,-Upon%20first%20unlocking
|
||||
player.setProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME, 8500000);
|
||||
|
||||
long now = System.currentTimeMillis() / 1000;
|
||||
long secondsSinceLastUsed = now - player.getSpringLastUsed();
|
||||
float percentageRefilled = (float)secondsSinceLastUsed / 15 / 100; // 15s = 1% max volume
|
||||
int maxVolume = player.getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME);
|
||||
int currentVolume = player.getProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME);
|
||||
if (currentVolume < maxVolume) {
|
||||
int volumeRefilled = (int)(percentageRefilled * maxVolume);
|
||||
int newVolume = currentVolume + volumeRefilled;
|
||||
if (currentVolume + volumeRefilled > maxVolume) {
|
||||
newVolume = maxVolume;
|
||||
}
|
||||
player.setProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME, newVolume);
|
||||
}
|
||||
player.setSpringLastUsed(now);
|
||||
player.save();
|
||||
}
|
||||
|
||||
// autoRecover checks player setting to see if auto recover is enabled, and refill HP to the predefined level.
|
||||
public void autoRecover(GameSession session) {
|
||||
// TODO: In MP, respect SotS settings from the HOST.
|
||||
boolean isAutoRecoveryEnabled = getIsAutoRecoveryEnabled();
|
||||
int autoRecoverPercentage = getAutoRecoveryPercentage();
|
||||
Grasscutter.getLogger().debug("isAutoRecoveryEnabled: " + isAutoRecoveryEnabled + "\tautoRecoverPercentage: " + autoRecoverPercentage);
|
||||
|
||||
if (isAutoRecoveryEnabled) {
|
||||
player.getTeamManager().getActiveTeam().forEach(entity -> {
|
||||
float maxHP = entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
float currentHP = entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
if (currentHP == maxHP) {
|
||||
return;
|
||||
}
|
||||
float targetHP = maxHP * autoRecoverPercentage / 100;
|
||||
|
||||
if (targetHP > currentHP) {
|
||||
float needHP = targetHP - currentHP;
|
||||
float needSV = needHP * 100; // convert HP needed to Spring Volume needed
|
||||
|
||||
int sotsSVBalance = player.getProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME);
|
||||
if (sotsSVBalance >= needSV) {
|
||||
// sufficient
|
||||
sotsSVBalance -= needSV;
|
||||
} else {
|
||||
// insufficient balance
|
||||
needSV = sotsSVBalance;
|
||||
sotsSVBalance = 0;
|
||||
}
|
||||
player.setProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME, sotsSVBalance);
|
||||
player.setSpringLastUsed(System.currentTimeMillis() / 1000);
|
||||
|
||||
float newHP = currentHP + needSV / 100; // convert SV to HP
|
||||
|
||||
// TODO: Figure out why client shows current HP instead of added HP.
|
||||
// Say an avatar had 12000 and now has 14000, it should show "2000".
|
||||
// The client always show "+14000" which is incorrect.
|
||||
|
||||
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
|
||||
session.send(new PacketEntityFightPropChangeReasonNotify(entity, FightProperty.FIGHT_PROP_CUR_HP,
|
||||
newHP, List.of(3), PropChangeReasonOuterClass.PropChangeReason.PROP_CHANGE_STATUE_RECOVER,
|
||||
ChangeHpReasonOuterClass.ChangeHpReason.ChangeHpAddStatue));
|
||||
session.send(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
|
||||
|
||||
Avatar avatar = entity.getAvatar();
|
||||
avatar.setCurrentHp(newHP);
|
||||
session.send(new PacketAvatarFightPropUpdateNotify(avatar, FightProperty.FIGHT_PROP_CUR_HP));
|
||||
player.save();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -22,11 +22,13 @@ import emu.grasscutter.game.inventory.Inventory;
|
||||
import emu.grasscutter.game.mail.Mail;
|
||||
import emu.grasscutter.game.mail.MailHandler;
|
||||
import emu.grasscutter.game.managers.MovementManager.MovementManager;
|
||||
import emu.grasscutter.game.managers.SotSManager.SotSManager;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
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;
|
||||
@ -88,7 +90,11 @@ public class Player {
|
||||
@Transient private MailHandler mailHandler;
|
||||
@Transient private MessageHandler messageHandler;
|
||||
|
||||
@Transient private SotSManager sotsManager;
|
||||
|
||||
private TeamManager teamManager;
|
||||
|
||||
private TowerManager towerManager;
|
||||
private PlayerGachaInfo gachaInfo;
|
||||
private PlayerProfile playerProfile;
|
||||
private boolean showAvatar;
|
||||
@ -124,6 +130,8 @@ public class Player {
|
||||
private MapMarksManager mapMarksManager;
|
||||
@Transient private MovementManager movementManager;
|
||||
|
||||
private long springLastUsed;
|
||||
|
||||
|
||||
@Deprecated
|
||||
@SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only!
|
||||
@ -165,6 +173,7 @@ public class Player {
|
||||
this.messageHandler = null;
|
||||
this.mapMarksManager = new MapMarksManager();
|
||||
this.movementManager = new MovementManager(this);
|
||||
this.sotsManager = new SotSManager(this);
|
||||
}
|
||||
|
||||
// On player creation
|
||||
@ -176,6 +185,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);
|
||||
@ -192,6 +202,7 @@ public class Player {
|
||||
this.messageHandler = null;
|
||||
this.mapMarksManager = new MapMarksManager();
|
||||
this.movementManager = new MovementManager(this);
|
||||
this.sotsManager = new SotSManager(this);
|
||||
}
|
||||
|
||||
public int getUid() {
|
||||
@ -389,6 +400,10 @@ public class Player {
|
||||
return this.teamManager;
|
||||
}
|
||||
|
||||
public TowerManager getTowerManager() {
|
||||
return towerManager;
|
||||
}
|
||||
|
||||
public PlayerGachaInfo getGachaInfo() {
|
||||
return gachaInfo;
|
||||
}
|
||||
@ -522,6 +537,14 @@ public class Player {
|
||||
}
|
||||
}
|
||||
|
||||
public long getSpringLastUsed() {
|
||||
return springLastUsed;
|
||||
}
|
||||
|
||||
public void setSpringLastUsed(long val) {
|
||||
springLastUsed = val;
|
||||
}
|
||||
|
||||
public SceneLoadState getSceneLoadState() {
|
||||
return sceneState;
|
||||
}
|
||||
@ -976,6 +999,8 @@ public class Player {
|
||||
|
||||
public MovementManager getMovementManager() { return movementManager; }
|
||||
|
||||
public SotSManager getSotSManager() { return sotsManager; }
|
||||
|
||||
public synchronized void onTick() {
|
||||
// Check ping
|
||||
if (this.getLastPingTime() > System.currentTimeMillis() + 60000) {
|
||||
@ -1030,6 +1055,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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
@ -59,7 +53,13 @@ public class TeamManager {
|
||||
@Transient private final Set<EntityBaseGadget> gadgets;
|
||||
@Transient private final IntSet teamResonances;
|
||||
@Transient private final IntSet teamResonancesConfig;
|
||||
|
||||
|
||||
@Transient private int useTemporarilyTeamIndex = -1;
|
||||
/**
|
||||
* Temporary Team for tower
|
||||
*/
|
||||
@Transient 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();
|
||||
}
|
||||
@ -352,7 +356,51 @@ public class TeamManager {
|
||||
// Packet
|
||||
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()) {
|
||||
|
42
src/main/java/emu/grasscutter/game/tower/TowerManager.java
Normal file
42
src/main/java/emu/grasscutter/game/tower/TowerManager.java
Normal file
@ -0,0 +1,42 @@
|
||||
package emu.grasscutter.game.tower;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Transient;
|
||||
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 {
|
||||
@Transient 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));
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
package emu.grasscutter.net.packet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class PacketOpcodes {
|
||||
// Empty
|
||||
public static final int NONE = 0;
|
||||
@ -1566,4 +1569,6 @@ public class PacketOpcodes {
|
||||
public static final int UNKNOWN_43 = 8877;
|
||||
public static final int UNKNOWN_44 = 8983;
|
||||
public static final int UNKNOWN_45 = 943;
|
||||
|
||||
public static final List<Integer> BANNED_PACKETS = Arrays.asList(PacketOpcodes.WindSeedClientNotify, PacketOpcodes.PlayerLuaShellNotify);
|
||||
}
|
||||
|
@ -157,6 +157,12 @@ public class GameSession extends KcpChannel {
|
||||
Grasscutter.getLogger().warn("Tried to send packet with missing cmd id!");
|
||||
return;
|
||||
}
|
||||
|
||||
// DO NOT REMOVE (unless we find a way to validate code before sending to client which I don't think we can)
|
||||
// Stop WindSeedClientNotify from being sent for security purposes.
|
||||
if(PacketOpcodes.BANNED_PACKETS.contains(packet.getOpcode())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Header
|
||||
if (packet.shouldBuildHeader()) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.game.managers.SotSManager.SotSManager;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
@ -18,26 +20,12 @@ import java.util.List;
|
||||
public class HandlerEnterTransPointRegionNotify extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception{
|
||||
session.getPlayer().getTeamManager().getActiveTeam().forEach(entity -> {
|
||||
boolean isAlive = entity.isAlive();
|
||||
if(entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) != entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP)){
|
||||
Float hp = entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP)-entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
|
||||
session.send(new PacketEntityFightPropUpdateNotify(entity,FightProperty.FIGHT_PROP_MAX_HP));
|
||||
Player player = session.getPlayer();
|
||||
SotSManager sotsManager = player.getSotSManager();
|
||||
|
||||
session.send(new PacketEntityFightPropChangeReasonNotify(
|
||||
entity, FightProperty.FIGHT_PROP_CUR_HP, hp, List.of(3),
|
||||
PropChangeReason.PROP_CHANGE_STATUE_RECOVER, ChangeHpReason.ChangeHpAddStatue));
|
||||
|
||||
entity.setFightProperty(
|
||||
FightProperty.FIGHT_PROP_CUR_HP,
|
||||
entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP)
|
||||
);
|
||||
session.send(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP));
|
||||
if (!isAlive) {
|
||||
entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
|
||||
}
|
||||
}
|
||||
});
|
||||
sotsManager.refillSpringVolume();
|
||||
sotsManager.autoRevive(session);
|
||||
sotsManager.scheduleAutoRecover(session);
|
||||
// TODO: allow interaction with the SotS?
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -15,14 +15,7 @@ public class PacketTakeAchievementRewardReq extends BasePacket {
|
||||
public PacketTakeAchievementRewardReq(GameSession session) {
|
||||
super(PacketOpcodes.TakeAchievementRewardReq);
|
||||
|
||||
List<AchievementInfo> a_list = new ArrayList<>();
|
||||
a_list.add(AchievementInfo.newBuilder().setId(82044).setStatusValue(2).setCurrent(0).setGoal(1).build());
|
||||
a_list.add(AchievementInfo.newBuilder().setId(81205).setStatusValue(2).setCurrent(0).setGoal(1).build());
|
||||
|
||||
|
||||
TakeAchievementRewardReq proto = TakeAchievementRewardReq.newBuilder()
|
||||
.addAllAList(a_list)
|
||||
.build();
|
||||
TakeAchievementRewardReq proto = TakeAchievementRewardReq.newBuilder().build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user