use of org.spongepowered.common.bridge.world.level.LevelBridge in project SpongeCommon by SpongePowered.
the class ChunkMapMixin_Tracker method tracker$startLoad.
@Redirect(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;runPostLoad()V"), slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;setFullStatus(Ljava/util/function/Supplier;)V"), to = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;addAllPendingBlockEntities(Ljava/util/Collection;)V")))
private void tracker$startLoad(final LevelChunk chunk) {
chunk.runPostLoad();
final boolean isFake = ((LevelBridge) chunk.getLevel()).bridge$isFake();
if (isFake) {
return;
}
if (!PhaseTracker.SERVER.onSidedThread()) {
new PrettyPrinter(60).add("Illegal Async Chunk Load").centre().hr().addWrapped("Sponge relies on knowing when chunks are being loaded as chunks add entities" + " to the parented world for management. These operations are generally not" + " threadsafe and shouldn't be considered a \"Sponge bug \". Adding/removing" + " entities from another thread to the world is never ok.").add().add(" %s : %s", "Chunk Pos", chunk.getPos().toString()).add().add(new Exception("Async Chunk Load Detected")).log(SpongeCommon.logger(), Level.ERROR);
return;
}
if (PhaseTracker.getInstance().getCurrentState() == GenerationPhase.State.CHUNK_REGENERATING_LOAD_EXISTING) {
return;
}
GenerationPhase.State.CHUNK_LOADING.createPhaseContext(PhaseTracker.getInstance()).source(chunk).world((ServerLevel) chunk.getLevel()).chunk(chunk).buildAndSwitch();
}
use of org.spongepowered.common.bridge.world.level.LevelBridge in project SpongeCommon by SpongePowered.
the class ServerPlayerMixin_Tracker method tracker$throwItemDrop.
/**
* @author gabizou - June 4th, 2016
* @author i509VCB - February 17th, 2020 - 1.14.4
* @author gabizou - December 31st, 2021 - 1.16.5
* @reason We inject a construct event for the item drop and conveniently
* can redirect the super call.
*/
@Redirect(method = "drop", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;drop(Lnet/minecraft/world/item/ItemStack;ZZ)Lnet/minecraft/world/entity/item/ItemEntity;"))
@Nullable
private ItemEntity tracker$throwItemDrop(final Player thisPlayer, final ItemStack droppedItem, final boolean dropAround, final boolean traceItem) {
if (droppedItem.isEmpty()) {
return null;
}
if (((PlatformEntityBridge) this).bridge$isFakePlayer()) {
return super.shadow$drop(droppedItem, dropAround, traceItem);
}
if (((LevelBridge) this.level).bridge$isFake()) {
return super.shadow$drop(droppedItem, dropAround, traceItem);
}
final double posX1 = this.shadow$getX();
final double posY1 = this.shadow$getEyeY() - (double) 0.3F;
final double posZ1 = this.shadow$getZ();
// Now the real fun begins.
final ItemStack item;
final ItemStackSnapshot snapshot = ItemStackUtil.snapshotOf(droppedItem);
final List<ItemStackSnapshot> original = new ArrayList<>();
original.add(snapshot);
try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) {
item = SpongeCommonEventFactory.throwDropItemAndConstructEvent((ServerPlayer) (Object) this, posX1, posY1, posZ1, snapshot, original, frame);
if (item == null || item.isEmpty()) {
return null;
}
// Here is where we would potentially perform item pre-merging (merge the item stacks with previously captured item stacks
// and only if those stacks can be stacked (count increased). Otherwise, we'll just continue to throw the entity item.
// For now, due to refactoring a majority of all of this code, pre-merging is disabled entirely.
final ItemEntity itemEntity = new ItemEntity(this.level, posX1, posY1, posZ1, droppedItem);
itemEntity.setPickUpDelay(40);
if (traceItem) {
itemEntity.setThrower(this.shadow$getUUID());
}
final Random random = this.shadow$getRandom();
if (dropAround) {
final float f = random.nextFloat() * 0.5F;
final float f1 = random.nextFloat() * ((float) Math.PI * 2F);
itemEntity.setDeltaMovement(-Mth.sin(f1) * f, 0.2F, Mth.cos(f1) * f);
} else {
final float f8 = Mth.sin(this.xRot * ((float) Math.PI / 180F));
final float f2 = Mth.cos(this.xRot * ((float) Math.PI / 180F));
final float f3 = Mth.sin(this.yRot * ((float) Math.PI / 180F));
final float f4 = Mth.cos(this.yRot * ((float) Math.PI / 180F));
final float f5 = this.random.nextFloat() * ((float) Math.PI * 2F);
final float f6 = 0.02F * this.random.nextFloat();
itemEntity.setDeltaMovement((double) (-f3 * f2 * 0.3F) + Math.cos(f5) * (double) f6, (-f8 * 0.3F + 0.1F + (this.random.nextFloat() - this.random.nextFloat()) * 0.1F), (double) (f4 * f2 * 0.3F) + Math.sin(f5) * (double) f6);
}
return itemEntity;
}
}
use of org.spongepowered.common.bridge.world.level.LevelBridge in project SpongeCommon by SpongePowered.
the class LivingEntityMixin_Tracker method tracker$enterDeathPhase.
/**
* @author i509VCB
* @author gabizou
*
* @reason We can enter in to the entity drops transaction here which will
* successfully batch the side effects (this is effectively a singular side
* effect/transaction instead of a pipeline) to perform some things around
* the entity's death. This successfully records the transactions associated
* with this entity entering into the death state.
*/
@Redirect(method = "baseTick()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;tickDeath()V"))
private void tracker$enterDeathPhase(final LivingEntity livingEntity) {
final PhaseTracker instance = PhaseTracker.SERVER;
if (!instance.onSidedThread()) {
this.shadow$tickDeath();
return;
}
if (((LevelBridge) this.level).bridge$isFake()) {
this.shadow$tickDeath();
return;
}
final PhaseContext<@NonNull ?> context = instance.getPhaseContext();
if (!context.doesBlockEventTracking()) {
this.shadow$tickDeath();
return;
}
try (final EffectTransactor ignored = context.getTransactor().ensureEntityDropTransactionEffect((LivingEntity) (Object) this)) {
this.shadow$tickDeath();
}
}
use of org.spongepowered.common.bridge.world.level.LevelBridge in project SpongeCommon by SpongePowered.
the class EntityActivationRange method activateEntities.
/**
* Find what entities are in range of the players in the world and set
* active if in range.
*
* @param world The world to perform activation checks in
*/
public static void activateEntities(final ServerLevel world) {
if (((LevelBridge) world).bridge$isFake()) {
return;
}
for (final ServerPlayer player : world.players()) {
int maxRange = 0;
for (final Integer range : EntityActivationRange.maxActivationRanges.values()) {
if (range > maxRange) {
maxRange = range;
}
}
maxRange = Math.min((((ServerWorld) world).properties().viewDistance() << 4) - 8, maxRange);
((ActivationCapabilityBridge) player).activation$setActivatedTick(SpongeCommon.server().getTickCount());
final AABB aabb = EntityActivationRange.maxBB;
EntityActivationRange.growBb(aabb, player.getBoundingBox(), maxRange, 256, maxRange);
final int i = Mth.floor(aabb.minX / 16.0D);
final int j = Mth.floor(aabb.maxX / 16.0D);
final int k = Mth.floor(aabb.minZ / 16.0D);
final int l = Mth.floor(aabb.maxZ / 16.0D);
for (int i1 = i; i1 <= j; ++i1) {
for (int j1 = k; j1 <= l; ++j1) {
final LevelChunk chunk = world.getChunkSource().getChunkNow(i1, j1);
if (chunk != null) {
EntityActivationRange.activateChunkEntities(player, chunk);
}
}
}
}
}
use of org.spongepowered.common.bridge.world.level.LevelBridge in project SpongeCommon by SpongePowered.
the class LevelChunkMixin_Tracker method bridge$createChunkPipeline.
/**
* Technically a full overwrite for {@link LevelChunk#setBlockState(BlockPos, BlockState, boolean)}
* and due to Sponge's hijacking of {@link ServerLevel#setBlock(BlockPos, BlockState, int)},
* it needs to be able to record transactions when necessary. This implementation allows for us to
* further specify the types of transactions and what proxies are needing to set up where.
*
* @param pos The position changing
* @param newState The new state
* @param currentState The current state - passed in from either chunk or world
* @param flag The sponge change flag, converted from an int to a proper struct
* @return The changed block state if not null
* @author gabizou - January 13th, 2020 - Minecraft 1.14.3
*/
@Override
@NonNull
public ChunkPipeline bridge$createChunkPipeline(final BlockPos pos, final BlockState newState, final BlockState currentState, final SpongeBlockChangeFlag flag, final int limit) {
final boolean isFake = ((LevelBridge) this.level).bridge$isFake();
if (isFake) {
throw new IllegalStateException("Cannot call ChunkBridge.bridge$buildChunkPipeline in non-Server managed worlds");
}
// int i = pos.getX() & 15;
final int xPos = pos.getX() & 15;
// int j = pos.getY();
final int yPos = pos.getY();
// int k = pos.getZ() & 15;
final int zPos = pos.getZ() & 15;
// Sponge - get the moving flag from our flag construct
LevelChunkSection chunksection = this.sections[yPos >> 4];
if (chunksection == LevelChunkMixin_Tracker.EMPTY_SECTION) {
if (newState.isAir()) {
return ChunkPipeline.nullReturn((LevelChunk) (Object) this, (ServerLevel) this.level);
}
chunksection = new LevelChunkSection(yPos >> 4 << 4);
this.sections[yPos >> 4] = chunksection;
}
// Sponge Start - Build out the BlockTransaction
final PhaseContext<@NonNull ?> context = PhaseTracker.getInstance().getPhaseContext();
@Nullable final BlockEntity existing = this.shadow$getBlockEntity(pos, LevelChunk.EntityCreationType.CHECK);
// Build a transaction maybe?
final WeakReference<ServerLevel> ref = new WeakReference<>((ServerLevel) this.level);
final SpongeBlockSnapshot snapshot = TrackingUtil.createPooledSnapshot(currentState, pos, flag, limit, existing, () -> Objects.requireNonNull(ref.get(), "ServerWorld dereferenced"), Optional::empty, Optional::empty);
// Pulled up from below
final ChangeBlock transaction = context.createTransaction(snapshot, newState, flag);
snapshot.blockChange = context.associateBlockChangeWithSnapshot(newState, currentState);
if (((BlockStateBridge) snapshot.state()).bridge$hasTileEntity() && (snapshot.blockChange == BlockChange.BREAK || snapshot.blockChange == BlockChange.MODIFY)) {
transaction.queuedRemoval = existing;
}
final ChunkPipeline.Builder builder = ChunkPipeline.builder().kickOff(transaction).chunk((LevelChunk) (Object) this).chunkSection(chunksection).world((ServerLevel) this.level);
// Populate the effects
transaction.populateChunkEffects(builder);
return builder.build();
}
Aggregations