Exemple #1
0
 /**
  * @author gabizou - February 7th, 2016
  *     <p>This will short circuit all other patches such that we control the entities being loaded
  *     by chunkloading and can throw our bulk entity event. This will bypass Forge's hook for
  *     individual entity events, but the SpongeModEventManager will still successfully throw the
  *     appropriate event and cancel the entities otherwise contained.
  * @param entities The entities being loaded
  * @param callbackInfo The callback info
  */
 @Final
 @Inject(method = "loadEntities", at = @At("HEAD"), cancellable = true)
 private void spongeLoadEntities(
     Collection<net.minecraft.entity.Entity> entities, CallbackInfo callbackInfo) {
   if (entities.isEmpty()) {
     // just return, no entities to load!
     callbackInfo.cancel();
     return;
   }
   List<Entity> entityList = new ArrayList<>();
   ImmutableList.Builder<EntitySnapshot> snapshotBuilder = ImmutableList.builder();
   for (net.minecraft.entity.Entity entity : entities) {
     entityList.add((Entity) entity);
     snapshotBuilder.add(((Entity) entity).createSnapshot());
   }
   SpawnCause cause = SpawnCause.builder().type(InternalSpawnTypes.CHUNK_LOAD).build();
   List<NamedCause> causes = new ArrayList<>();
   causes.add(NamedCause.source(cause));
   causes.add(NamedCause.of("World", this));
   SpawnEntityEvent.ChunkLoad chunkLoad =
       SpongeEventFactory.createSpawnEntityEventChunkLoad(
           Cause.of(causes), entityList, snapshotBuilder.build(), this);
   SpongeImpl.postEvent(chunkLoad);
   if (!chunkLoad.isCancelled()) {
     for (Entity successful : chunkLoad.getEntities()) {
       this.loadedEntityList.add((net.minecraft.entity.Entity) successful);
       this.onEntityAdded((net.minecraft.entity.Entity) successful);
     }
   }
   callbackInfo.cancel();
 }
 @Inject(method = "trySpawnGolem", at = @At("HEAD"), cancellable = true)
 private void checkChunkBeforeTrySpawnGolem(World world, BlockPos pos, CallbackInfo callbackInfo) {
   final Chunk chunk = world.getChunkFromBlockCoords(pos);
   if (chunk == null || chunk.isEmpty() || !chunk.isTerrainPopulated()) {
     callbackInfo.cancel();
   }
 }
Exemple #3
0
 @Inject(method = "playSoundAtEntity", at = @At("HEAD"), cancellable = true)
 private void spongePlaySoundAtEntity(
     net.minecraft.entity.Entity entity,
     String name,
     float volume,
     float pitch,
     CallbackInfo callbackInfo) {
   if (((IMixinEntity) entity).isVanished()) {
     callbackInfo.cancel();
   }
 }
 @Inject(
     method = "onCollideWithPlayer",
     at =
         @At(
             value = "INVOKE",
             target =
                 "Lnet/minecraft/entity/item/EntityItem;getEntityItem()Lnet/minecraft/item/ItemStack;"),
     cancellable = true)
 public void onPlayerItemPickup(EntityPlayer entityIn, CallbackInfo ci) {
   if (!SpongeCommonEventFactory.callPlayerChangeInventoryPickupEvent(
       entityIn, this.getEntityItem(), this.delayBeforeCanPickup)) {
     ci.cancel();
   }
 }
  /**
   * @Author Zidane
   *
   * <p>Invoke before {@code System.arraycopy(packetIn.getLines(), 0, tileentitysign.signText, 0,
   * 4);} (line 1156 in source) to call SignChangeEvent.
   *
   * @param packetIn Injected packet param
   * @param ci Info to provide mixin on how to handle the callback
   * @param worldserver Injected world param
   * @param blockpos Injected blockpos param
   * @param tileentity Injected tilentity param
   * @param tileentitysign Injected tileentitysign param
   */
  @Inject(
      method = "processUpdateSign",
      at =
          @At(
              value = "INVOKE",
              target =
                  "Lnet/minecraft/network/play/client/C12PacketUpdateSign;getLines()[Lnet/minecraft/util/IChatComponent;"),
      cancellable = true,
      locals = LocalCapture.CAPTURE_FAILSOFT)
  public void callSignChangeEvent(
      C12PacketUpdateSign packetIn,
      CallbackInfo ci,
      WorldServer worldserver,
      BlockPos blockpos,
      TileEntity tileentity,
      TileEntitySign tileentitysign) {
    ci.cancel();
    final Optional<SignData> existingSignData = ((Sign) tileentitysign).getData();
    if (!existingSignData.isPresent()) {
      // TODO Unsure if this is the best to do here...
      throw new RuntimeException("Critical error! Sign data not present on sign!");
    }
    final SignData changedSignData = existingSignData.get().copy();

    for (int i = 0; i < packetIn.getLines().length; i++) {
      changedSignData.setLine(i, SpongeTexts.toText(packetIn.getLines()[i]));
    }
    // I pass changedSignData in here twice to emulate the fact that even-though the current sign
    // data doesn't have the lines from the packet
    // applied, this is what it "is" right now. If the data shown in the world is desired, it can be
    // fetched from Sign.getData
    final SignChangeEvent event =
        SpongeEventFactory.createSignChange(
            Sponge.getGame(),
            new Cause(null, this.playerEntity, null),
            (Sign) tileentitysign,
            changedSignData,
            changedSignData);
    if (!Sponge.getGame().getEventManager().post(event)) {
      ((Sign) tileentitysign).offer(event.getNewData());
    } else {
      // If cancelled, I set the data back that was fetched from the sign. This means that if its a
      // new sign, the sign will be empty else
      // it will be the text of the sign that was showing in the world
      ((Sign) tileentitysign).offer(existingSignData.get());
    }
    tileentitysign.markDirty();
    worldserver.markBlockForUpdate(blockpos);
  }
 @Inject(
     method = "randomTick",
     at = @At(value = "HEAD"),
     locals = LocalCapture.CAPTURE_FAILEXCEPTION,
     cancellable = true)
 public void callRandomTickEvent(
     World world, BlockPos pos, IBlockState state, Random rand, CallbackInfo ci) {
   final BlockRandomTickEvent event =
       SpongeEventFactory.createBlockRandomTick(
           Sponge.getGame(),
           null,
           new Location<org.spongepowered.api.world.World>(
               (org.spongepowered.api.world.World) world,
               VecHelper.toVector(pos))); // TODO Fix null Cause
   Sponge.getGame().getEventManager().post(event);
   if (event.isCancelled()) {
     ci.cancel();
   }
 }
 @Inject(
     method = "randomTick",
     at = @At(value = "HEAD"),
     locals = LocalCapture.CAPTURE_FAILEXCEPTION,
     cancellable = true)
 public void callRandomTickEvent(
     net.minecraft.world.World world,
     BlockPos pos,
     IBlockState state,
     Random rand,
     CallbackInfo ci) {
   BlockSnapshot blockSnapshot = ((World) world).createSnapshot(VecHelper.toVector(pos));
   final TickBlockEvent event =
       SpongeEventFactory.createTickBlockEvent(Cause.of(NamedCause.source(world)), blockSnapshot);
   SpongeImpl.postEvent(event);
   if (event.isCancelled()) {
     ci.cancel();
   }
 }
  @Inject(
      method = "processPlayer",
      at =
          @At(
              value = "FIELD",
              target = "net.minecraft.network.NetHandlerPlayServer.hasMoved:Z",
              ordinal = 2),
      cancellable = true)
  public void proccesPlayerMoved(C03PacketPlayer packetIn, CallbackInfo ci) {
    if (packetIn.isMoving() || packetIn.getRotating() && !this.playerEntity.isDead) {
      Player player = (Player) this.playerEntity;
      Vector3d fromrot = player.getRotation();

      // If Sponge used the player's current location, the delta might never be triggered which
      // could be exploited
      Location from = player.getLocation();
      if (this.lastMoveLocation != null) {
        from = this.lastMoveLocation;
      }

      Vector3d torot = new Vector3d(packetIn.getPitch(), packetIn.getYaw(), 0);
      Location to =
          new Location(
              player.getWorld(),
              packetIn.getPositionX(),
              packetIn.getPositionY(),
              packetIn.getPositionZ());

      // Minecraft sends a 0, 0, 0 position when rotation only update occurs, this needs to be
      // recognized and corrected
      boolean rotationOnly = !packetIn.isMoving() && packetIn.getRotating();
      if (rotationOnly) {
        // Correct the to location so it's not misrepresented to plugins, only when player rotates
        // without moving
        // In this case it's only a rotation update, which isn't related to the to location
        from = player.getLocation();
        to = from;
      }

      // Minecraft does the same with rotation when it's only a positional update
      boolean positionOnly = packetIn.isMoving() && !packetIn.getRotating();
      if (positionOnly) {
        // Correct the new rotation to match the old rotation
        torot = fromrot;
      }

      double deltaSquared = to.getPosition().distanceSquared(from.getPosition());
      double deltaAngleSquared = fromrot.distanceSquared(torot);

      // These magic numbers are sad but help prevent excessive lag from this event.
      // eventually it would be nice to not have them
      if (deltaSquared > ((1f / 16) * (1f / 16)) || deltaAngleSquared > (.15f * .15f)) {
        PlayerMoveEvent event =
            SpongeEventFactory.createPlayerMove(Sponge.getGame(), player, from, to, torot);
        Sponge.getGame().getEventManager().post(event);
        if (event.isCancelled()) {
          player.setLocationAndRotation(from, fromrot);
          this.lastMoveLocation = from;
          ci.cancel();
        } else if (!event.getNewLocation().equals(to)) {
          player.setLocationAndRotation(event.getNewLocation(), event.getRotation());
          this.lastMoveLocation = event.getNewLocation();
          ci.cancel();
        } else if (!from.equals(player.getLocation()) && this.justTeleported) {
          this.lastMoveLocation = player.getLocation();
          // Prevent teleports during the move event from causing odd behaviors
          this.justTeleported = false;
          ci.cancel();
        } else {
          this.lastMoveLocation = event.getNewLocation();
        }
      }
    }
  }
  /**
   * @author zml
   *     <p>Purpose: replace the logic used for command blocks to make functional
   * @param ci callback
   * @param packetIn method param
   */
  @Inject(
      method = "processVanilla250Packet",
      at =
          @At(
              value = "INVOKE",
              shift = At.Shift.AFTER,
              target =
                  "net/minecraft/network/PacketThreadUtil.checkThreadAndEnqueue(Lnet/minecraft/network/Packet;"
                      + "Lnet/minecraft/network/INetHandler;Lnet/minecraft/util/IThreadListener;)V"),
      cancellable = true)
  public void processCommandBlock(C17PacketCustomPayload packetIn, CallbackInfo ci) {
    if ("MC|AdvCdm".equals(packetIn.getChannelName())) {
      PacketBuffer packetbuffer;
      try {
        if (!this.serverController.isCommandBlockEnabled()) {
          this.playerEntity.addChatMessage(
              new ChatComponentTranslation("advMode.notEnabled", new Object[0]));
          // Sponge: Check permissions for command block usage TODO: Maybe throw an event instead?
          // } else if (this.playerEntity.canCommandSenderUseCommand(2, "") &&
          // this.playerEntity.capabilities.isCreativeMode) {
        } else {
          packetbuffer = packetIn.getBufferData();

          try {
            byte b0 = packetbuffer.readByte();
            CommandBlockLogic commandblocklogic = null;

            String permissionCheck = null; // Sponge
            if (b0 == 0) {
              TileEntity tileentity =
                  this.playerEntity.worldObj.getTileEntity(
                      new BlockPos(
                          packetbuffer.readInt(), packetbuffer.readInt(), packetbuffer.readInt()));

              if (tileentity instanceof TileEntityCommandBlock) {
                commandblocklogic = ((TileEntityCommandBlock) tileentity).getCommandBlockLogic();
                permissionCheck =
                    "minecraft.commandblock.edit.block."
                        + commandblocklogic.getCommandSenderName(); // Sponge
              }
            } else if (b0 == 1) {
              Entity entity = this.playerEntity.worldObj.getEntityByID(packetbuffer.readInt());

              if (entity instanceof EntityMinecartCommandBlock) {
                commandblocklogic = ((EntityMinecartCommandBlock) entity).getCommandBlockLogic();
                permissionCheck =
                    "minecraft.commandblock.edit.minecart."
                        + commandblocklogic.getCommandSenderName(); // Sponge
              }
              // Sponge begin
            } else {
              throw new IllegalArgumentException("Unknown command block type!");
            }
            Player spongePlayer = ((Player) this.playerEntity);
            if (permissionCheck == null || !spongePlayer.hasPermission(permissionCheck)) {
              spongePlayer.sendMessage(
                  t("You do not have permission to edit this command block!")
                      .builder()
                      .color(TextColors.RED)
                      .build());
              return;
              // Sponge end
            }

            String s1 = packetbuffer.readStringFromBuffer(packetbuffer.readableBytes());
            boolean flag = packetbuffer.readBoolean();

            if (commandblocklogic != null) {
              commandblocklogic.setCommand(s1);
              commandblocklogic.setTrackOutput(flag);

              if (!flag) {
                commandblocklogic.setLastOutput((IChatComponent) null);
              }

              commandblocklogic.func_145756_e();
              this.playerEntity.addChatMessage(
                  new ChatComponentTranslation("advMode.setCommand.success", new Object[] {s1}));
            }
          } catch (Exception exception1) {
            logger.error("Couldn\'t set command block", exception1);
          } finally {
            packetbuffer.release();
          }
          /*} else { // Sponge: Give more accurate no permission message
          this.playerEntity.addChatMessage(new ChatComponentTranslation("advMode.notAllowed", new Object[0]));*/
        }
      } finally {
        ci.cancel();
      }
    }
  }