diff --git a/proxy.py b/proxy.py index b352af3ac..2d2282af9 100644 --- a/proxy.py +++ b/proxy.py @@ -21,43 +21,45 @@ ## from mitmproxy import http +from proxy_config import REMOTE_HOST class MlgmXyysd_Genshin_Impact_Proxy: + LIST_DOMAINS = [ + "api-os-takumi.mihoyo.com", + "hk4e-api-os-static.mihoyo.com", + "hk4e-sdk-os.mihoyo.com", + "dispatchosglobal.yuanshen.com", + "osusadispatch.yuanshen.com", + "account.mihoyo.com", + "log-upload-os.mihoyo.com", + "dispatchcntest.yuanshen.com", + "devlog-upload.mihoyo.com", + "webstatic.mihoyo.com", + "log-upload.mihoyo.com", + "hk4e-sdk.mihoyo.com", + "api-beta-sdk.mihoyo.com", + "api-beta-sdk-os.mihoyo.com", + "cnbeta01dispatch.yuanshen.com", + "dispatchcnglobal.yuanshen.com", + "cnbeta02dispatch.yuanshen.com", + "sdk-os-static.mihoyo.com", + "webstatic-sea.mihoyo.com", + "webstatic-sea.hoyoverse.com", + "hk4e-sdk-os-static.hoyoverse.com", + "sdk-os-static.hoyoverse.com", + "api-account-os.hoyoverse.com", + "hk4e-sdk-os.hoyoverse.com", + "overseauspider.yuanshen.com", + "gameapi-account.mihoyo.com", + "minor-api.mihoyo.com", + "public-data-api.mihoyo.com", + "uspider.yuanshen.com", + "sdk-static.mihoyo.com" + ] + def request(self, flow: http.HTTPFlow) -> None: - - # This can also be replaced with another IP address. - REMOTE_HOST = "localhost" - - LIST_DOMAINS = [ - "api-os-takumi.mihoyo.com", - "hk4e-api-os-static.mihoyo.com", - "hk4e-sdk-os.mihoyo.com", - "dispatchosglobal.yuanshen.com", - "osusadispatch.yuanshen.com", - "account.mihoyo.com", - "log-upload-os.mihoyo.com", - "dispatchcntest.yuanshen.com", - "devlog-upload.mihoyo.com", - "webstatic.mihoyo.com", - "log-upload.mihoyo.com", - "hk4e-sdk.mihoyo.com", - "api-beta-sdk.mihoyo.com", - "api-beta-sdk-os.mihoyo.com", - "cnbeta01dispatch.yuanshen.com", - "dispatchcnglobal.yuanshen.com", - "cnbeta02dispatch.yuanshen.com", - "sdk-os-static.mihoyo.com", - "webstatic-sea.mihoyo.com", - "webstatic-sea.hoyoverse.com", - "hk4e-sdk-os-static.hoyoverse.com", - "sdk-os-static.hoyoverse.com", - "api-account-os.hoyoverse.com", - "hk4e-sdk-os.hoyoverse.com", - "overseauspider.yuanshen.com" - ] - - if flow.request.host in LIST_DOMAINS: + if flow.request.host in self.LIST_DOMAINS: flow.request.host = REMOTE_HOST addons = [ diff --git a/proxy_config.py b/proxy_config.py new file mode 100644 index 000000000..f048ef88c --- /dev/null +++ b/proxy_config.py @@ -0,0 +1,2 @@ +# This can also be replaced with another IP address. +REMOTE_HOST = "localhost" \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/commands/PlayerCommands.java b/src/main/java/emu/grasscutter/commands/PlayerCommands.java index 4b7a2b8e1..a488b7f31 100644 --- a/src/main/java/emu/grasscutter/commands/PlayerCommands.java +++ b/src/main/java/emu/grasscutter/commands/PlayerCommands.java @@ -16,10 +16,12 @@ import emu.grasscutter.game.entity.EntityMonster; import emu.grasscutter.game.inventory.GenshinItem; import emu.grasscutter.game.inventory.Inventory; import emu.grasscutter.game.inventory.ItemType; +import emu.grasscutter.game.props.ClimateType; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; +import emu.grasscutter.server.packet.send.PacketSceneAreaWeatherNotify; import emu.grasscutter.server.packet.send.PacketGetPlayerTokenRsp; import emu.grasscutter.server.packet.send.PacketItemAddHintNotify; import emu.grasscutter.server.packet.send.PacketPlayerLoginRsp; @@ -455,32 +457,111 @@ public final class PlayerCommands { } } - @Command(label = "sethealth", aliases = {"sethp"}, - usage = "sethealth ", execution = Command.Execution.PLAYER, description = "Sets your health to the specified value", - permission = "player.sethealth") - public static class SetHealthCommand implements CommandHandler { - - @Override +@Command(label = "setstats", aliases = {"stats"}, + usage = "Usage: setstats|stats ", execution = Command.Execution.PLAYER) + public static class SetStatsCommand implements CommandHandler { + @Override public void execute(GenshinPlayer player, List args) { - if (args.size() < 1) { - CommandHandler.sendMessage(null, "Usage: sethealth "); - return; - } - - try { - int health = Integer.parseInt(args.get(0)); - EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity(); - if (entity == null) + String stat = args.get(0); + switch(stat){ + default: + CommandHandler.sendMessage(player, "Usage: setstats|stats "); return; - - entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, health); - entity.getWorld().broadcastPacket( - new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP)); - player.dropMessage("Health set to " + health + "."); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(null, "Invalid health value."); + case "hp": + try { + int health = Integer.parseInt(args.get(1)); + EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity(); + entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, health); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP)); + player.dropMessage("HP set to " + health + "."); + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(null, "Invalid HP value."); + return; + } + break; + case "def": + try { + int def = Integer.parseInt(args.get(1)); + EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity(); + entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE, def); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_DEFENSE)); + player.dropMessage("DEF set to " + def + "."); + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(null, "Invalid DEF value."); + return; + } + break; + case "atk": + try { + int atk = Integer.parseInt(args.get(1)); + EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity(); + entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK, atk); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_ATTACK)); + player.dropMessage("ATK set to " + atk + "."); + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(null, "Invalid ATK value."); + return; + } + break; + case "em": + try { + int em = Integer.parseInt(args.get(1)); + EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity(); + entity.setFightProperty(FightProperty.FIGHT_PROP_ELEMENT_MASTERY, em); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_ELEMENT_MASTERY)); + player.dropMessage("Elemental Mastery set to " + em + "."); + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(null, "Invalid EM value."); + return; + } + break; + case "er": + try { + float er = Integer.parseInt(args.get(1)); + EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity(); + float erecharge = er / 10000; + entity.setFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, erecharge); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY)); + float iger = erecharge * 100; + player.dropMessage("Energy recharge set to " + iger + "%."); + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(null, "Invalid ER value."); + return; + } + break; + case "crate": + try { + float cr = Integer.parseInt(args.get(1)); + EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity(); + float crate = cr / 10000; + entity.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL, crate); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CRITICAL)); + float igcrate = crate * 100; + player.dropMessage("Crit Rate set to " + igcrate + "%."); + + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(null, "Invalid Crit Rate value."); + return; + } + break; + case "cdmg": + try { + float cdmg = Integer.parseInt(args.get(1)); + EntityAvatar entity = player.getTeamManager().getCurrentAvatarEntity(); + float cdamage = cdmg / 10000; + entity.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL_HURT, cdamage); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CRITICAL_HURT)); + float igcdmg = cdamage * 100; + player.dropMessage("Crit DMG set to " + igcdmg + "%"); + + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(null, "Invalid Crit DMG value."); + return; + } + break; + } - } + } } @Command(label = "setworldlevel", aliases = {"setworldlvl"}, usage = "setworldlevel ", @@ -573,6 +654,42 @@ public final class PlayerCommands { } } } + + @Command(label = "pos", + usage = "Usage: pos", description = "Get coordinates.", + execution = Command.Execution.PLAYER) + public static class CordCommand implements CommandHandler { + + @Override + public void execute(GenshinPlayer player, List args) { + player.dropMessage(String.format("Coord: %.3f, %.3f, %.3f", player.getPos().getX(), player.getPos().getY(), player.getPos().getZ())); + } + } + + @Command(label = "weather", aliases = {"weather", "w"}, + usage = "weather ", description = "Changes the weather.", + execution = Command.Execution.PLAYER, permission = "player.weather" + ) + public static class ChangeWeatherCommand implements CommandHandler { + @Override + public void execute(GenshinPlayer player, List args) { + if (args.size() < 1) { + CommandHandler.sendMessage(player, "Usage: weather "); + return; + } + + try { + int weatherId = Integer.parseInt(args.get(0)); + + ClimateType climate = ClimateType.getTypeByValue(weatherId); + + player.getScene().setClimate(climate); + player.getScene().broadcastPacket(new PacketSceneAreaWeatherNotify(player)); + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(player, "Invalid weather ID."); + } + } + } @Command(label = "restart", usage = "Usage: restart", description = "Restarts the current session", execution = Command.Execution.PLAYER, permission = "player.restart") public static class RestartCommand implements CommandHandler { diff --git a/src/main/java/emu/grasscutter/game/GenshinPlayer.java b/src/main/java/emu/grasscutter/game/GenshinPlayer.java index 70fea04f0..1d8650e54 100644 --- a/src/main/java/emu/grasscutter/game/GenshinPlayer.java +++ b/src/main/java/emu/grasscutter/game/GenshinPlayer.java @@ -38,6 +38,7 @@ import emu.grasscutter.server.packet.send.PacketAvatarAddNotify; import emu.grasscutter.server.packet.send.PacketAvatarDataNotify; import emu.grasscutter.server.packet.send.PacketAvatarGainCostumeNotify; import emu.grasscutter.server.packet.send.PacketAvatarGainFlycloakNotify; +import emu.grasscutter.server.packet.send.PacketClientAbilityInitFinishNotify; import emu.grasscutter.server.packet.send.PacketCombatInvocationsNotify; import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp; import emu.grasscutter.server.packet.send.PacketItemAddHintNotify; @@ -104,6 +105,7 @@ public class GenshinPlayer { @Transient private final Int2ObjectMap coopRequests; @Transient private final InvokeHandler combatInvokeHandler; @Transient private final InvokeHandler abilityInvokeHandler; + @Transient private final InvokeHandler clientAbilityInitFinishHandler; @Deprecated @SuppressWarnings({ "rawtypes", "unchecked" }) // Morphia only! public GenshinPlayer() { @@ -126,6 +128,7 @@ public class GenshinPlayer { this.coopRequests = new Int2ObjectOpenHashMap<>(); this.combatInvokeHandler = new InvokeHandler(PacketCombatInvocationsNotify.class); this.abilityInvokeHandler = new InvokeHandler(PacketAbilityInvocationsNotify.class); + this.clientAbilityInitFinishHandler = new InvokeHandler(PacketClientAbilityInitFinishNotify.class); } // On player creation @@ -389,6 +392,10 @@ public class GenshinPlayer { return this.abilityInvokeHandler; } + public InvokeHandler getClientAbilityInitFinishHandler() { + return clientAbilityInitFinishHandler; + } + public void setMpSetting(MpSettingType mpSetting) { this.mpSetting = mpSetting; } diff --git a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java index dab6ba0a4..f13b9dc2f 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java +++ b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java @@ -226,18 +226,22 @@ public final class DispatchServer { Account account = DatabaseHelper.getAccountByName(requestData.account); // Check if account exists, else create a new one. - if (account == null && Grasscutter.getConfig().ServerOptions.AutomaticallyCreateAccounts) { - // This account has been created AUTOMATICALLY. There will be no permissions added. - account = DatabaseHelper.createAccountWithId(requestData.account, 0); - - responseData.message = "OK"; - responseData.data.account.uid = account.getId(); - responseData.data.account.token = account.generateSessionKey(); - responseData.data.account.email = account.getEmail(); - } else if (!Grasscutter.getConfig().ServerOptions.AutomaticallyCreateAccounts) { - responseData.retcode = -201; - responseData.message = "Username not found."; + if (account == null) { + // Account doesnt exist, so we can either auto create it if the config value is set + if (Grasscutter.getConfig().ServerOptions.AutomaticallyCreateAccounts) { + // This account has been created AUTOMATICALLY. There will be no permissions added. + account = DatabaseHelper.createAccountWithId(requestData.account, 0); + + responseData.message = "OK"; + responseData.data.account.uid = account.getId(); + responseData.data.account.token = account.generateSessionKey(); + responseData.data.account.email = account.getEmail(); + } else { + responseData.retcode = -201; + responseData.message = "Username not found."; + } } else { + // Account was found, log the player in responseData.message = "OK"; responseData.data.account.uid = account.getId(); responseData.data.account.token = account.generateSessionKey(); diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 282589a4b..291f303d7 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -154,7 +154,7 @@ public final class GameServer extends MihoyoKcpServer { public Account getAccountByName(String username) { Optional playerOpt = getPlayers().values().stream().filter(player -> player.getAccount().getUsername().equals(username)).findFirst(); - if (playerOpt.get() != null) { + if (playerOpt.isPresent()) { return playerOpt.get().getAccount(); } return DatabaseHelper.getAccountByName(username); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerClientAbilityInitFinishNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerClientAbilityInitFinishNotify.java new file mode 100644 index 000000000..cfe697b91 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerClientAbilityInitFinishNotify.java @@ -0,0 +1,26 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; +import emu.grasscutter.net.proto.ClientAbilityInitFinishNotifyOuterClass.ClientAbilityInitFinishNotify; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.server.game.GameSession; + +@Opcodes(PacketOpcodes.ClientAbilityInitFinishNotify) +public class HandlerClientAbilityInitFinishNotify extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + ClientAbilityInitFinishNotify notif = ClientAbilityInitFinishNotify.parseFrom(payload); + + for (AbilityInvokeEntry entry : notif.getInvokesList()) { + session.getPlayer().getClientAbilityInitFinishHandler().addEntry(entry.getForwardType(), entry); + } + + if (notif.getInvokesList().size() > 0) { + session.getPlayer().getClientAbilityInitFinishHandler().update(session.getPlayer()); + } + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerNpcTalkReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerNpcTalkReq.java new file mode 100644 index 000000000..588e1c4e1 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerNpcTalkReq.java @@ -0,0 +1,21 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.game.inventory.GenshinItem; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.NpcTalkReqOuterClass.NpcTalkReq; +import emu.grasscutter.net.packet.PacketHandler; +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); + + session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId())); + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEntityClientDataNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEntityClientDataNotify.java index accbd253d..1a60f677b 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEntityClientDataNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEntityClientDataNotify.java @@ -1,5 +1,6 @@ package emu.grasscutter.server.packet.recv; +import emu.grasscutter.net.packet.GenshinPacket; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketHandler; @@ -10,7 +11,15 @@ public class HandlerSetEntityClientDataNotify extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - // Auto template + // Skip if there is no one to broadcast it too + if (session.getPlayer().getScene().getPlayerCount() <= 1) { + return; + } + + GenshinPacket packet = new GenshinPacket(PacketOpcodes.SetEntityClientDataNotify, true); + packet.setData(payload); + + session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), packet); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketClientAbilityInitFinishNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketClientAbilityInitFinishNotify.java new file mode 100644 index 000000000..dc676c4d1 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketClientAbilityInitFinishNotify.java @@ -0,0 +1,29 @@ +package emu.grasscutter.server.packet.send; + +import java.util.List; + +import emu.grasscutter.net.packet.GenshinPacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; +import emu.grasscutter.net.proto.ClientAbilityInitFinishNotifyOuterClass.ClientAbilityInitFinishNotify; + +public class PacketClientAbilityInitFinishNotify extends GenshinPacket { + + public PacketClientAbilityInitFinishNotify(List entries) { + super(PacketOpcodes.ClientAbilityInitFinishNotify, true); + + int entityId = 0; + + if (entries.size() > 0) { + AbilityInvokeEntry entry = entries.get(0); + entityId = entry.getEntityId(); + } + + ClientAbilityInitFinishNotify proto = ClientAbilityInitFinishNotify.newBuilder() + .setEntityId(entityId) + .addAllInvokes(entries) + .build(); + + this.setData(proto); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketNpcTalkRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketNpcTalkRsp.java new file mode 100644 index 000000000..b447a19eb --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketNpcTalkRsp.java @@ -0,0 +1,19 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.GenshinPacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.NpcTalkRspOuterClass.NpcTalkRsp; + +public class PacketNpcTalkRsp extends GenshinPacket { + public PacketNpcTalkRsp(int npcEntityId, int curTalkId, int entityId) { + super(PacketOpcodes.NpcTalkRsp); + + NpcTalkRsp p = NpcTalkRsp.newBuilder() + .setNpcEntityId(npcEntityId) + .setCurTalkId(curTalkId) + .setEntityId(entityId) + .build(); + + this.setData(p); + } +}