Skip to content

Commit

Permalink
Merge branch 'api-12' into api-13
Browse files Browse the repository at this point in the history
# Conflicts:
#	forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/PluginFileParser.java
#	gradle.properties
#	src/main/java/org/spongepowered/common/event/tracking/TrackingUtil.java
#	src/mixins/java/org/spongepowered/common/mixin/core/world/entity/LivingEntityMixin_Attack_Impl.java
#	src/mixins/java/org/spongepowered/common/mixin/core/world/entity/player/PlayerMixin_Attack_Impl.java
#	src/mixins/java/org/spongepowered/common/mixin/tracker/server/level/ServerLevelMixin_Tracker.java
#	src/mixins/java/org/spongepowered/common/mixin/tracker/world/level/LevelMixin_Tracker.java
#	src/mixins/resources/mixins.sponge.tracker.json
  • Loading branch information
Yeregorix committed Jan 22, 2025
2 parents 0d0366a + 8d8a232 commit b751024
Show file tree
Hide file tree
Showing 12 changed files with 254 additions and 209 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@

import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
Expand All @@ -70,7 +69,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -96,30 +94,6 @@ public SpongeEventManager() {
this.handlersByEvent = HashMultimap.create();
this.registeredListeners = new ReferenceOpenHashSet<>();
this.checker = new ListenerChecker(ShouldFire.class);

// Caffeine offers no control over the concurrency level of the
// ConcurrentHashMap which backs the cache. By default this concurrency
// level is 16. We replace the backing map before any use can occur
// a new ConcurrentHashMap with a concurrency level of 1
try {
// Cache impl class is UnboundedLocalLoadingCache which extends
// UnboundedLocalManualCache

// UnboundedLocalManualCache has a field 'cache' with an
// UnboundedLocalCache which contains the actual backing map
final Field innerCache = this.handlersCache.getClass().getSuperclass().getDeclaredField("cache");
innerCache.setAccessible(true);
final Object innerCacheValue = innerCache.get(this.handlersCache);
final Class<?> innerCacheClass = innerCacheValue.getClass(); // UnboundedLocalCache
final Field cacheData = innerCacheClass.getDeclaredField("data");
cacheData.setAccessible(true);
final ConcurrentHashMap<Class<? extends Event>, RegisteredListener.Cache> newBackingData =
new ConcurrentHashMap<>(150, 0.75f, 1);
cacheData.set(innerCacheValue, newBackingData);
} catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
SpongeCommon.logger().warn("Failed to set event cache backing array, type was " + this.handlersCache.getClass().getName());
SpongeCommon.logger().warn(" Caused by: " + e.getClass().getName() + ": " + e.getMessage());
}
}

private static @Nullable String getHandlerErrorOrNull(final ListenerClassVisitor.DiscoveredMethod method) throws
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import net.minecraft.world.level.BlockEventData;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.TickingBlockEntity;
import net.minecraft.world.level.material.FluidState;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
Expand All @@ -51,19 +50,13 @@
import org.spongepowered.api.world.BlockChangeFlags;
import org.spongepowered.api.world.LocatableBlock;
import org.spongepowered.common.SpongeCommon;
import org.spongepowered.common.accessor.world.level.chunk.LevelChunk$BoundTickingBlockEntityAccessor;
import org.spongepowered.common.accessor.world.level.chunk.LevelChunk$RebindableTickingBlockEntityWrapperAccessor;
import org.spongepowered.common.accessor.world.level.chunk.LevelChunkAccessor;
import org.spongepowered.common.block.SpongeBlockSnapshot;
import org.spongepowered.common.bridge.CreatorTrackedBridge;
import org.spongepowered.common.bridge.TrackableBridge;
import org.spongepowered.common.bridge.world.TrackedWorldBridge;
import org.spongepowered.common.bridge.world.inventory.ViewableInventoryBridge;
import org.spongepowered.common.bridge.world.level.TrackableBlockEventDataBridge;
import org.spongepowered.common.bridge.world.level.block.entity.BlockEntityBridge;
import org.spongepowered.common.bridge.world.level.chunk.ActiveChunkReferantBridge;
import org.spongepowered.common.bridge.world.level.chunk.LevelChunkBridge;
import org.spongepowered.common.bridge.world.level.chunk.TrackedLevelChunkBridge;
import org.spongepowered.common.entity.PlayerTracker;
import org.spongepowered.common.event.ShouldFire;
import org.spongepowered.common.event.SpongeCommonEventFactory;
Expand All @@ -85,7 +78,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;

/**
Expand All @@ -103,7 +96,7 @@ public final class TrackingUtil {

public static final int WIDTH = 40;

public static void tickEntity(final Consumer<net.minecraft.world.entity.Entity> consumer, final net.minecraft.world.entity.Entity entity) {
public static void tickEntity(final net.minecraft.world.entity.Entity entity, final Runnable tick) {
Preconditions.checkArgument(entity instanceof Entity, () -> String.format("Entity %s is not an instance of SpongeAPI's Entity!", entity));
Objects.requireNonNull(entity, "Cannot capture on a null ticking entity!");
if (!((TrackableBridge) entity).bridge$shouldTick()) {
Expand All @@ -113,13 +106,13 @@ public static void tickEntity(final Consumer<net.minecraft.world.entity.Entity>
final PhaseTracker phaseTracker = PhaseTracker.getWorldInstance((ServerLevel) entity.level());
final EntityTickContext tickContext = TickPhase.Tick.ENTITY.createPhaseContext(phaseTracker).source(entity);
try (final EntityTickContext context = tickContext) {
if (entity instanceof CreatorTrackedBridge) {
((CreatorTrackedBridge) entity).tracker$getNotifierUUID().ifPresent(context::notifier);
((CreatorTrackedBridge) entity).tracker$getCreatorUUID().ifPresent(context::creator);
if (entity instanceof CreatorTrackedBridge ctb) {
ctb.tracker$getNotifierUUID().ifPresent(context::notifier);
ctb.tracker$getCreatorUUID().ifPresent(context::creator);
}
context.buildAndSwitch();
PhaseTracker.LOGGER.trace(TrackingUtil.ENTITY_TICK, () -> "Wrapping Entity Tick: " + entity.toString());
consumer.accept(entity);
tick.run();
if (ShouldFire.MOVE_ENTITY_EVENT) {
SpongeCommonEventFactory.callNaturalMoveEntityEvent(entity);
}
Expand All @@ -131,79 +124,51 @@ public static void tickEntity(final Consumer<net.minecraft.world.entity.Entity>
}
}

private static Optional<net.minecraft.world.level.block.entity.BlockEntity> getTickingBlockEntity(
final TickingBlockEntity ticker) {
if (ticker instanceof LevelChunk$BoundTickingBlockEntityAccessor beAccessor) {
return Optional.of(beAccessor.accessor$blockEntity());
} else if (ticker instanceof LevelChunk$RebindableTickingBlockEntityWrapperAccessor beAccessor) {
return getTickingBlockEntity(beAccessor.accessor$ticker());
} else if (ticker == LevelChunkAccessor.accessor$NULL_TICKER()) {
return Optional.empty();
}
return Optional.empty();
}

@SuppressWarnings({"unused", "try"})
public static void tickTileEntity(final TrackedWorldBridge mixinWorldServer, final TickingBlockEntity tile) {
Objects.requireNonNull(tile, "Cannot capture on a null ticking tile entity!");
final Optional<BlockEntity> tickingBlockEntity = getTickingBlockEntity(tile);
if (!tickingBlockEntity.isPresent()) {
return;
}
final net.minecraft.world.level.block.entity.BlockEntity blockEntity = tickingBlockEntity.get();
public static void tickTileEntity(final BlockEntity blockEntity, final Runnable tick) {
Objects.requireNonNull(blockEntity, "Cannot capture on a null ticking tile entity!");
if (!((org.spongepowered.api.block.entity.BlockEntity) blockEntity).isTicking()) {
return;
}
final BlockEntityBridge mixinTileEntity = (BlockEntityBridge) tickingBlockEntity.get();
final BlockPos pos = blockEntity.getBlockPos();
final @Nullable LevelChunkBridge chunk = ((ActiveChunkReferantBridge) blockEntity).bridge$getActiveChunk();
if (!((TrackableBridge) blockEntity).bridge$shouldTick()) {
return;
}
if (chunk == null) {
((ActiveChunkReferantBridge) blockEntity).bridge$setActiveChunk((TrackedLevelChunkBridge) blockEntity.getLevel().getChunkAt(blockEntity.getBlockPos()));
}

final PhaseTracker phaseTracker = PhaseTracker.getWorldInstance((ServerLevel) blockEntity.getLevel());
final TileEntityTickContext context = TickPhase.Tick.TILE_ENTITY.createPhaseContext(phaseTracker).source(mixinTileEntity);
final TileEntityTickContext context = TickPhase.Tick.TILE_ENTITY.createPhaseContext(phaseTracker).source(blockEntity);
try (final PhaseContext<@NonNull ?> phaseContext = context) {

if (blockEntity instanceof CreatorTrackedBridge) {
if (blockEntity instanceof CreatorTrackedBridge ctb) {
// Add notifier and owner so we don't have to perform lookups during the phases and other processing
((CreatorTrackedBridge) blockEntity).tracker$getNotifierUUID().ifPresent(phaseContext::notifier);
ctb.tracker$getNotifierUUID().ifPresent(phaseContext::notifier);
// Allow the tile entity to validate the owner of itself. As long as the tile entity
// chunk is already loaded and activated, and the tile entity has already loaded
// the owner of itself.
((CreatorTrackedBridge) blockEntity).tracker$getCreatorUUID().ifPresent(phaseContext::creator);
ctb.tracker$getCreatorUUID().ifPresent(phaseContext::creator);
}

// Finally, switch the context now that we have the owner and notifier
phaseContext.buildAndSwitch();

PhaseTracker.LOGGER.trace(TrackingUtil.BLOCK_ENTITY_TICK, () -> "Wrapping Entity Tick: " + tile.toString());
tile.tick();
PhaseTracker.LOGGER.trace(TrackingUtil.BLOCK_ENTITY_TICK, () -> "Wrapping Entity Tick: " + blockEntity);
tick.run();

// If we know the viewers force broadcast now to associate the inventory change with its blockentity
// otherwise the viewing players update this during their ticking
if (blockEntity instanceof ViewableInventoryBridge) {
final Set<ServerPlayer> players = ((ViewableInventoryBridge) blockEntity).viewableBridge$getViewers();
if (players.size() > 0) {
if (blockEntity instanceof ViewableInventoryBridge vib) {
final Set<ServerPlayer> players = vib.viewableBridge$getViewers();
if (!players.isEmpty()) {
players.forEach(player -> player.containerMenu.broadcastChanges());
}
}

} catch (final Exception e) {
PhasePrinter.printExceptionFromPhase(phaseTracker.stack, e, context);
}
// We delay clearing active chunk if TE is invalidated during tick so we must remove it after
if (blockEntity.isRemoved()) {
((ActiveChunkReferantBridge) blockEntity).bridge$setActiveChunk(null);
}
}

@SuppressWarnings("rawtypes")
public static void updateTickBlock(
final TrackedWorldBridge mixinWorld, final net.minecraft.world.level.block.state.BlockState block, final BlockPos pos, final RandomSource random) {
final TrackedWorldBridge mixinWorld, final net.minecraft.world.level.block.state.BlockState block,
final BlockPos pos, final Runnable tick) {
final ServerLevel world = (ServerLevel) mixinWorld;
final org.spongepowered.api.world.server.ServerWorld apiWorld = (org.spongepowered.api.world.server.ServerWorld) world;
final PhaseTracker phaseTracker = PhaseTracker.getWorldInstance(world);
Expand All @@ -228,15 +193,15 @@ public static void updateTickBlock(
try (final PhaseContext<@NonNull ?> context = phaseContext) {
context.buildAndSwitch();
PhaseTracker.LOGGER.trace(TrackingUtil.BLOCK_TICK, () -> "Wrapping Block Tick: " + block.toString());
block.tick(world, pos, random);
tick.run();
} catch (final Exception | NoClassDefFoundError e) {
PhasePrinter.printExceptionFromPhase(phaseTracker.stack, e, phaseContext);

}
}

public static void updateTickFluid(
final TrackedWorldBridge mixinWorld, final FluidState fluidState, final BlockPos pos, final net.minecraft.world.level.block.state.BlockState blockState) {
final TrackedWorldBridge mixinWorld, final FluidState fluidState, final BlockPos pos, final net.minecraft.world.level.block.state.BlockState blockState, final Runnable tick) {
final ServerLevel world = (ServerLevel) mixinWorld;
final org.spongepowered.api.world.server.ServerWorld apiWorld = (org.spongepowered.api.world.server.ServerWorld) world;
final PhaseTracker phaseTracker = PhaseTracker.getWorldInstance(world);
Expand All @@ -263,16 +228,18 @@ public static void updateTickFluid(
try (final PhaseContext<?> context = phaseContext) {
context.buildAndSwitch();
PhaseTracker.LOGGER.trace(TrackingUtil.FLUID_TICK, () -> "Wrapping Fluid Tick: " + fluidState.toString());
fluidState.tick(world, pos, blockState);
tick.run();
} catch (final Exception | NoClassDefFoundError e) {
PhasePrinter.printExceptionFromPhase(phaseTracker.stack, e, phaseContext);

}
}

@SuppressWarnings("rawtypes")
public static void randomTickBlock(final TrackedWorldBridge mixinWorld,
final net.minecraft.world.level.block.state.BlockState state, final BlockPos pos, final RandomSource random) {
public static void randomTickBlock(
final TrackedWorldBridge mixinWorld, final net.minecraft.world.level.block.state.BlockState state,
final BlockPos pos, final RandomSource random, final Runnable tick
) {
final ServerLevel world = (ServerLevel) mixinWorld;
final org.spongepowered.api.world.server.ServerWorld apiWorld = (org.spongepowered.api.world.server.ServerWorld) world;
final PhaseTracker phaseTracker = PhaseTracker.getWorldInstance(world);
Expand Down Expand Up @@ -302,14 +269,17 @@ public static void randomTickBlock(final TrackedWorldBridge mixinWorld,
try (final PhaseContext<@NonNull ?> context = phaseContext) {
context.buildAndSwitch();
PhaseTracker.LOGGER.trace(TrackingUtil.BLOCK_TICK, "Wrapping Random Block Tick: {}", state);
state.randomTick(world, pos, random);
tick.run();
} catch (final Exception | NoClassDefFoundError e) {
PhasePrinter.printExceptionFromPhase(phaseTracker.stack, e, phaseContext);
}
}
@SuppressWarnings("rawtypes")
public static void randomTickFluid(final TrackedWorldBridge mixinWorld,
final FluidState state, final BlockPos pos, final RandomSource random) {
public static void randomTickFluid(
final TrackedWorldBridge mixinWorld,
final FluidState state, final BlockPos pos, final RandomSource random,
final Runnable tick
) {
final ServerLevel world = (ServerLevel) mixinWorld;
final org.spongepowered.api.world.server.ServerWorld apiWorld = (org.spongepowered.api.world.server.ServerWorld) world;
final PhaseTracker phaseTracker = PhaseTracker.getWorldInstance(world);
Expand Down Expand Up @@ -342,20 +312,20 @@ public static void randomTickFluid(final TrackedWorldBridge mixinWorld,
try (final PhaseContext<@NonNull ?> context = phaseContext) {
context.buildAndSwitch();
PhaseTracker.LOGGER.trace(TrackingUtil.FLUID_TICK, () -> "Wrapping Random Fluid Tick: " + state.toString());
state.randomTick(world, pos, random);
tick.run();
} catch (final Exception | NoClassDefFoundError e) {
PhasePrinter.printExceptionFromPhase(phaseTracker.stack, e, phaseContext);
}
}

public static boolean fireMinecraftBlockEvent(final ServerLevel worldIn, final BlockEventData event,
final net.minecraft.world.level.block.state.BlockState currentState
public static boolean fireMinecraftBlockEvent(
final ServerLevel worldIn, final BlockEventData event, final BooleanSupplier tick
) {
final TrackableBlockEventDataBridge blockEvent = (TrackableBlockEventDataBridge) (Object) event;
final @Nullable Object source = blockEvent.bridge$getTileEntity() != null ? blockEvent.bridge$getTileEntity() : blockEvent.bridge$getTickingLocatable();
if (source == null) {
// No source present which means we are ignoring the phase state
return currentState.triggerEvent(worldIn, event.pos(), event.paramA(), event.paramB());
return tick.getAsBoolean();
}
final BlockEventTickContext phaseContext = TickPhase.Tick.BLOCK_EVENT.createPhaseContext(PhaseTracker.getWorldInstance(worldIn));
phaseContext.source(source);
Expand All @@ -369,7 +339,7 @@ public static boolean fireMinecraftBlockEvent(final ServerLevel worldIn, final B
boolean result = true;
try (final BlockEventTickContext o = phaseContext) {
o.buildAndSwitch();
phaseContext.setEventSucceeded(currentState.triggerEvent(worldIn, event.pos(), event.paramA(), event.paramB()));
phaseContext.setEventSucceeded(tick.getAsBoolean());
// We need to grab the result here as the phase context close will trigger a reset
result = phaseContext.wasNotCancelled();
} // We can't return onBlockEventReceived because the phase state may have cancelled all transactions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ public TileEntityTickContext(final IPhaseState<TileEntityTickContext> phaseState
@Override
public TileEntityTickContext source(final Object owner) {
super.source(owner);
if (owner instanceof TrackableBridge) {
final TrackableBridge mixinTileentity = (TrackableBridge) owner;
if (owner instanceof TrackableBridge mixinTileentity) {
this.setBlockEvents(mixinTileentity.bridge$allowsBlockEventCreation())
.setBulkBlockCaptures(mixinTileentity.bridge$allowsBlockBulkCaptures())
.setEntitySpawnEvents(mixinTileentity.bridge$allowsEntityEventCreation())
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/spongepowered/common/util/NetworkUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ public final class NetworkUtil {
* @return The string representation of the host
*/
public static String getHostString(final SocketAddress address) {
if (address instanceof InetSocketAddress) {
return ((InetSocketAddress) address).getHostString();
if (address instanceof InetSocketAddress isa) {
return isa.getHostString();
} else if (address instanceof LocalAddress) {
return NetworkUtil.LOCAL_ADDRESS;
}
Expand Down
Loading

0 comments on commit b751024

Please sign in to comment.