use of org.spongepowered.api.world.Location in project SpongeCommon by SpongePowered.
the class MixinNetHandlerPlayServer method throwMoveEvent.
/**
* @author gabizou - June 22nd, 2016
* @reason Sponge has to throw the movement events before we consider moving the player and there's
* no clear way to go about it with the target position being null and the last position update checks.
* @param packetIn
*/
@Redirect(method = "processPlayer", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/player/EntityPlayerMP;queuedEndExit:Z"))
private boolean throwMoveEvent(EntityPlayerMP playerMP, CPacketPlayer packetIn) {
if (!playerMP.queuedEndExit) {
// We don't fire an event to avoid confusing plugins.
if (!packetIn.moving && !packetIn.rotating) {
return playerMP.queuedEndExit;
}
// Sponge Start - Movement event
Player player = (Player) this.player;
IMixinEntityPlayerMP mixinPlayer = (IMixinEntityPlayerMP) this.player;
Vector3d fromrot = player.getRotation();
// If Sponge used the player's current location, the delta might never be triggered which could be exploited
Location<World> from = player.getLocation();
if (this.lastMoveLocation != null) {
from = this.lastMoveLocation;
}
Vector3d torot = new Vector3d(packetIn.pitch, packetIn.yaw, 0);
Location<World> to = new Location<>(player.getWorld(), packetIn.x, packetIn.y, packetIn.z);
// Minecraft sends a 0, 0, 0 position when rotation only update occurs, this needs to be recognized and corrected
boolean rotationOnly = !packetIn.moving && packetIn.rotating;
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.moving && !packetIn.rotating;
if (positionOnly) {
// Correct the new rotation to match the old rotation
torot = fromrot;
}
((IMixinEntityPlayerMP) this.player).setVelocityOverride(to.getPosition().sub(from.getPosition()));
double deltaSquared = to.getPosition().distanceSquared(from.getPosition());
double deltaAngleSquared = fromrot.distanceSquared(torot);
// eventually it would be nice to not have them
if (deltaSquared > ((1f / 16) * (1f / 16)) || deltaAngleSquared > (.15f * .15f)) {
Transform<World> fromTransform = player.getTransform().setLocation(from).setRotation(fromrot);
Transform<World> toTransform = player.getTransform().setLocation(to).setRotation(torot);
Sponge.getCauseStackManager().pushCause(player);
MoveEntityEvent event = SpongeEventFactory.createMoveEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), fromTransform, toTransform, player);
SpongeImpl.postEvent(event);
Sponge.getCauseStackManager().popCause();
if (event.isCancelled()) {
mixinPlayer.setLocationAndAngles(fromTransform);
this.lastMoveLocation = from;
((IMixinEntityPlayerMP) this.player).setVelocityOverride(null);
return true;
} else if (!event.getToTransform().equals(toTransform)) {
mixinPlayer.setLocationAndAngles(event.getToTransform());
this.lastMoveLocation = event.getToTransform().getLocation();
((IMixinEntityPlayerMP) this.player).setVelocityOverride(null);
return true;
} 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;
((IMixinEntityPlayerMP) this.player).setVelocityOverride(null);
return true;
} else {
this.lastMoveLocation = event.getToTransform().getLocation();
}
this.resendLatestResourcePackRequest();
}
}
return playerMP.queuedEndExit;
}
use of org.spongepowered.api.world.Location in project SpongeCommon by SpongePowered.
the class SpongeCommonEventFactory method callNotifyNeighborEvent.
@SuppressWarnings("rawtypes")
public static NotifyNeighborBlockEvent callNotifyNeighborEvent(World world, BlockPos sourcePos, EnumSet notifiedSides) {
final PhaseTracker phaseTracker = PhaseTracker.getInstance();
final PhaseData peek = phaseTracker.getCurrentPhaseData();
final PhaseContext<?> context = peek.context;
// Don't fire notify events during world gen or while restoring
if (peek.state.isWorldGeneration() || peek.state == State.RESTORING_BLOCKS) {
return null;
}
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
final BlockState blockstate = (BlockState) ((net.minecraft.world.World) world).getBlockState(sourcePos);
final LocatableBlock locatable = LocatableBlock.builder().location(new Location<World>(world, sourcePos.getX(), sourcePos.getY(), sourcePos.getZ())).state(blockstate).build();
if (context.getNotifier().isPresent()) {
context.addNotifierAndOwnerToCauseStack();
} else {
final IMixinChunk mixinChunk = (IMixinChunk) ((WorldServer) world).getChunkFromBlockCoords(sourcePos);
mixinChunk.getBlockNotifier(sourcePos).ifPresent(user -> Sponge.getCauseStackManager().addContext(EventContextKeys.NOTIFIER, user));
mixinChunk.getBlockOwner(sourcePos).ifPresent(owner -> Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, owner));
}
Sponge.getCauseStackManager().pushCause(locatable);
final Map<Direction, BlockState> neighbors = new HashMap<>();
for (Object obj : notifiedSides) {
EnumFacing notifiedSide = (EnumFacing) obj;
BlockPos offset = sourcePos.offset(notifiedSide);
Direction direction = DirectionFacingProvider.getInstance().getKey(notifiedSide).get();
Location<World> location = new Location<>(world, VecHelper.toVector3i(offset));
if (location.getBlockY() >= 0 && location.getBlockY() <= 255) {
neighbors.put(direction, location.getBlock());
}
}
// ImmutableMap<Direction, BlockState> originalNeighbors =
// ImmutableMap.copyOf(neighbors);
NotifyNeighborBlockEvent event = SpongeEventFactory.createNotifyNeighborBlockEvent(Sponge.getCauseStackManager().getCurrentCause(), neighbors, neighbors);
SpongeImpl.postEvent(event);
return event;
}
}
use of org.spongepowered.api.world.Location in project SpongeCommon by SpongePowered.
the class SpongeCommonEventFactory method handleCollideImpactEvent.
public static boolean handleCollideImpactEvent(net.minecraft.entity.Entity projectile, @Nullable ProjectileSource projectileSource, RayTraceResult movingObjectPosition) {
final PhaseTracker phaseTracker = PhaseTracker.getInstance();
RayTraceResult.Type movingObjectType = movingObjectPosition.typeOfHit;
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(projectile);
Sponge.getCauseStackManager().addContext(EventContextKeys.PROJECTILE_SOURCE, projectileSource == null ? ProjectileSource.UNKNOWN : projectileSource);
final Optional<User> owner = phaseTracker.getCurrentPhaseData().context.getOwner();
owner.ifPresent(user -> Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, user));
Location<World> impactPoint = new Location<>((World) projectile.world, VecHelper.toVector3d(movingObjectPosition.hitVec));
boolean cancelled = false;
if (movingObjectType == RayTraceResult.Type.BLOCK) {
final BlockPos blockPos = movingObjectPosition.getBlockPos();
if (blockPos.getY() <= 0) {
return false;
}
BlockSnapshot targetBlock = ((World) projectile.world).createSnapshot(VecHelper.toVector3i(movingObjectPosition.getBlockPos()));
Direction side = Direction.NONE;
if (movingObjectPosition.sideHit != null) {
side = DirectionFacingProvider.getInstance().getKey(movingObjectPosition.sideHit).get();
}
CollideBlockEvent.Impact event = SpongeEventFactory.createCollideBlockEventImpact(Sponge.getCauseStackManager().getCurrentCause(), impactPoint, targetBlock.getState(), targetBlock.getLocation().get(), side);
cancelled = SpongeImpl.postEvent(event);
// Track impact block if event is not cancelled
if (!cancelled && owner.isPresent()) {
BlockPos targetPos = VecHelper.toBlockPos(impactPoint.getBlockPosition());
IMixinChunk spongeChunk = (IMixinChunk) projectile.world.getChunkFromBlockCoords(targetPos);
spongeChunk.addTrackedBlockPosition((Block) targetBlock.getState().getType(), targetPos, owner.get(), PlayerTracker.Type.NOTIFIER);
}
} else if (movingObjectPosition.entityHit != null) {
// entity
ArrayList<Entity> entityList = new ArrayList<>();
entityList.add((Entity) movingObjectPosition.entityHit);
CollideEntityEvent.Impact event = SpongeEventFactory.createCollideEntityEventImpact(Sponge.getCauseStackManager().getCurrentCause(), entityList, impactPoint);
cancelled = SpongeImpl.postEvent(event);
}
if (cancelled) {
// Entities such as EnderPearls call setDead during onImpact. However, if the event is cancelled
// setDead will never be called resulting in a bad state such as falling through world.
projectile.setDead();
}
return cancelled;
}
}
use of org.spongepowered.api.world.Location in project SpongeCommon by SpongePowered.
the class SpongeCommonEventFactory method handlePistonEvent.
/**
* This simulates the blocks a piston moves and calls the event for saner
* debugging.
*
* @return if the event was cancelled
*/
public static boolean handlePistonEvent(IMixinWorldServer world, WorldServer.ServerBlockEventList list, Object obj, BlockPos pos, Block blockIn, int eventId, int eventParam) {
boolean extending = (eventId == 0);
final IBlockState blockstate = ((net.minecraft.world.World) world).getBlockState(pos);
EnumFacing direction = blockstate.getValue(BlockDirectional.FACING);
final LocatableBlock locatable = LocatableBlock.builder().location(new Location<>((World) world, pos.getX(), pos.getY(), pos.getZ())).state((BlockState) blockstate).build();
// Sets toss out duplicate values (even though there shouldn't be any)
HashSet<Location<org.spongepowered.api.world.World>> locations = new HashSet<>();
locations.add(new Location<>((World) world, pos.getX(), pos.getY(), pos.getZ()));
BlockPistonStructureHelper movedBlocks = new BlockPistonStructureHelper((WorldServer) world, pos, direction, extending);
// calculates blocks to be moved
movedBlocks.canMove();
Stream.concat(movedBlocks.getBlocksToMove().stream(), movedBlocks.getBlocksToDestroy().stream()).map(block -> new Location<>((World) world, block.getX(), block.getY(), block.getZ())).collect(// SUPER
Collectors.toCollection(() -> locations));
// If the piston is extending and there are no blocks to destroy, add the offset location for protection purposes
if (extending && movedBlocks.getBlocksToDestroy().isEmpty()) {
final List<BlockPos> movedPositions = movedBlocks.getBlocksToMove();
BlockPos offsetPos;
// If there are no blocks to move, add the offset of piston
if (movedPositions.isEmpty()) {
offsetPos = pos.offset(direction);
} else {
// Add the offset of last block set to move
offsetPos = movedPositions.get(movedPositions.size() - 1).offset(direction);
}
locations.add(new Location<>((World) world, offsetPos.getX(), offsetPos.getY(), offsetPos.getZ()));
}
try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
if (extending) {
Sponge.getCauseStackManager().addContext(EventContextKeys.PISTON_EXTEND, world.asSpongeWorld());
} else {
Sponge.getCauseStackManager().addContext(EventContextKeys.PISTON_RETRACT, world.asSpongeWorld());
}
return SpongeCommonEventFactory.callChangeBlockEventPre(world, ImmutableList.copyOf(locations), locatable).isCancelled();
}
}
use of org.spongepowered.api.world.Location in project SpongeCommon by SpongePowered.
the class MixinBlockCactus method preSetOnFire.
@Inject(method = "onEntityCollidedWithBlock", at = @At(value = "FIELD", target = CACTUS_DAMAGE_FIELD, opcode = Opcodes.GETSTATIC))
public void preSetOnFire(net.minecraft.world.World worldIn, BlockPos pos, IBlockState state, Entity entityIn, CallbackInfo callbackInfo) {
if (!worldIn.isRemote) {
this.originalCactus = DamageSource.CACTUS;
Location<World> location = new Location<>((World) worldIn, pos.getX(), pos.getY(), pos.getZ());
DamageSource.CACTUS = new MinecraftBlockDamageSource("cactus", location);
}
}
Aggregations