use of org.spongepowered.common.interfaces.world.IMixinWorldServer in project SpongeCommon by SpongePowered.
the class IPhaseState method spawnEntityOrCapture.
/**
* This is Step 3 of entity spawning. It is used for the sole purpose of capturing an entity spawn
* and doesn't actually spawn an entity into the world until the current phase is unwound.
* The method itself should technically capture entity spawns, however, in the event it
* is required that the entity cannot be captured, returning {@code false} will mark it
* to spawn into the world, bypassing any of the bulk spawn events or capturing.
*
* <p>NOTE: This method should only be called and handled if and only if {@link IPhaseState#allowEntitySpawns()}
* returns {@code true}. Violation of this will have unforseen consequences.</p>
*
* @param context The current context
* @param entity The entity being captured
* @param chunkX The chunk x position
* @param chunkZ The chunk z position
* @return True if the entity was successfully captured
*/
default boolean spawnEntityOrCapture(C context, org.spongepowered.api.entity.Entity entity, int chunkX, int chunkZ) {
final User user = context.getNotifier().orElseGet(() -> context.getOwner().orElse(null));
if (user != null) {
entity.setCreator(user.getUniqueId());
}
final ArrayList<org.spongepowered.api.entity.Entity> entities = new ArrayList<>(1);
entities.add(entity);
final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), entities);
SpongeImpl.postEvent(event);
if (!event.isCancelled() && event.getEntities().size() > 0) {
for (org.spongepowered.api.entity.Entity item : event.getEntities()) {
((IMixinWorldServer) item.getWorld()).forceSpawnEntity(item);
}
return true;
}
return false;
}
use of org.spongepowered.common.interfaces.world.IMixinWorldServer in project SpongeCommon by SpongePowered.
the class PhaseTracker method notifyBlockOfStateChange.
// --------------------- DELEGATED WORLD METHODS -------------------------
/**
* Replacement of {@link net.minecraft.world.World#neighborChanged(BlockPos, Block, BlockPos)}
* that adds tracking into play.
*
* @param mixinWorld THe world
* @param notifyPos The original notification position
* @param sourceBlock The source block type
* @param sourcePos The source block position
*/
public void notifyBlockOfStateChange(final IMixinWorldServer mixinWorld, final BlockPos notifyPos, final Block sourceBlock, @Nullable final BlockPos sourcePos) {
final IBlockState iblockstate = ((WorldServer) mixinWorld).getBlockState(notifyPos);
try {
// Sponge start - prepare notification
final PhaseData peek = this.stack.peek();
final IPhaseState<?> state = peek.state;
((IPhaseState) state).associateNeighborStateNotifier(peek.context, sourcePos, iblockstate.getBlock(), notifyPos, ((WorldServer) mixinWorld), PlayerTracker.Type.NOTIFIER);
// Sponge End
iblockstate.neighborChanged(((WorldServer) mixinWorld), notifyPos, sourceBlock, sourcePos);
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Exception while updating neighbours");
CrashReportCategory crashreportcategory = crashreport.makeCategory("Block being updated");
crashreportcategory.addDetail("Source block type", () -> {
try {
return String.format("ID #%d (%s // %s)", Block.getIdFromBlock(sourceBlock), sourceBlock.getUnlocalizedName(), sourceBlock.getClass().getCanonicalName());
} catch (Throwable var2) {
return "ID #" + Block.getIdFromBlock(sourceBlock);
}
});
CrashReportCategory.addBlockInfo(crashreportcategory, notifyPos, iblockstate);
throw new ReportedException(crashreport);
}
}
use of org.spongepowered.common.interfaces.world.IMixinWorldServer in project SpongeCommon by SpongePowered.
the class PhaseTracker method spawnEntity.
/**
* This is the replacement of {@link WorldServer#spawnEntity(net.minecraft.entity.Entity)}
* where it captures into phases. The causes and relations are processed by the phases.
*
* The difference between {@link #spawnEntityWithCause(World, Entity)} is that it bypasses
* any phases and directly throws a spawn entity event.
*
* @param world The world
* @param entity The entity
* @return True if the entity spawn was successful
*/
public boolean spawnEntity(World world, Entity entity) {
checkNotNull(entity, "Entity cannot be null!");
// Sponge Start - handle construction phases
if (((IMixinEntity) entity).isInConstructPhase()) {
((IMixinEntity) entity).firePostConstructEvents();
}
final net.minecraft.entity.Entity minecraftEntity = EntityUtil.toNative(entity);
final WorldServer minecraftWorld = (WorldServer) world;
final IMixinWorldServer mixinWorldServer = (IMixinWorldServer) minecraftWorld;
final PhaseData phaseData = this.stack.peek();
final IPhaseState<?> phaseState = phaseData.state;
final PhaseContext<?> context = phaseData.context;
final boolean isForced = minecraftEntity.forceSpawn || minecraftEntity instanceof EntityPlayer;
// Certain phases disallow entity spawns (such as block restoration)
if (!isForced && !phaseState.allowEntitySpawns()) {
return false;
}
// Sponge End - continue with vanilla mechanics
final int chunkX = MathHelper.floor(minecraftEntity.posX / 16.0D);
final int chunkZ = MathHelper.floor(minecraftEntity.posZ / 16.0D);
if (!isForced && !mixinWorldServer.isMinecraftChunkLoaded(chunkX, chunkZ, true)) {
return false;
}
if (minecraftEntity instanceof EntityPlayer) {
EntityPlayer entityplayer = (EntityPlayer) minecraftEntity;
minecraftWorld.playerEntities.add(entityplayer);
minecraftWorld.updateAllPlayersSleepingFlag();
SpongeImplHooks.firePlayerJoinSpawnEvent((EntityPlayerMP) entityplayer);
} else {
// Sponge start - check for vanilla owner
if (minecraftEntity instanceof IEntityOwnable) {
IEntityOwnable ownable = (IEntityOwnable) entity;
net.minecraft.entity.Entity owner = ownable.getOwner();
if (owner != null && owner instanceof EntityPlayer) {
context.owner = (User) owner;
entity.setCreator(ownable.getOwnerId());
}
} else if (minecraftEntity instanceof EntityThrowable) {
EntityThrowable throwable = (EntityThrowable) minecraftEntity;
EntityLivingBase thrower = throwable.getThrower();
if (thrower != null) {
User user = null;
if (!(thrower instanceof EntityPlayer)) {
user = ((IMixinEntity) thrower).getCreatorUser().orElse(null);
} else {
user = (User) thrower;
}
if (user != null) {
context.owner = user;
entity.setCreator(user.getUniqueId());
}
}
}
// Sponge end
}
// capture all entities until the phase is marked for completion.
if (!isForced) {
try {
return ((IPhaseState) phaseState).spawnEntityOrCapture(context, entity, chunkX, chunkZ);
} catch (Exception | NoClassDefFoundError e) {
// Just in case something really happened, we should print a nice exception for people to
// paste us
this.printExceptionSpawningEntity(context, e);
return false;
}
}
// Sponge end - continue on with the checks.
minecraftWorld.getChunkFromChunkCoords(chunkX, chunkZ).addEntity(minecraftEntity);
minecraftWorld.loadedEntityList.add(minecraftEntity);
// Sponge - Cannot add onEntityAdded to the access transformer because forge makes it public
mixinWorldServer.onSpongeEntityAdded(minecraftEntity);
return true;
}
use of org.spongepowered.common.interfaces.world.IMixinWorldServer in project SpongeCommon by SpongePowered.
the class PhaseTracker method spawnEntityWithCause.
/**
* The core implementation of {@link World#spawnEntity(Entity)} that
* bypasses any sort of cause tracking and throws an event directly
*
* @param world The world
* @param entity The entity
* @return True if entity was spawned, false if not
*/
public boolean spawnEntityWithCause(World world, Entity entity) {
checkNotNull(entity, "Entity cannot be null!");
// Sponge Start - handle construction phases
if (((IMixinEntity) entity).isInConstructPhase()) {
((IMixinEntity) entity).firePostConstructEvents();
}
final net.minecraft.entity.Entity minecraftEntity = EntityUtil.toNative(entity);
final WorldServer worldServer = (WorldServer) world;
final IMixinWorldServer mixinWorldServer = (IMixinWorldServer) worldServer;
// Sponge End - continue with vanilla mechanics
final int chunkX = MathHelper.floor(minecraftEntity.posX / 16.0D);
final int chunkZ = MathHelper.floor(minecraftEntity.posZ / 16.0D);
final boolean isForced = minecraftEntity.forceSpawn || minecraftEntity instanceof EntityPlayer;
if (!isForced && !mixinWorldServer.isMinecraftChunkLoaded(chunkX, chunkZ, true)) {
return false;
}
// Sponge Start - throw an event
// We need to use an arraylist so that filtering will work.
final List<Entity> entities = new ArrayList<>(1);
entities.add(entity);
final SpawnEntityEvent.Custom event = SpongeEventFactory.createSpawnEntityEventCustom(Sponge.getCauseStackManager().getCurrentCause(), entities);
SpongeImpl.postEvent(event);
if (entity instanceof EntityPlayer || !event.isCancelled()) {
mixinWorldServer.forceSpawnEntity(entity);
}
return true;
}
use of org.spongepowered.common.interfaces.world.IMixinWorldServer in project SpongeCommon by SpongePowered.
the class TrackingUtil method updateTickBlock.
public static void updateTickBlock(IMixinWorldServer mixinWorld, Block block, BlockPos pos, IBlockState state, Random random) {
final WorldServer minecraftWorld = mixinWorld.asMinecraftWorld();
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(minecraftWorld);
if (ShouldFire.TICK_BLOCK_EVENT) {
BlockSnapshot snapshot = mixinWorld.createSpongeBlockSnapshot(state, state, pos, BlockChangeFlags.NONE);
final TickBlockEvent event = SpongeEventFactory.createTickBlockEventScheduled(Sponge.getCauseStackManager().getCurrentCause(), snapshot);
SpongeImpl.postEvent(event);
if (event.isCancelled()) {
return;
}
}
final LocatableBlock locatable = LocatableBlock.builder().location(new Location<>(mixinWorld.asSpongeWorld(), pos.getX(), pos.getY(), pos.getZ())).state((BlockState) state).build();
Sponge.getCauseStackManager().pushCause(locatable);
IPhaseState<BlockTickContext> phase = ((IMixinBlock) block).requiresBlockCapture() ? TickPhase.Tick.BLOCK : TickPhase.Tick.NO_CAPTURE_BLOCK;
final BlockTickContext phaseContext = phase.createPhaseContext().source(locatable);
checkAndAssignBlockTickConfig(block, minecraftWorld, phaseContext);
final PhaseTracker phaseTracker = PhaseTracker.getInstance();
// We have to associate any notifiers in case of scheduled block updates from other sources
final PhaseData current = phaseTracker.getCurrentPhaseData();
final IPhaseState<?> currentState = current.state;
((IPhaseState) currentState).appendNotifierPreBlockTick(mixinWorld, pos, current.context, phaseContext);
try (PhaseContext<?> context = phaseContext.buildAndSwitch()) {
block.updateTick(minecraftWorld, pos, state, random);
} catch (Exception | NoClassDefFoundError e) {
phaseTracker.printExceptionFromPhase(e, phaseContext);
}
}
}
Aggregations