content: package emu.grasscutter.game.systems;
  
  import emu.grasscutter.game.CoopRequest;
  import emu.grasscutter.game.props.EnterReason;
  import emu.grasscutter.game.world.World;
  import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
  import emu.grasscutter.game.player.Player;
  import emu.grasscutter.game.player.Player.SceneLoadState;
  import emu.grasscutter.net.proto.PlayerApplyEnterMpResultNotifyOuterClass;
  import emu.grasscutter.server.game.BaseGameSystem;
  import emu.grasscutter.server.game.GameServer;
  import emu.grasscutter.server.packet.send.PacketPlayerApplyEnterMpNotify;
  import emu.grasscutter.server.packet.send.PacketPlayerApplyEnterMpResultNotify;
  import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
  
  public class MultiplayerSystem extends BaseGameSystem {
  
      public MultiplayerSystem(GameServer server) {
          super(server);
      }
  
      public void applyEnterMp(Player player, int targetUid) {
          Player target = getServer().getPlayerByUid(targetUid);
          if (target == null) {
              player.sendPacket(new PacketPlayerApplyEnterMpResultNotify(targetUid, "", false, PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_PLAYER_CANNOT_ENTER_MP));
              return;
          }
  
          // Sanity checks - Dont let player join if already in multiplayer
          if (player.getWorld().isMultiplayer()) {
              return;
          }
  
          /*
          if (target.getWorld().isDungeon()) {
              player.sendPacket(new PacketPlayerApplyEnterMpResultNotify(targetUid, "", false, PlayerApplyEnterMpReason.SceneCannotEnter));
              return;
          }
          */
  
          // Get request
          CoopRequest request = target.getCoopRequests().get(player.getUid());
  
          if (request != null && !request.isExpired()) {
              // Join request already exists
              return;
          }
  
          // Put request in
          request = new CoopRequest(player);
          target.getCoopRequests().put(player.getUid(), request);
  
          // Packet
          target.sendPacket(new PacketPlayerApplyEnterMpNotify(player));
      }
  
      public void applyEnterMpReply(Player hostPlayer, int applyUid, boolean isAgreed) {
          // Checks
          CoopRequest request = hostPlayer.getCoopRequests().get(applyUid);
          if (request == null || request.isExpired()) {
              return;
          }
  
          // Remove now that we are handling it
          Player requester = request.getRequester();
          hostPlayer.getCoopRequests().remove(applyUid);
  
          // Sanity checks - Dont let the requesting player join if they are already in multiplayer
          if (requester.getWorld().isMultiplayer()) {
              request.getRequester().sendPacket(new PacketPlayerApplyEnterMpResultNotify(hostPlayer, false, PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_PLAYER_CANNOT_ENTER_MP));
              return;
          }
  
          // Response packet
          request.getRequester().sendPacket(new PacketPlayerApplyEnterMpResultNotify(hostPlayer, isAgreed, PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_PLAYER_JUDGE));
  
          // Declined
          if (!isAgreed) {
              return;
          }
  
          // Success
          if (!hostPlayer.getWorld().isMultiplayer()) {
              // Player not in multiplayer, create multiplayer world
              World world = new World(hostPlayer, true);
  
              // Add
              world.addPlayer(hostPlayer);
  
              // Rejoin packet
              hostPlayer.sendPacket(new PacketPlayerEnterSceneNotify(hostPlayer, hostPlayer, EnterType.ENTER_TYPE_SELF, EnterReason.HostFromSingleToMp, hostPlayer.getScene().getId(), hostPlayer.getPosition()));
          }
  
          // Set scene pos and id of requester to the host player's
          requester.getPosition().set(hostPlayer.getPosition());
          requester.getRotation().set(hostPlayer.getRotation());
          requester.setSceneId(hostPlayer.getSceneId());
  
          // Make requester join
          hostPlayer.getWorld().addPlayer(requester);
  
          // Packet
          requester.sendPacket(new PacketPlayerEnterSceneNotify(requester, hostPlayer, EnterType.ENTER_TYPE_OTHER, EnterReason.TeamJoin, hostPlayer.getScene().getId(), hostPlayer.getPosition()));
      }
  
      public boolean leaveCoop(Player player) {
          // Make sure player's world is multiplayer
          if (!player.getWorld().isMultiplayer()) {
              return false;
          }
  
          // Make sure everyone's scene is loaded
          for (Player p : player.getWorld().getPlayers()) {
              if (p.getSceneLoadState() != SceneLoadState.LOADED) {
                  return false;
              }
          }
  
          // Create new world for player
          World world = new World(player);
          world.addPlayer(player);
  
          // Packet
          player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_TYPE_SELF, EnterReason.TeamBack, player.getScene().getId(), player.getPosition()));
  
          return true;
      }
  
      public boolean kickPlayer(Player player, int targetUid) {
          // Make sure player's world is multiplayer and that player is owner
          if (!player.getWorld().isMultiplayer() || player.getWorld().getHost() != player) {
              return false;
          }
  
          // Get victim and sanity checks
          Player victim = player.getServer().getPlayerByUid(targetUid);
  
          if (victim == null || victim == player) {
              return false;
          }
  
          // Make sure victim's scene has loaded
          if (victim.getSceneLoadState() != SceneLoadState.LOADED) {
              return false;
          }
  
          // Kick
          World world = new World(victim);
          world.addPlayer(victim);
  
          victim.sendPacket(new PacketPlayerEnterSceneNotify(victim, EnterType.ENTER_TYPE_SELF, EnterReason.TeamKick, victim.getScene().getId(), victim.getPosition()));
          return true;
      }
  }
  