Continue updating/refactoring classes

Most code is matched from `Grasscutter-Quests`.
This commit is contained in:
KingRainbow44
2023-04-01 22:17:10 -04:00
parent 772532515e
commit 9fbb7fb3be
97 changed files with 14397 additions and 12921 deletions

View File

@@ -1,30 +1,24 @@
package emu.grasscutter.server.event.entity;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.server.event.Cancellable;
import emu.grasscutter.server.event.types.EntityEvent;
import javax.annotation.Nullable;
public final class EntityDamageEvent extends EntityEvent implements Cancellable {
@Nullable private final GameEntity damager;
private float damage;
public EntityDamageEvent(GameEntity entity, float damage, @Nullable GameEntity damager) {
super(entity);
this.damage = damage;
this.damager = damager;
}
public float getDamage() {
return this.damage;
}
public void setDamage(float damage) {
this.damage = damage;
}
@Nullable public GameEntity getDamager() {
return this.damager;
}
}
package emu.grasscutter.server.event.entity;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.props.ElementType;
import emu.grasscutter.server.event.Cancellable;
import emu.grasscutter.server.event.types.EntityEvent;
import lombok.Getter;
import lombok.Setter;
import javax.annotation.Nullable;
public final class EntityDamageEvent extends EntityEvent implements Cancellable {
@Getter @Setter private float damage;
@Getter @Setter private ElementType attackElementType;
@Getter @Nullable private final GameEntity damager;
public EntityDamageEvent(GameEntity entity, float damage, ElementType attackElementType, @Nullable GameEntity damager) {
super(entity);
this.damage = damage;
this.attackElementType = attackElementType;
this.damager = damager;
}
}

View File

@@ -1,281 +1,279 @@
package emu.grasscutter.server.game;
import static emu.grasscutter.config.Configuration.GAME_INFO;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.battlepass.BattlePassSystem;
import emu.grasscutter.game.chat.ChatSystem;
import emu.grasscutter.game.chat.ChatSystemHandler;
import emu.grasscutter.game.combine.CombineManger;
import emu.grasscutter.game.drop.DropSystem;
import emu.grasscutter.game.dungeons.DungeonSystem;
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
import emu.grasscutter.game.expedition.ExpeditionSystem;
import emu.grasscutter.game.gacha.GachaSystem;
import emu.grasscutter.game.managers.cooking.CookingCompoundManager;
import emu.grasscutter.game.managers.cooking.CookingManager;
import emu.grasscutter.game.managers.energy.EnergyManager;
import emu.grasscutter.game.managers.stamina.StaminaManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.QuestSystem;
import emu.grasscutter.game.shop.ShopSystem;
import emu.grasscutter.game.systems.AnnouncementSystem;
import emu.grasscutter.game.systems.InventorySystem;
import emu.grasscutter.game.systems.MultiplayerSystem;
import emu.grasscutter.game.tower.TowerSystem;
import emu.grasscutter.game.world.World;
import emu.grasscutter.game.world.WorldDataSystem;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
import emu.grasscutter.server.event.game.ServerTickEvent;
import emu.grasscutter.server.event.internal.ServerStartEvent;
import emu.grasscutter.server.event.internal.ServerStopEvent;
import emu.grasscutter.server.event.types.ServerEvent;
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
import emu.grasscutter.task.TaskMap;
import java.net.InetSocketAddress;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import kcp.highway.ChannelConfig;
import kcp.highway.KcpServer;
import lombok.Getter;
@Getter
public final class GameServer extends KcpServer {
// Game server base
private final InetSocketAddress address;
private final GameServerPacketHandler packetHandler;
private final Map<Integer, Player> players;
private final Set<World> worlds;
// Server systems
private final InventorySystem inventorySystem;
private final GachaSystem gachaSystem;
private final ShopSystem shopSystem;
private final MultiplayerSystem multiplayerSystem;
private final DungeonSystem dungeonSystem;
private final ExpeditionSystem expeditionSystem;
private final DropSystem dropSystem;
private final WorldDataSystem worldDataSystem;
private final BattlePassSystem battlePassSystem;
private final CombineManger combineSystem;
private final TowerSystem towerSystem;
private final AnnouncementSystem announcementSystem;
private final QuestSystem questSystem;
// Extra
private final ServerTaskScheduler scheduler;
private final TaskMap taskMap;
private ChatSystemHandler chatManager;
public GameServer() {
this(getAdapterInetSocketAddress());
}
public GameServer(InetSocketAddress address) {
ChannelConfig channelConfig = new ChannelConfig();
channelConfig.nodelay(true, GAME_INFO.kcpInterval, 2, true);
channelConfig.setMtu(1400);
channelConfig.setSndwnd(256);
channelConfig.setRcvwnd(256);
channelConfig.setTimeoutMillis(30 * 1000); // 30s
channelConfig.setUseConvChannel(true);
channelConfig.setAckNoDelay(false);
this.init(GameSessionManager.getListener(), channelConfig, address);
DungeonChallenge.initialize();
EnergyManager.initialize();
StaminaManager.initialize();
CookingManager.initialize();
CookingCompoundManager.initialize();
CombineManger.initialize();
// Game Server base
this.address = address;
this.packetHandler = new GameServerPacketHandler(PacketHandler.class);
this.players = new ConcurrentHashMap<>();
this.worlds = Collections.synchronizedSet(new HashSet<>());
// Extra
this.scheduler = new ServerTaskScheduler();
this.taskMap = new TaskMap(true);
// Create game systems
this.inventorySystem = new InventorySystem(this);
this.gachaSystem = new GachaSystem(this);
this.shopSystem = new ShopSystem(this);
this.multiplayerSystem = new MultiplayerSystem(this);
this.dungeonSystem = new DungeonSystem(this);
this.dropSystem = new DropSystem(this);
this.expeditionSystem = new ExpeditionSystem(this);
this.combineSystem = new CombineManger(this);
this.towerSystem = new TowerSystem(this);
this.worldDataSystem = new WorldDataSystem(this);
this.battlePassSystem = new BattlePassSystem(this);
this.announcementSystem = new AnnouncementSystem(this);
this.questSystem = new QuestSystem(this);
// Chata manager
this.chatManager = new ChatSystem(this);
// Hook into shutdown event.
Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown));
}
private static InetSocketAddress getAdapterInetSocketAddress() {
InetSocketAddress inetSocketAddress;
if (GAME_INFO.bindAddress.equals("")) {
inetSocketAddress = new InetSocketAddress(GAME_INFO.bindPort);
} else {
inetSocketAddress = new InetSocketAddress(GAME_INFO.bindAddress, GAME_INFO.bindPort);
}
return inetSocketAddress;
}
@Deprecated
public ChatSystemHandler getChatManager() {
return chatManager;
}
@Deprecated
public void setChatManager(ChatSystemHandler chatManager) {
this.chatManager = chatManager;
}
public ChatSystemHandler getChatSystem() {
return chatManager;
}
public void setChatSystem(ChatSystemHandler chatManager) {
this.chatManager = chatManager;
}
public void registerPlayer(Player player) {
getPlayers().put(player.getUid(), player);
}
public Player getPlayerByUid(int id) {
return this.getPlayerByUid(id, false);
}
public Player getPlayerByUid(int id, boolean allowOfflinePlayers) {
// Console check
if (id == GameConstants.SERVER_CONSOLE_UID) {
return null;
}
// Get from online players
Player player = this.getPlayers().get(id);
if (!allowOfflinePlayers) {
return player;
}
// Check database if character isnt here
if (player == null) {
player = DatabaseHelper.getPlayerByUid(id);
}
return player;
}
public Player getPlayerByAccountId(String accountId) {
Optional<Player> playerOpt =
getPlayers().values().stream()
.filter(player -> player.getAccount().getId().equals(accountId))
.findFirst();
return playerOpt.orElse(null);
}
public SocialDetail.Builder getSocialDetailByUid(int id) {
// Get from online players
Player player = this.getPlayerByUid(id, true);
if (player == null) {
return null;
}
return player.getSocialDetail();
}
public Account getAccountByName(String username) {
Optional<Player> playerOpt =
getPlayers().values().stream()
.filter(player -> player.getAccount().getUsername().equals(username))
.findFirst();
if (playerOpt.isPresent()) {
return playerOpt.get().getAccount();
}
return DatabaseHelper.getAccountByName(username);
}
public synchronized void onTick() {
var tickStart = Instant.now();
// Tick worlds.
this.worlds.removeIf(World::onTick);
// Tick players.
this.players.values().forEach(Player::onTick);
// Tick scheduler.
this.getScheduler().runTasks();
// Call server tick event.
ServerTickEvent event = new ServerTickEvent(tickStart, Instant.now());
event.call();
}
public void registerWorld(World world) {
this.getWorlds().add(world);
}
public void deregisterWorld(World world) {
// TODO Auto-generated method stub
}
public void start() {
// Schedule game loop.
Timer gameLoop = new Timer();
gameLoop.scheduleAtFixedRate(
new TimerTask() {
@Override
public void run() {
try {
onTick();
} catch (Exception e) {
Grasscutter.getLogger().error(translate("messages.game.game_update_error"), e);
}
}
},
new Date(),
1000L);
Grasscutter.getLogger().info(translate("messages.status.free_software"));
Grasscutter.getLogger()
.info(translate("messages.game.address_bind", GAME_INFO.accessAddress, address.getPort()));
ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
event.call();
}
public void onServerShutdown() {
ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
event.call();
// Kick and save all players
List<Player> list = new ArrayList<>(this.getPlayers().size());
list.addAll(this.getPlayers().values());
for (Player player : list) {
player.getSession().close();
}
}
}
package emu.grasscutter.server.game;
import static emu.grasscutter.config.Configuration.GAME_INFO;
import static emu.grasscutter.utils.Language.translate;
import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.battlepass.BattlePassSystem;
import emu.grasscutter.game.chat.ChatSystem;
import emu.grasscutter.game.chat.ChatSystemHandler;
import emu.grasscutter.game.combine.CombineManger;
import emu.grasscutter.game.drop.DropSystem;
import emu.grasscutter.game.dungeons.DungeonSystem;
import emu.grasscutter.game.expedition.ExpeditionSystem;
import emu.grasscutter.game.gacha.GachaSystem;
import emu.grasscutter.game.managers.cooking.CookingCompoundManager;
import emu.grasscutter.game.managers.cooking.CookingManager;
import emu.grasscutter.game.managers.energy.EnergyManager;
import emu.grasscutter.game.managers.stamina.StaminaManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.QuestSystem;
import emu.grasscutter.game.shop.ShopSystem;
import emu.grasscutter.game.systems.AnnouncementSystem;
import emu.grasscutter.game.systems.InventorySystem;
import emu.grasscutter.game.systems.MultiplayerSystem;
import emu.grasscutter.game.tower.TowerSystem;
import emu.grasscutter.game.world.World;
import emu.grasscutter.game.world.WorldDataSystem;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
import emu.grasscutter.server.event.game.ServerTickEvent;
import emu.grasscutter.server.event.internal.ServerStartEvent;
import emu.grasscutter.server.event.internal.ServerStopEvent;
import emu.grasscutter.server.event.types.ServerEvent;
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
import emu.grasscutter.task.TaskMap;
import java.net.InetSocketAddress;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import kcp.highway.ChannelConfig;
import kcp.highway.KcpServer;
import lombok.Getter;
@Getter
public final class GameServer extends KcpServer {
// Game server base
private final InetSocketAddress address;
private final GameServerPacketHandler packetHandler;
private final Map<Integer, Player> players;
private final Set<World> worlds;
// Server systems
private final InventorySystem inventorySystem;
private final GachaSystem gachaSystem;
private final ShopSystem shopSystem;
private final MultiplayerSystem multiplayerSystem;
private final DungeonSystem dungeonSystem;
private final ExpeditionSystem expeditionSystem;
private final DropSystem dropSystem;
private final WorldDataSystem worldDataSystem;
private final BattlePassSystem battlePassSystem;
private final CombineManger combineSystem;
private final TowerSystem towerSystem;
private final AnnouncementSystem announcementSystem;
private final QuestSystem questSystem;
// Extra
private final ServerTaskScheduler scheduler;
private final TaskMap taskMap;
private ChatSystemHandler chatManager;
public GameServer() {
this(getAdapterInetSocketAddress());
}
public GameServer(InetSocketAddress address) {
ChannelConfig channelConfig = new ChannelConfig();
channelConfig.nodelay(true, GAME_INFO.kcpInterval, 2, true);
channelConfig.setMtu(1400);
channelConfig.setSndwnd(256);
channelConfig.setRcvwnd(256);
channelConfig.setTimeoutMillis(30 * 1000); // 30s
channelConfig.setUseConvChannel(true);
channelConfig.setAckNoDelay(false);
this.init(GameSessionManager.getListener(), channelConfig, address);
EnergyManager.initialize();
StaminaManager.initialize();
CookingManager.initialize();
CookingCompoundManager.initialize();
CombineManger.initialize();
// Game Server base
this.address = address;
this.packetHandler = new GameServerPacketHandler(PacketHandler.class);
this.players = new ConcurrentHashMap<>();
this.worlds = Collections.synchronizedSet(new HashSet<>());
// Extra
this.scheduler = new ServerTaskScheduler();
this.taskMap = new TaskMap(true);
// Create game systems
this.inventorySystem = new InventorySystem(this);
this.gachaSystem = new GachaSystem(this);
this.shopSystem = new ShopSystem(this);
this.multiplayerSystem = new MultiplayerSystem(this);
this.dungeonSystem = new DungeonSystem(this);
this.dropSystem = new DropSystem(this);
this.expeditionSystem = new ExpeditionSystem(this);
this.combineSystem = new CombineManger(this);
this.towerSystem = new TowerSystem(this);
this.worldDataSystem = new WorldDataSystem(this);
this.battlePassSystem = new BattlePassSystem(this);
this.announcementSystem = new AnnouncementSystem(this);
this.questSystem = new QuestSystem(this);
// Chata manager
this.chatManager = new ChatSystem(this);
// Hook into shutdown event.
Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown));
}
private static InetSocketAddress getAdapterInetSocketAddress() {
InetSocketAddress inetSocketAddress;
if (GAME_INFO.bindAddress.equals("")) {
inetSocketAddress = new InetSocketAddress(GAME_INFO.bindPort);
} else {
inetSocketAddress = new InetSocketAddress(GAME_INFO.bindAddress, GAME_INFO.bindPort);
}
return inetSocketAddress;
}
@Deprecated
public ChatSystemHandler getChatManager() {
return chatManager;
}
@Deprecated
public void setChatManager(ChatSystemHandler chatManager) {
this.chatManager = chatManager;
}
public ChatSystemHandler getChatSystem() {
return chatManager;
}
public void setChatSystem(ChatSystemHandler chatManager) {
this.chatManager = chatManager;
}
public void registerPlayer(Player player) {
getPlayers().put(player.getUid(), player);
}
public Player getPlayerByUid(int id) {
return this.getPlayerByUid(id, false);
}
public Player getPlayerByUid(int id, boolean allowOfflinePlayers) {
// Console check
if (id == GameConstants.SERVER_CONSOLE_UID) {
return null;
}
// Get from online players
Player player = this.getPlayers().get(id);
if (!allowOfflinePlayers) {
return player;
}
// Check database if character isnt here
if (player == null) {
player = DatabaseHelper.getPlayerByUid(id);
}
return player;
}
public Player getPlayerByAccountId(String accountId) {
Optional<Player> playerOpt =
getPlayers().values().stream()
.filter(player -> player.getAccount().getId().equals(accountId))
.findFirst();
return playerOpt.orElse(null);
}
public SocialDetail.Builder getSocialDetailByUid(int id) {
// Get from online players
Player player = this.getPlayerByUid(id, true);
if (player == null) {
return null;
}
return player.getSocialDetail();
}
public Account getAccountByName(String username) {
Optional<Player> playerOpt =
getPlayers().values().stream()
.filter(player -> player.getAccount().getUsername().equals(username))
.findFirst();
if (playerOpt.isPresent()) {
return playerOpt.get().getAccount();
}
return DatabaseHelper.getAccountByName(username);
}
public synchronized void onTick() {
var tickStart = Instant.now();
// Tick worlds.
this.worlds.removeIf(World::onTick);
// Tick players.
this.players.values().forEach(Player::onTick);
// Tick scheduler.
this.getScheduler().runTasks();
// Call server tick event.
ServerTickEvent event = new ServerTickEvent(tickStart, Instant.now());
event.call();
}
public void registerWorld(World world) {
this.getWorlds().add(world);
}
public void deregisterWorld(World world) {
// TODO Auto-generated method stub
}
public void start() {
// Schedule game loop.
Timer gameLoop = new Timer();
gameLoop.scheduleAtFixedRate(
new TimerTask() {
@Override
public void run() {
try {
onTick();
} catch (Exception e) {
Grasscutter.getLogger().error(translate("messages.game.game_update_error"), e);
}
}
},
new Date(),
1000L);
Grasscutter.getLogger().info(translate("messages.status.free_software"));
Grasscutter.getLogger()
.info(translate("messages.game.address_bind", GAME_INFO.accessAddress, address.getPort()));
ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
event.call();
}
public void onServerShutdown() {
ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
event.call();
// Kick and save all players
List<Player> list = new ArrayList<>(this.getPlayers().size());
list.addAll(this.getPlayers().values());
for (Player player : list) {
player.getSession().close();
}
}
}

View File

@@ -1,41 +1,26 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.QuestData.QuestCondition;
import emu.grasscutter.game.quest.enums.QuestTrigger;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.AddQuestContentProgressReqOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketAddQuestContentProgressRsp;
import java.util.List;
import java.util.stream.Stream;
@Opcodes(PacketOpcodes.AddQuestContentProgressReq)
public class HandlerAddQuestContentProgressReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = AddQuestContentProgressReqOuterClass.AddQuestContentProgressReq.parseFrom(payload);
// Find all conditions in quest that are the same as the given one
Stream<QuestCondition> finishCond =
GameData.getQuestDataMap().get(req.getParam()).getFinishCond().stream();
Stream<QuestCondition> acceptCond =
GameData.getQuestDataMap().get(req.getParam()).getAcceptCond().stream();
Stream<QuestCondition> failCond =
GameData.getQuestDataMap().get(req.getParam()).getFailCond().stream();
List<QuestCondition> allCondMatch =
Stream.concat(Stream.concat(acceptCond, failCond), finishCond)
.filter(p -> p.getType().getValue() == req.getContentType())
.toList();
for (QuestCondition cond : allCondMatch) {
session
.getPlayer()
.getQuestManager()
.triggerEvent(
QuestTrigger.getContentTriggerByValue(req.getContentType()), cond.getParam());
}
session.send(new PacketAddQuestContentProgressRsp(req.getContentType()));
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.AddQuestContentProgressReqOuterClass.AddQuestContentProgressReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketAddQuestContentProgressRsp;
@Opcodes(PacketOpcodes.AddQuestContentProgressReq)
public class HandlerAddQuestContentProgressReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = AddQuestContentProgressReq.parseFrom(payload);
// Find all conditions in quest that are the same as the given one
var type = QuestContent.getContentTriggerByValue(req.getContentType());
if(type != null) {
session.getPlayer().getQuestManager().queueEvent(type, req.getParam());
}
session.send(new PacketAddQuestContentProgressRsp(req.getContentType()));
}
}

View File

@@ -1,69 +1,39 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.GameConstants;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.avatar.AvatarSkillDepotData;
import emu.grasscutter.data.excels.world.WorldAreaData;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.AvatarChangeElementTypeReqOuterClass.AvatarChangeElementTypeReq;
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketAbilityChangeNotify;
import emu.grasscutter.server.packet.send.PacketAvatarChangeElementTypeRsp;
import emu.grasscutter.server.packet.send.PacketAvatarFightPropNotify;
import emu.grasscutter.server.packet.send.PacketAvatarSkillDepotChangeNotify;
@Opcodes(PacketOpcodes.AvatarChangeElementTypeReq)
public class HandlerAvatarChangeElementTypeReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
AvatarChangeElementTypeReq req = AvatarChangeElementTypeReq.parseFrom(payload);
WorldAreaData area = GameData.getWorldAreaDataMap().get(req.getAreaId());
if (area == null
|| area.getElementType() == null
|| area.getElementType().getDepotValue() <= 0) {
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
return;
}
// Get current avatar, should be one of the main characters
EntityAvatar mainCharacterEntity =
session.getPlayer().getTeamManager().getCurrentAvatarEntity();
Avatar mainCharacter = mainCharacterEntity.getAvatar();
int skillDepotId = area.getElementType().getDepotValue();
switch (mainCharacter.getAvatarId()) {
case GameConstants.MAIN_CHARACTER_MALE -> skillDepotId += 500;
case GameConstants.MAIN_CHARACTER_FEMALE -> skillDepotId += 700;
default -> {
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
return;
}
}
// Sanity checks for skill depots
AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(skillDepotId);
if (skillDepot == null || skillDepot.getId() == mainCharacter.getSkillDepotId()) {
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
return;
}
// Set skill depot
mainCharacter.setSkillDepotData(skillDepot);
// Success
session.send(new PacketAvatarChangeElementTypeRsp());
// Ability change packet
session.send(new PacketAvatarSkillDepotChangeNotify(mainCharacter));
session.send(new PacketAbilityChangeNotify(mainCharacterEntity));
session.send(new PacketAvatarFightPropNotify(mainCharacter));
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.data.GameData;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.AvatarChangeElementTypeReqOuterClass.AvatarChangeElementTypeReq;
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketAvatarChangeElementTypeRsp;
import lombok.val;
/**
* Changes the currently active avatars Element if possible
*/
@Opcodes(PacketOpcodes.AvatarChangeElementTypeReq)
public class HandlerAvatarChangeElementTypeReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = AvatarChangeElementTypeReq.parseFrom(payload);
var area = GameData.getWorldAreaDataMap().get(req.getAreaId());
if (area == null || area.getElementType() == null || area.getElementType().getDepotIndex() <= 0) {
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
return;
}
val avatar = session.getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar();
if (!avatar.changeElement(area.getElementType())) {
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
return;
}
// Success
session.send(new PacketAvatarChangeElementTypeRsp());
}
}

View File

@@ -1,191 +1,191 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
import emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify;
import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
import emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo;
import emu.grasscutter.net.proto.EvtAnimatorParameterInfoOuterClass.EvtAnimatorParameterInfo;
import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo;
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass;
import emu.grasscutter.server.event.entity.EntityMoveEvent;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.utils.Position;
@Opcodes(PacketOpcodes.CombatInvocationsNotify)
public class HandlerCombatInvocationsNotify extends PacketHandler {
private float cachedLandingSpeed = 0;
private long cachedLandingTimeMillisecond = 0;
private boolean monitorLandingEvent = false;
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
CombatInvocationsNotify notif = CombatInvocationsNotify.parseFrom(payload);
for (CombatInvokeEntry entry : notif.getInvokeListList()) {
// Handle combat invoke
switch (entry.getArgumentType()) {
case COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT -> {
EvtBeingHitInfo hitInfo = EvtBeingHitInfo.parseFrom(entry.getCombatData());
AttackResult attackResult = hitInfo.getAttackResult();
Player player = session.getPlayer();
// Check if the player is invulnerable.
if (attackResult.getAttackerId()
!= player.getTeamManager().getCurrentAvatarEntity().getId()
&& player.getAbilityManager().isAbilityInvulnerable()) break;
// Handle damage
player.getAttackResults().add(attackResult);
player.getEnergyManager().handleAttackHit(hitInfo);
}
case COMBAT_TYPE_ARGUMENT_ENTITY_MOVE -> {
// Handle movement
EntityMoveInfo moveInfo = EntityMoveInfo.parseFrom(entry.getCombatData());
GameEntity entity = session.getPlayer().getScene().getEntityById(moveInfo.getEntityId());
if (entity != null) {
// Move player
MotionInfo motionInfo = moveInfo.getMotionInfo();
MotionState motionState = motionInfo.getState();
// Call entity move event.
EntityMoveEvent event =
new EntityMoveEvent(
entity,
new Position(motionInfo.getPos()),
new Position(motionInfo.getRot()),
motionState);
event.call();
entity.move(event.getPosition(), event.getRotation());
entity.setLastMoveSceneTimeMs(moveInfo.getSceneTime());
entity.setLastMoveReliableSeq(moveInfo.getReliableSeq());
entity.setMotionState(motionState);
session
.getPlayer()
.getStaminaManager()
.handleCombatInvocationsNotify(session, moveInfo, entity);
// TODO: handle MOTION_FIGHT landing which has a different damage factor
// Also, for plunge attacks, LAND_SPEED is always -30 and is not useful.
// May need the height when starting plunge attack.
// MOTION_LAND_SPEED and MOTION_FALL_ON_GROUND arrive in different packets.
// Cache land speed for later use.
if (motionState == MotionState.MOTION_STATE_LAND_SPEED) {
cachedLandingSpeed = motionInfo.getSpeed().getY();
cachedLandingTimeMillisecond = System.currentTimeMillis();
monitorLandingEvent = true;
}
if (monitorLandingEvent) {
if (motionState == MotionState.MOTION_STATE_FALL_ON_GROUND) {
monitorLandingEvent = false;
handleFallOnGround(session, entity, motionState);
}
}
// MOTION_STATE_NOTIFY = Dont send to other players
if (motionState == MotionState.MOTION_STATE_NOTIFY) {
continue;
}
}
}
case COMBAT_TYPE_ARGUMENT_ANIMATOR_PARAMETER_CHANGED -> {
EvtAnimatorParameterInfo paramInfo =
EvtAnimatorParameterInfo.parseFrom(entry.getCombatData());
if (paramInfo.getIsServerCache()) {
paramInfo = paramInfo.toBuilder().setIsServerCache(false).build();
entry = entry.toBuilder().setCombatData(paramInfo.toByteString()).build();
}
}
default -> {}
}
session.getPlayer().getCombatInvokeHandler().addEntry(entry.getForwardType(), entry);
}
}
private void handleFallOnGround(GameSession session, GameEntity entity, MotionState motionState) {
if (session.getPlayer().inGodmode()) {
return;
}
// People have reported that after plunge attack (client sends a FIGHT instead of
// FALL_ON_GROUND) they will die
// if they talk to an NPC (this is when the client sends a FALL_ON_GROUND) without jumping
// again.
// A dirty patch: if not received immediately after MOTION_LAND_SPEED, discard this packet.
// 200ms seems to be a reasonable delay.
int maxDelay = 200;
long actualDelay = System.currentTimeMillis() - cachedLandingTimeMillisecond;
Grasscutter.getLogger()
.trace(
"MOTION_FALL_ON_GROUND received after "
+ actualDelay
+ "/"
+ maxDelay
+ "ms."
+ (actualDelay > maxDelay ? " Discard" : ""));
if (actualDelay > maxDelay) {
return;
}
float currentHP = entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
float maxHP = entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
float damageFactor = 0;
if (cachedLandingSpeed < -23.5) {
damageFactor = 0.33f;
}
if (cachedLandingSpeed < -25) {
damageFactor = 0.5f;
}
if (cachedLandingSpeed < -26.5) {
damageFactor = 0.66f;
}
if (cachedLandingSpeed < -28) {
damageFactor = 1f;
}
float damage = maxHP * damageFactor;
float newHP = currentHP - damage;
if (newHP < 0) {
newHP = 0;
}
if (damageFactor > 0) {
Grasscutter.getLogger()
.debug(
currentHP
+ "/"
+ maxHP
+ "\tLandingSpeed: "
+ cachedLandingSpeed
+ "\tDamageFactor: "
+ damageFactor
+ "\tDamage: "
+ damage
+ "\tNewHP: "
+ newHP);
} else {
Grasscutter.getLogger().trace(currentHP + "/" + maxHP + "\tLandingSpeed: 0\tNo damage");
}
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
entity
.getWorld()
.broadcastPacket(
new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
if (newHP == 0) {
session
.getPlayer()
.getStaminaManager()
.killAvatar(session, entity, PlayerDieTypeOuterClass.PlayerDieType.PLAYER_DIE_TYPE_FALL);
}
cachedLandingSpeed = 0;
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
import emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify;
import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
import emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo;
import emu.grasscutter.net.proto.EvtAnimatorParameterInfoOuterClass.EvtAnimatorParameterInfo;
import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo;
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass;
import emu.grasscutter.server.event.entity.EntityMoveEvent;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import emu.grasscutter.utils.Position;
@Opcodes(PacketOpcodes.CombatInvocationsNotify)
public class HandlerCombatInvocationsNotify extends PacketHandler {
private float cachedLandingSpeed = 0;
private long cachedLandingTimeMillisecond = 0;
private boolean monitorLandingEvent = false;
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
CombatInvocationsNotify notif = CombatInvocationsNotify.parseFrom(payload);
for (CombatInvokeEntry entry : notif.getInvokeListList()) {
// Handle combat invoke
switch (entry.getArgumentType()) {
case COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT -> {
EvtBeingHitInfo hitInfo = EvtBeingHitInfo.parseFrom(entry.getCombatData());
AttackResult attackResult = hitInfo.getAttackResult();
Player player = session.getPlayer();
// Check if the player is invulnerable.
if (attackResult.getAttackerId()
!= player.getTeamManager().getCurrentAvatarEntity().getId()
&& player.getAbilityManager().isAbilityInvulnerable()) break;
// Handle damage
player.getAttackResults().add(attackResult);
player.getEnergyManager().handleAttackHit(hitInfo);
}
case COMBAT_TYPE_ARGUMENT_ENTITY_MOVE -> {
// Handle movement
EntityMoveInfo moveInfo = EntityMoveInfo.parseFrom(entry.getCombatData());
GameEntity entity = session.getPlayer().getScene().getEntityById(moveInfo.getEntityId());
if (entity != null) {
// Move player
MotionInfo motionInfo = moveInfo.getMotionInfo();
MotionState motionState = motionInfo.getState();
// Call entity move event.
EntityMoveEvent event =
new EntityMoveEvent(
entity,
new Position(motionInfo.getPos()),
new Position(motionInfo.getRot()),
motionState);
event.call();
entity.move(event.getPosition(), event.getRotation());
entity.setLastMoveSceneTimeMs(moveInfo.getSceneTime());
entity.setLastMoveReliableSeq(moveInfo.getReliableSeq());
entity.setMotionState(motionState);
session
.getPlayer()
.getStaminaManager()
.handleCombatInvocationsNotify(session, moveInfo, entity);
// TODO: handle MOTION_FIGHT landing which has a different damage factor
// Also, for plunge attacks, LAND_SPEED is always -30 and is not useful.
// May need the height when starting plunge attack.
// MOTION_LAND_SPEED and MOTION_FALL_ON_GROUND arrive in different packets.
// Cache land speed for later use.
if (motionState == MotionState.MOTION_STATE_LAND_SPEED) {
cachedLandingSpeed = motionInfo.getSpeed().getY();
cachedLandingTimeMillisecond = System.currentTimeMillis();
monitorLandingEvent = true;
}
if (monitorLandingEvent) {
if (motionState == MotionState.MOTION_STATE_FALL_ON_GROUND) {
monitorLandingEvent = false;
handleFallOnGround(session, entity, motionState);
}
}
// MOTION_STATE_NOTIFY = Dont send to other players
if (motionState == MotionState.MOTION_STATE_NOTIFY) {
continue;
}
}
}
case COMBAT_TYPE_ARGUMENT_ANIMATOR_PARAMETER_CHANGED -> {
EvtAnimatorParameterInfo paramInfo =
EvtAnimatorParameterInfo.parseFrom(entry.getCombatData());
if (paramInfo.getIsServerCache()) {
paramInfo = paramInfo.toBuilder().setIsServerCache(false).build();
entry = entry.toBuilder().setCombatData(paramInfo.toByteString()).build();
}
}
default -> {}
}
session.getPlayer().getCombatInvokeHandler().addEntry(entry.getForwardType(), entry);
}
}
private void handleFallOnGround(GameSession session, GameEntity entity, MotionState motionState) {
if (session.getPlayer().isInGodMode()) {
return;
}
// People have reported that after plunge attack (client sends a FIGHT instead of
// FALL_ON_GROUND) they will die
// if they talk to an NPC (this is when the client sends a FALL_ON_GROUND) without jumping
// again.
// A dirty patch: if not received immediately after MOTION_LAND_SPEED, discard this packet.
// 200ms seems to be a reasonable delay.
int maxDelay = 200;
long actualDelay = System.currentTimeMillis() - cachedLandingTimeMillisecond;
Grasscutter.getLogger()
.trace(
"MOTION_FALL_ON_GROUND received after "
+ actualDelay
+ "/"
+ maxDelay
+ "ms."
+ (actualDelay > maxDelay ? " Discard" : ""));
if (actualDelay > maxDelay) {
return;
}
float currentHP = entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
float maxHP = entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
float damageFactor = 0;
if (cachedLandingSpeed < -23.5) {
damageFactor = 0.33f;
}
if (cachedLandingSpeed < -25) {
damageFactor = 0.5f;
}
if (cachedLandingSpeed < -26.5) {
damageFactor = 0.66f;
}
if (cachedLandingSpeed < -28) {
damageFactor = 1f;
}
float damage = maxHP * damageFactor;
float newHP = currentHP - damage;
if (newHP < 0) {
newHP = 0;
}
if (damageFactor > 0) {
Grasscutter.getLogger()
.debug(
currentHP
+ "/"
+ maxHP
+ "\tLandingSpeed: "
+ cachedLandingSpeed
+ "\tDamageFactor: "
+ damageFactor
+ "\tDamage: "
+ damage
+ "\tNewHP: "
+ newHP);
} else {
Grasscutter.getLogger().trace(currentHP + "/" + maxHP + "\tLandingSpeed: 0\tNo damage");
}
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
entity
.getWorld()
.broadcastPacket(
new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
if (newHP == 0) {
session
.getPlayer()
.getStaminaManager()
.killAvatar(session, entity, PlayerDieTypeOuterClass.PlayerDieType.PLAYER_DIE_TYPE_FALL);
}
cachedLandingSpeed = 0;
}
}

View File

@@ -1,28 +1,29 @@
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.EvtDoSkillSuccNotifyOuterClass.EvtDoSkillSuccNotify;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.EvtDoSkillSuccNotify)
public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
EvtDoSkillSuccNotify notify = EvtDoSkillSuccNotify.parseFrom(payload);
var player = session.getPlayer();
int skillId = notify.getSkillId();
int casterId = notify.getCasterId();
// Call skill perform in the player's ability manager.
player.getAbilityManager().onSkillStart(session.getPlayer(), skillId, casterId);
// Handle skill notify in other managers.
player.getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
player.getEnergyManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
player.getQuestManager().triggerEvent(QuestContent.QUEST_CONTENT_SKILL, skillId, 0);
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.EvtDoSkillSuccNotifyOuterClass.EvtDoSkillSuccNotify;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.EvtDoSkillSuccNotify)
public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
EvtDoSkillSuccNotify notify = EvtDoSkillSuccNotify.parseFrom(payload);
var player = session.getPlayer();
int skillId = notify.getSkillId();
int casterId = notify.getCasterId();
// Call skill perform in the player's ability manager.
player.getAbilityManager().onSkillStart(session.getPlayer(), skillId, casterId);
// Handle skill notify in other managers.
player.getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
player.getEnergyManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_SKILL, skillId, 0);
}
}

View File

@@ -1,29 +1,29 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.ExecuteGadgetLuaReqOuterClass.ExecuteGadgetLuaReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketExecuteGadgetLuaRsp;
@Opcodes(PacketOpcodes.ExecuteGadgetLuaReq)
public class HandlerExecuteGadgetLuaReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
ExecuteGadgetLuaReq req = ExecuteGadgetLuaReq.parseFrom(payload);
Player player = session.getPlayer();
GameEntity entity = player.getScene().getEntities().get(req.getSourceEntityId());
int result = 1;
if (entity instanceof EntityGadget gadget)
result = gadget.onClientExecuteRequest(req.getParam1(), req.getParam2(), req.getParam3());
player.sendPacket(new PacketExecuteGadgetLuaRsp(result));
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.ExecuteGadgetLuaReqOuterClass.ExecuteGadgetLuaReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketExecuteGadgetLuaRsp;
@Opcodes(PacketOpcodes.ExecuteGadgetLuaReq)
public class HandlerExecuteGadgetLuaReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
ExecuteGadgetLuaReq req = ExecuteGadgetLuaReq.parseFrom(payload);
Player player = session.getPlayer();
GameEntity entity = player.getScene().getEntities().get(req.getSourceEntityId());
int result = 1;
if (entity instanceof EntityGadget gadget)
result = gadget.onClientExecuteRequest(req.getParam1(), req.getParam2(), req.getParam3());
player.sendPacket(new PacketExecuteGadgetLuaRsp(result));
}
}

View File

@@ -1,22 +1,23 @@
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.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.GadgetInteractReq)
public class HandlerGadgetInteractReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
GadgetInteractReq req = GadgetInteractReq.parseFrom(payload);
session
.getPlayer()
.getQuestManager()
.triggerEvent(QuestContent.QUEST_CONTENT_INTERACT_GADGET, req.getGadgetId());
session.getPlayer().interactWith(req.getGadgetEntityId(), req);
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.GadgetInteractReq)
public class HandlerGadgetInteractReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
GadgetInteractReq req = GadgetInteractReq.parseFrom(payload);
session
.getPlayer()
.getQuestManager()
.queueEvent(QuestContent.QUEST_CONTENT_INTERACT_GADGET, req.getGadgetId());
session.getPlayer().interactWith(req.getGadgetEntityId(), req);
}
}

View File

@@ -1,67 +1,66 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.activity.musicgame.MusicGameActivityHandler;
import emu.grasscutter.game.activity.musicgame.MusicGamePlayerData;
import emu.grasscutter.game.props.ActivityType;
import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.MusicGameSettleReqOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketActivityInfoNotify;
import emu.grasscutter.server.packet.send.PacketMusicGameSettleRsp;
@Opcodes(PacketOpcodes.MusicGameSettleReq)
public class HandlerMusicGameSettleReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = MusicGameSettleReqOuterClass.MusicGameSettleReq.parseFrom(payload);
var playerData =
session
.getPlayer()
.getActivityManager()
.getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_MUSIC_GAME);
if (playerData.isEmpty()) {
return;
}
var handler = (MusicGameActivityHandler) playerData.get().getActivityHandler();
boolean isNewRecord = false;
// check if custom beatmap
if (req.getUgcGuid() == 0) {
session
.getPlayer()
.getActivityManager()
.triggerWatcher(
WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE,
String.valueOf(req.getMusicBasicId()),
String.valueOf(req.getScore()));
isNewRecord =
handler.setMusicGameRecord(
playerData.get(),
MusicGamePlayerData.MusicGameRecord.of()
.musicId(req.getMusicBasicId())
.maxCombo(req.getMaxCombo())
.maxScore(req.getScore())
.build());
// update activity info
session.send(new PacketActivityInfoNotify(handler.toProto(playerData.get())));
} else {
handler.setMusicGameCustomBeatmapRecord(
playerData.get(),
MusicGamePlayerData.CustomBeatmapRecord.of()
.musicShareId(req.getUgcGuid())
.score(req.getMaxCombo())
// .settle(req.getSuccess())
.build());
}
session.send(
new PacketMusicGameSettleRsp(req.getMusicBasicId(), req.getUgcGuid(), isNewRecord));
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.activity.musicgame.MusicGameActivityHandler;
import emu.grasscutter.game.activity.musicgame.MusicGamePlayerData;
import emu.grasscutter.game.props.ActivityType;
import emu.grasscutter.game.props.WatcherTriggerType;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.MusicGameSettleReqOuterClass.MusicGameSettleReq;
import emu.grasscutter.net.proto.RetcodeOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketActivityInfoNotify;
import emu.grasscutter.server.packet.send.PacketMusicGameSettleRsp;
import lombok.val;
@Opcodes(PacketOpcodes.MusicGameSettleReq)
public class HandlerMusicGameSettleReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
val req = MusicGameSettleReq.parseFrom(payload);
val activityManager = session.getPlayer().getActivityManager();
val playerDataOpt = activityManager.getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_MUSIC_GAME);
if (playerDataOpt.isEmpty()) {
session.send(new PacketMusicGameSettleRsp(RetcodeOuterClass.Retcode.RET_MUSIC_GAME_LEVEL_CONFIG_NOT_FOUND, req));
return;
}
val playerData = playerDataOpt.get();
val handler = (MusicGameActivityHandler) playerData.getActivityHandler();
boolean isNewRecord = false;
// check if custom beatmap
if (req.getUgcGuid() == 0) {
session.getPlayer().getActivityManager().triggerWatcher(
WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE,
String.valueOf(req.getMusicBasicId()),
String.valueOf(req.getScore())
);
isNewRecord = handler.setMusicGameRecord(playerData,
MusicGamePlayerData.MusicGameRecord.of()
.musicId(req.getMusicBasicId())
.maxCombo(req.getMaxCombo())
.maxScore(req.getScore())
.build());
// update activity info
session.send(new PacketActivityInfoNotify(handler.toProto(playerData, activityManager.getConditionExecutor())));
} else {
handler.setMusicGameCustomBeatmapRecord(playerData,
MusicGamePlayerData.CustomBeatmapRecord.of()
.musicShareId(req.getUgcGuid())
.score(req.getMaxCombo())
.settle(req.getIsSaveScore())
.build());
}
session.send(new PacketMusicGameSettleRsp(req.getMusicBasicId(), req.getUgcGuid(), isNewRecord));
}
}

View File

@@ -1,66 +1,67 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.MainQuestData;
import emu.grasscutter.data.binout.MainQuestData.TalkData;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.NpcTalkReqOuterClass.NpcTalkReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketNpcTalkRsp;
@Opcodes(PacketOpcodes.NpcTalkReq)
public class HandlerNpcTalkReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
NpcTalkReq req = NpcTalkReq.parseFrom(payload);
// Check if mainQuest exists
// remove last 2 digits to get a mainQuestId
int talkId = req.getTalkId();
int mainQuestId = talkId / 100;
MainQuestData mainQuestData = GameData.getMainQuestDataMap().get(mainQuestId);
if (mainQuestData != null) {
// This talk is associated with a quest. Handle it.
// If the quest has no talk data defined on it, create one.
TalkData talkForQuest = new TalkData(talkId, "");
if (mainQuestData.getTalks() != null) {
var talks = mainQuestData.getTalks().stream().filter(p -> p.getId() == talkId).toList();
if (talks.size() > 0) {
talkForQuest = talks.get(0);
}
}
// Add to the list of done talks for this quest.
var mainQuest = session.getPlayer().getQuestManager().getMainQuestById(mainQuestId);
if (mainQuest != null) {
session
.getPlayer()
.getQuestManager()
.getMainQuestById(mainQuestId)
.getTalks()
.put(talkId, talkForQuest);
}
// Fire quest triggers.
session
.getPlayer()
.getQuestManager()
.triggerEvent(
QuestContent.QUEST_CONTENT_COMPLETE_ANY_TALK, String.valueOf(req.getTalkId()), 0, 0);
session
.getPlayer()
.getQuestManager()
.triggerEvent(QuestContent.QUEST_CONTENT_COMPLETE_TALK, req.getTalkId(), 0);
session
.getPlayer()
.getQuestManager()
.triggerEvent(QuestContent.QUEST_CONTENT_FINISH_PLOT, req.getTalkId(), 0);
}
session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId()));
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.MainQuestData;
import emu.grasscutter.data.binout.MainQuestData.TalkData;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.NpcTalkReqOuterClass.NpcTalkReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketNpcTalkRsp;
@Opcodes(PacketOpcodes.NpcTalkReq)
public class HandlerNpcTalkReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
NpcTalkReq req = NpcTalkReq.parseFrom(payload);
// Check if mainQuest exists
// remove last 2 digits to get a mainQuestId
int talkId = req.getTalkId();
int mainQuestId = talkId / 100;
MainQuestData mainQuestData = GameData.getMainQuestDataMap().get(mainQuestId);
if (mainQuestData != null) {
// This talk is associated with a quest. Handle it.
// If the quest has no talk data defined on it, create one.
TalkData talkForQuest = new TalkData(talkId, "");
if (mainQuestData.getTalks() != null) {
var talks = mainQuestData.getTalks().stream().filter(p -> p.getId() == talkId).toList();
if (talks.size() > 0) {
talkForQuest = talks.get(0);
}
}
// Add to the list of done talks for this quest.
var mainQuest = session.getPlayer().getQuestManager().getMainQuestById(mainQuestId);
if (mainQuest != null) {
session
.getPlayer()
.getQuestManager()
.getMainQuestById(mainQuestId)
.getTalks()
.put(talkId, talkForQuest);
}
// Fire quest triggers.
session
.getPlayer()
.getQuestManager()
.queueEvent(
QuestContent.QUEST_CONTENT_COMPLETE_ANY_TALK, String.valueOf(req.getTalkId()), 0, 0);
session
.getPlayer()
.getQuestManager()
.queueEvent(QuestContent.QUEST_CONTENT_COMPLETE_TALK, req.getTalkId(), 0);
session
.getPlayer()
.getQuestManager()
.queueEvent(QuestContent.QUEST_CONTENT_FINISH_PLOT, req.getTalkId(), 0);
}
session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId()));
}
}

View File

@@ -1,24 +1,25 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketPostEnterSceneRsp;
@Opcodes(PacketOpcodes.PostEnterSceneReq)
public class HandlerPostEnterSceneReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
if (session.getPlayer().getScene().getSceneType() == SceneType.SCENE_ROOM) {
session
.getPlayer()
.getQuestManager()
.triggerEvent(QuestContent.QUEST_CONTENT_ENTER_ROOM, session.getPlayer().getSceneId(), 0);
}
session.send(new PacketPostEnterSceneRsp(session.getPlayer()));
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketPostEnterSceneRsp;
@Opcodes(PacketOpcodes.PostEnterSceneReq)
public class HandlerPostEnterSceneReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
if (session.getPlayer().getScene().getSceneType() == SceneType.SCENE_ROOM) {
session
.getPlayer()
.getQuestManager()
.queueEvent(QuestContent.QUEST_CONTENT_ENTER_ROOM, session.getPlayer().getSceneId(), 0);
}
session.send(new PacketPostEnterSceneRsp(session.getPlayer()));
}
}

View File

@@ -1,40 +1,39 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketSelectWorktopOptionRsp;
@Opcodes(PacketOpcodes.SelectWorktopOptionReq)
public class HandlerSelectWorktopOptionReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
SelectWorktopOptionReq req = SelectWorktopOptionReq.parseFrom(payload);
try {
GameEntity entity = session.getPlayer().getScene().getEntityById(req.getGadgetEntityId());
if (!(entity instanceof EntityGadget)) {
return;
}
session.getPlayer().getScene().selectWorktopOptionWith(req);
session
.getPlayer()
.getScene()
.getScriptManager()
.callEvent(
EventType.EVENT_SELECT_OPTION,
new ScriptArgs(entity.getConfigId(), req.getOptionId()));
} finally {
// Always send packet
session.send(new PacketSelectWorktopOptionRsp(req.getGadgetEntityId(), req.getOptionId()));
}
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.quest.enums.QuestContent;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketSelectWorktopOptionRsp;
@Opcodes(PacketOpcodes.SelectWorktopOptionReq)
public class HandlerSelectWorktopOptionReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
SelectWorktopOptionReq req = SelectWorktopOptionReq.parseFrom(payload);
try {
GameEntity entity = session.getPlayer().getScene().getEntityById(req.getGadgetEntityId());
if (!(entity instanceof EntityGadget)) {
return;
}
session.getPlayer().getScene().selectWorktopOptionWith(req);
session.getPlayer().getScene().getScriptManager().callEvent(
new ScriptArgs(entity.getGroupId(), EventType.EVENT_SELECT_OPTION, entity.getConfigId(), req.getOptionId())
);
session.getPlayer().getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_WORKTOP_SELECT, entity.getConfigId(), req.getOptionId());
} finally {
// Always send packet
session.send(new PacketSelectWorktopOptionRsp(req.getGadgetEntityId(), req.getOptionId()));
}
}
}

View File

@@ -14,7 +14,7 @@ public class HandlerSkipPlayerGameTimeReq extends PacketHandler {
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var req = SkipPlayerGameTimeReqOuterClass.SkipPlayerGameTimeReq.parseFrom(payload);
var player = session.getPlayer();
player.getScene().setTime(req.getGameTime());
player.updatePlayerGameTime(req.getGameTime());
player.getScene().broadcastPacket(new PacketPlayerGameTimeNotify(player));
player.sendPacket(new PacketSkipPlayerGameTimeRsp(req));
}

View File

@@ -1,34 +1,27 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.entity.platform.EntityPlatform;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.UpdateAbilityCreatedMovingPlatformNotifyOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketPlatformStartRouteNotify;
import emu.grasscutter.server.packet.send.PacketPlatformStopRouteNotify;
@Opcodes(PacketOpcodes.UpdateAbilityCreatedMovingPlatformNotify)
public class HandlerUpdateAbilityCreatedMovingPlatformNotify extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var notify =
UpdateAbilityCreatedMovingPlatformNotifyOuterClass.UpdateAbilityCreatedMovingPlatformNotify
.parseFrom(payload);
var entity = session.getPlayer().getScene().getEntityById(notify.getEntityId());
if (!(entity instanceof EntityPlatform)) {
return;
}
var scene = ((EntityPlatform) entity).getOwner().getScene();
switch (notify.getOpType()) {
case OP_TYPE_ACTIVATE -> scene.broadcastPacket(
new PacketPlatformStartRouteNotify((EntityPlatform) entity, scene));
case OP_TYPE_DEACTIVATE -> scene.broadcastPacket(
new PacketPlatformStopRouteNotify((EntityPlatform) entity, scene));
}
}
}
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.gadget.platform.AbilityRoute;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.UpdateAbilityCreatedMovingPlatformNotifyOuterClass.UpdateAbilityCreatedMovingPlatformNotify;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.UpdateAbilityCreatedMovingPlatformNotify)
public class HandlerUpdateAbilityCreatedMovingPlatformNotify extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
var notify = UpdateAbilityCreatedMovingPlatformNotify.parseFrom(payload);
var entity = session.getPlayer().getScene().getEntityById(notify.getEntityId());
if (!(entity instanceof EntityGadget entityGadget) || !(entityGadget.getRouteConfig() instanceof AbilityRoute)) {
return;
}
switch (notify.getOpType()) {
case OP_TYPE_ACTIVATE -> entityGadget.startPlatform();
case OP_TYPE_DEACTIVATE -> entityGadget.stopPlatform();
}
}
}

View File

@@ -1,18 +1,18 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.ChangeGameTimeRspOuterClass.ChangeGameTimeRsp;
public class PacketChangeGameTimeRsp extends BasePacket {
public PacketChangeGameTimeRsp(Player player) {
super(PacketOpcodes.ChangeGameTimeRsp);
ChangeGameTimeRsp proto =
ChangeGameTimeRsp.newBuilder().setCurGameTime(player.getScene().getTime()).build();
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.ChangeGameTimeRspOuterClass.ChangeGameTimeRsp;
public class PacketChangeGameTimeRsp extends BasePacket {
public PacketChangeGameTimeRsp(Player player) {
super(PacketOpcodes.ChangeGameTimeRsp);
ChangeGameTimeRsp proto =
ChangeGameTimeRsp.newBuilder().setCurGameTime(player.getWorld().getGameTime()).build();
this.setData(proto);
}
}

View File

@@ -1,64 +1,13 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DungeonSettleNotifyOuterClass.DungeonSettleNotify;
import emu.grasscutter.net.proto.ItemParamOuterClass;
import emu.grasscutter.net.proto.TowerLevelEndNotifyOuterClass.TowerLevelEndNotify;
public class PacketDungeonSettleNotify extends BasePacket {
public PacketDungeonSettleNotify(WorldChallenge challenge) {
super(PacketOpcodes.DungeonSettleNotify);
DungeonSettleNotify proto =
DungeonSettleNotify.newBuilder()
.setDungeonId(challenge.getScene().getDungeonData().getId())
.setIsSuccess(challenge.isSuccess())
.setCloseTime(challenge.getScene().getAutoCloseTime())
.setResult(challenge.isSuccess() ? 1 : 0)
.build();
this.setData(proto);
}
public PacketDungeonSettleNotify(
WorldChallenge challenge, boolean canJump, boolean hasNextLevel, int nextFloorId) {
super(PacketOpcodes.DungeonSettleNotify);
var continueStatus =
TowerLevelEndNotify.ContinueStateType.CONTINUE_STATE_TYPE_CAN_NOT_CONTINUE_VALUE;
if (challenge.isSuccess() && canJump) {
continueStatus =
hasNextLevel
? TowerLevelEndNotify.ContinueStateType.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_LEVEL_VALUE
: TowerLevelEndNotify.ContinueStateType
.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_FLOOR_VALUE;
}
var towerLevelEndNotify =
TowerLevelEndNotify.newBuilder()
.setIsSuccess(challenge.isSuccess())
.setContinueState(continueStatus)
.addFinishedStarCondList(1)
.addFinishedStarCondList(2)
.addFinishedStarCondList(3)
.addRewardItemList(
ItemParamOuterClass.ItemParam.newBuilder().setItemId(201).setCount(1000).build());
if (nextFloorId > 0 && canJump) {
towerLevelEndNotify.setNextFloorId(nextFloorId);
}
DungeonSettleNotify proto =
DungeonSettleNotify.newBuilder()
.setDungeonId(challenge.getScene().getDungeonData().getId())
.setIsSuccess(challenge.isSuccess())
.setCloseTime(challenge.getScene().getAutoCloseTime())
.setResult(challenge.isSuccess() ? 1 : 0)
.setTowerLevelEndNotify(towerLevelEndNotify.build())
.build();
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
public class PacketDungeonSettleNotify extends BasePacket {
public PacketDungeonSettleNotify(BaseDungeonResult result) {
super(PacketOpcodes.DungeonSettleNotify);
this.setData(result.getProto());
}
}

View File

@@ -1,22 +1,33 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.EntityFightPropUpdateNotifyOuterClass.EntityFightPropUpdateNotify;
public class PacketEntityFightPropUpdateNotify extends BasePacket {
public PacketEntityFightPropUpdateNotify(GameEntity entity, FightProperty prop) {
super(PacketOpcodes.EntityFightPropUpdateNotify);
EntityFightPropUpdateNotify proto =
EntityFightPropUpdateNotify.newBuilder()
.setEntityId(entity.getId())
.putFightPropMap(prop.getId(), entity.getFightProperty(prop))
.build();
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.EntityFightPropUpdateNotifyOuterClass.EntityFightPropUpdateNotify;
import java.util.Collection;
public class PacketEntityFightPropUpdateNotify extends BasePacket {
public PacketEntityFightPropUpdateNotify(GameEntity entity, FightProperty prop) {
super(PacketOpcodes.EntityFightPropUpdateNotify);
EntityFightPropUpdateNotify proto =
EntityFightPropUpdateNotify.newBuilder()
.setEntityId(entity.getId())
.putFightPropMap(prop.getId(), entity.getFightProperty(prop))
.build();
this.setData(proto);
}
public PacketEntityFightPropUpdateNotify(GameEntity entity, Collection<FightProperty> props) {
super(PacketOpcodes.EntityFightPropUpdateNotify);
var protoBuilder = EntityFightPropUpdateNotify.newBuilder()
.setEntityId(entity.getId());
props.forEach(p -> protoBuilder.putFightPropMap(p.getId(), entity.getFightProperty(p)));
this.setData(protoBuilder);
}
}

View File

@@ -1,26 +1,26 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.GameMainQuest;
import emu.grasscutter.game.quest.enums.ParentQuestState;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.FinishedParentQuestNotifyOuterClass.FinishedParentQuestNotify;
public class PacketFinishedParentQuestNotify extends BasePacket {
public PacketFinishedParentQuestNotify(Player player) {
super(PacketOpcodes.FinishedParentQuestNotify, true);
FinishedParentQuestNotify.Builder proto = FinishedParentQuestNotify.newBuilder();
for (GameMainQuest mainQuest : player.getQuestManager().getMainQuests().values()) {
// Canceled Quests do not appear in this packet
if (mainQuest.getState() != ParentQuestState.PARENT_QUEST_STATE_CANCELED) {
proto.addParentQuestList(mainQuest.toProto());
}
}
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.GameMainQuest;
import emu.grasscutter.game.quest.enums.ParentQuestState;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.FinishedParentQuestNotifyOuterClass.FinishedParentQuestNotify;
public class PacketFinishedParentQuestNotify extends BasePacket {
public PacketFinishedParentQuestNotify(Player player) {
super(PacketOpcodes.FinishedParentQuestNotify, true);
FinishedParentQuestNotify.Builder proto = FinishedParentQuestNotify.newBuilder();
for (GameMainQuest mainQuest : player.getQuestManager().getMainQuests().values()) {
//Canceled Quests do not appear in this packet
if (mainQuest.getState() != ParentQuestState.PARENT_QUEST_STATE_CANCELED) {
proto.addParentQuestList(mainQuest.toProto(false));
}
}
this.setData(proto);
}
}

View File

@@ -1,31 +1,33 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.quest.GameMainQuest;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.FinishedParentQuestUpdateNotifyOuterClass.FinishedParentQuestUpdateNotify;
import java.util.List;
public class PacketFinishedParentQuestUpdateNotify extends BasePacket {
public PacketFinishedParentQuestUpdateNotify(GameMainQuest quest) {
super(PacketOpcodes.FinishedParentQuestUpdateNotify);
FinishedParentQuestUpdateNotify proto =
FinishedParentQuestUpdateNotify.newBuilder().addParentQuestList(quest.toProto()).build();
this.setData(proto);
}
public PacketFinishedParentQuestUpdateNotify(List<GameMainQuest> quests) {
super(PacketOpcodes.FinishedParentQuestUpdateNotify);
var proto = FinishedParentQuestUpdateNotify.newBuilder();
for (GameMainQuest mainQuest : quests) {
proto.addParentQuestList(mainQuest.toProto());
}
proto.build();
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.quest.GameMainQuest;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.FinishedParentQuestUpdateNotifyOuterClass.FinishedParentQuestUpdateNotify;
import java.util.List;
public class PacketFinishedParentQuestUpdateNotify extends BasePacket {
public PacketFinishedParentQuestUpdateNotify(GameMainQuest quest) {
super(PacketOpcodes.FinishedParentQuestUpdateNotify);
FinishedParentQuestUpdateNotify proto = FinishedParentQuestUpdateNotify.newBuilder()
.addParentQuestList(quest.toProto(true))
.build();
this.setData(proto);
}
public PacketFinishedParentQuestUpdateNotify(List<GameMainQuest> quests) {
super(PacketOpcodes.FinishedParentQuestUpdateNotify);
var proto = FinishedParentQuestUpdateNotify.newBuilder();
for (GameMainQuest mainQuest : quests) {
proto.addParentQuestList(mainQuest.toProto(true));
}
proto.build();
this.setData(proto);
}
}

View File

@@ -1,11 +1,11 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
public class PacketHomeUnknown2Rsp extends BasePacket {
public PacketHomeUnknown2Rsp() {
super(PacketOpcodes.Unk2700_KIIOGMKFNNP_ServerRsp);
}
}
//package emu.grasscutter.server.packet.send;
//
//import emu.grasscutter.net.packet.BasePacket;
//import emu.grasscutter.net.packet.PacketOpcodes;
//
//public class PacketHomeUnknown2Rsp extends BasePacket {
//
// public PacketHomeUnknown2Rsp() {
// super(PacketOpcodes.Unk2700_KIIOGMKFNNP_ServerRsp);
// }
//}

View File

@@ -1,18 +1,32 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.MusicGameSettleRspOuterClass;
public class PacketMusicGameSettleRsp extends BasePacket {
public PacketMusicGameSettleRsp(int musicBasicId, long musicShareId, boolean isNewRecord) {
super(PacketOpcodes.MusicGameSettleRsp);
var proto = MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder();
proto.setMusicBasicId(musicBasicId).setUgcGuid(musicShareId).setIsNewRecord(isNewRecord);
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.MusicGameSettleReqOuterClass;
import emu.grasscutter.net.proto.MusicGameSettleRspOuterClass;
import emu.grasscutter.net.proto.RetcodeOuterClass;
public class PacketMusicGameSettleRsp extends BasePacket {
public PacketMusicGameSettleRsp(int musicBasicId, long musicShareId, boolean isNewRecord) {
super(PacketOpcodes.MusicGameSettleRsp);
var proto = MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder();
proto.setMusicBasicId(musicBasicId).setUgcGuid(musicShareId).setIsNewRecord(isNewRecord);
this.setData(proto);
}
public PacketMusicGameSettleRsp(RetcodeOuterClass.Retcode errorCode, MusicGameSettleReqOuterClass.MusicGameSettleReq req) {
super(PacketOpcodes.MusicGameSettleRsp);
var proto = MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder()
.setRetcode(errorCode.getNumber())
.setMusicBasicId(req.getMusicBasicId())
.setUgcGuid(req.getUgcGuid());
this.setData(proto);
}
}

View File

@@ -1,22 +1,20 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.entity.platform.EntityPlatform;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PlatformStartRouteNotifyOuterClass;
public class PacketPlatformStartRouteNotify extends BasePacket {
public PacketPlatformStartRouteNotify(EntityPlatform entity, Scene scene) {
super(PacketOpcodes.PlatformStartRouteNotify);
var notify =
PlatformStartRouteNotifyOuterClass.PlatformStartRouteNotify.newBuilder()
.setEntityId(entity.getId())
.setSceneTime(scene.getSceneTime())
.setPlatform(entity.onStartRoute())
.build();
this.setData(notify);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PlatformStartRouteNotifyOuterClass.PlatformStartRouteNotify;
import lombok.val;
public class PacketPlatformStartRouteNotify extends BasePacket {
public PacketPlatformStartRouteNotify(EntityGadget gadgetEntity) {
super(PacketOpcodes.PlatformStartRouteNotify);
val notify = PlatformStartRouteNotify.newBuilder()
.setEntityId(gadgetEntity.getId())
.setSceneTime(gadgetEntity.getScene().getSceneTime())
.setPlatform(gadgetEntity.getPlatformInfo());
this.setData(notify);
}
}

View File

@@ -1,22 +1,20 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.entity.platform.EntityPlatform;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PlatformStopRouteNotifyOuterClass;
public class PacketPlatformStopRouteNotify extends BasePacket {
public PacketPlatformStopRouteNotify(EntityPlatform entity, Scene scene) {
super(PacketOpcodes.PlatformStopRouteNotify);
var notify =
PlatformStopRouteNotifyOuterClass.PlatformStopRouteNotify.newBuilder()
.setPlatform(entity.onStopRoute())
.setSceneTime(scene.getSceneTime())
.setEntityId(entity.getId())
.build();
this.setData(notify);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PlatformStopRouteNotifyOuterClass;
public class PacketPlatformStopRouteNotify extends BasePacket {
public PacketPlatformStopRouteNotify(EntityGadget gadgetEntity) {
super(PacketOpcodes.PlatformStopRouteNotify);
var notify = PlatformStopRouteNotifyOuterClass.PlatformStopRouteNotify.newBuilder()
.setPlatform(gadgetEntity.getPlatformInfo())
.setSceneTime(gadgetEntity.getScene().getSceneTime())
.setEntityId(gadgetEntity.getId())
.build();
this.setData(notify);
}
}

View File

@@ -1,21 +1,21 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PlayerGameTimeNotifyOuterClass.PlayerGameTimeNotify;
public class PacketPlayerGameTimeNotify extends BasePacket {
public PacketPlayerGameTimeNotify(Player player) {
super(PacketOpcodes.PlayerGameTimeNotify);
PlayerGameTimeNotify proto =
PlayerGameTimeNotify.newBuilder()
.setGameTime(player.getScene().getTime())
.setUid(player.getUid())
.build();
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PlayerGameTimeNotifyOuterClass.PlayerGameTimeNotify;
public class PacketPlayerGameTimeNotify extends BasePacket {
public PacketPlayerGameTimeNotify(Player player) {
super(PacketOpcodes.PlayerGameTimeNotify);
PlayerGameTimeNotify proto =
PlayerGameTimeNotify.newBuilder()
.setGameTime(player.getWorld().getGameTime())
.setUid(player.getUid())
.build();
this.setData(proto);
}
}