use of org.spongepowered.common.bridge.server.level.ServerLevelBridge in project SpongeCommon by SpongePowered.
the class ServerLevelMixin method save.
/**
* @author zidane - December 17th, 2020 - Minecraft 1.16.4
* @reason Honor our serialization behavior in performing saves
*/
@Overwrite
public void save(@Nullable final ProgressListener progress, final boolean flush, final boolean skipSave) {
final Cause currentCause = Sponge.server().causeStackManager().currentCause();
if (Sponge.eventManager().post(SpongeEventFactory.createSaveWorldEventPre(currentCause, ((ServerWorld) this)))) {
// cancelled save
return;
}
final PrimaryLevelData levelData = (PrimaryLevelData) this.shadow$getLevelData();
final ServerChunkCache chunkProvider = ((ServerLevel) (Object) this).getChunkSource();
if (!skipSave) {
final SerializationBehavior behavior = ((PrimaryLevelDataBridge) levelData).bridge$serializationBehavior().orElse(SerializationBehavior.AUTOMATIC);
if (progress != null) {
progress.progressStartNoAbort(new TranslatableComponent("menu.savingLevel"));
}
// We always save the metadata unless it is NONE
if (behavior != SerializationBehavior.NONE) {
this.shadow$saveLevelData();
// Sponge Start - We do per-world WorldInfo/WorldBorders/BossBars
levelData.setWorldBorder(this.getWorldBorder().createSettings());
levelData.setCustomBossEvents(((ServerLevelBridge) this).bridge$getBossBarManager().save());
((ServerLevelBridge) this).bridge$getLevelSave().saveDataTag(SpongeCommon.server().registryAccess(), (PrimaryLevelData) this.shadow$getLevelData(), this.shadow$dimension() == Level.OVERWORLD ? SpongeCommon.server().getPlayerList().getSingleplayerData() : null);
// Sponge End
}
if (progress != null) {
progress.progressStage(new TranslatableComponent("menu.savingChunks"));
}
final boolean canAutomaticallySave = !this.impl$isManualSave && behavior == SerializationBehavior.AUTOMATIC;
final boolean canManuallySave = this.impl$isManualSave && behavior == SerializationBehavior.MANUAL;
if (canAutomaticallySave || canManuallySave) {
chunkProvider.save(flush);
}
Sponge.eventManager().post(SpongeEventFactory.createSaveWorldEventPost(currentCause, ((ServerWorld) this)));
}
this.impl$isManualSave = false;
}
use of org.spongepowered.common.bridge.server.level.ServerLevelBridge 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(final TrackedWorldBridge world, final BlockPos pos, final net.minecraft.world.level.block.state.BlockState blockstate, final int eventId) {
final boolean extending = (eventId == 0);
final net.minecraft.core.Direction direction = blockstate.getValue(DirectionalBlock.FACING);
final LocatableBlock locatable = new SpongeLocatableBlockBuilder().world((ServerWorld) world).state((BlockState) blockstate).position(pos.getX(), pos.getY(), pos.getZ()).build();
// Sets toss out duplicate values (even though there shouldn't be any)
final HashSet<ServerLocation> locations = new HashSet<>();
locations.add(ServerLocation.of((ServerWorld) world, pos.getX(), pos.getY(), pos.getZ()));
final PistonStructureResolver movedBlocks = new PistonStructureResolver((ServerLevel) world, pos, direction, extending);
// calculates blocks to be moved
movedBlocks.resolve();
Stream.concat(movedBlocks.getToPush().stream(), movedBlocks.getToDestroy().stream()).map(block -> ServerLocation.of((ServerWorld) 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.getToDestroy().isEmpty()) {
final List<BlockPos> movedPositions = movedBlocks.getToPush();
final BlockPos offsetPos;
// If there are no blocks to move, add the offset of piston
if (movedPositions.isEmpty()) {
offsetPos = pos.relative(direction);
} else {
// Add the offset of last block set to move
offsetPos = movedPositions.get(movedPositions.size() - 1).relative(direction);
}
locations.add(ServerLocation.of((ServerWorld) world, offsetPos.getX(), offsetPos.getY(), offsetPos.getZ()));
}
try (final CauseStackManager.StackFrame frame = PhaseTracker.getInstance().pushCauseFrame()) {
if (extending) {
frame.addContext(EventContextKeys.PISTON_EXTEND, (ServerWorld) world);
} else {
frame.addContext(EventContextKeys.PISTON_RETRACT, (ServerWorld) world);
}
return SpongeCommonEventFactory.callChangeBlockEventPre((ServerLevelBridge) world, ImmutableList.copyOf(locations), locatable).isCancelled();
}
}
use of org.spongepowered.common.bridge.server.level.ServerLevelBridge in project SpongeCommon by SpongePowered.
the class SpongeWorldManager method unloadWorld0.
private void unloadWorld0(final ServerLevel world) throws IOException {
final net.minecraft.resources.ResourceKey<Level> registryKey = world.dimension();
if (world.getPlayers(p -> true).size() != 0) {
throw new IOException(String.format("World '%s' was told to unload but players remain.", registryKey.location()));
}
SpongeCommon.logger().info("Unloading world '{}' ({})", registryKey.location(), RegistryTypes.WORLD_TYPE.get().valueKey((WorldType) world.dimensionType()));
SpongeCommon.post(SpongeEventFactory.createUnloadWorldEvent(PhaseTracker.getCauseStackManager().currentCause(), (org.spongepowered.api.world.server.ServerWorld) world));
final BlockPos spawnPoint = world.getSharedSpawnPos();
world.getChunkSource().removeRegionTicket(SpongeWorldManager.SPAWN_CHUNKS, new ChunkPos(spawnPoint), 11, registryKey.location());
((PrimaryLevelDataBridge) world.getLevelData()).bridge$configAdapter().save();
((ServerLevelBridge) world).bridge$setManualSave(true);
try {
world.save(null, true, world.noSave);
world.close();
((ServerLevelBridge) world).bridge$getLevelSave().close();
} catch (final Exception ex) {
throw new IOException(ex);
}
this.worlds.remove(registryKey);
}
use of org.spongepowered.common.bridge.server.level.ServerLevelBridge in project SpongeCommon by SpongePowered.
the class SpongeWorldManager method loadSpawnChunks.
private void loadSpawnChunks(final ServerLevel world) {
final BlockPos spawnPoint = world.getSharedSpawnPos();
final ChunkPos chunkPos = new ChunkPos(spawnPoint);
final ChunkProgressListener chunkStatusListener = ((ServerLevelBridge) world).bridge$getChunkStatusListener();
chunkStatusListener.updateSpawnPos(chunkPos);
final ServerChunkCache serverChunkProvider = world.getChunkSource();
serverChunkProvider.getLightEngine().setTaskPerBatch(500);
((MinecraftServerAccessor) this.server).accessor$nextTickTime(Util.getMillis());
serverChunkProvider.addRegionTicket(SpongeWorldManager.SPAWN_CHUNKS, chunkPos, 11, world.dimension().location());
while (serverChunkProvider.getTickingGenerated() != 441) {
((MinecraftServerAccessor) this.server).accessor$nextTickTime(Util.getMillis() + 10L);
((MinecraftServerAccessor) this.server).accessor$waitUntilNextTick();
}
((MinecraftServerAccessor) this.server).accessor$nextTickTime(Util.getMillis() + 10L);
((MinecraftServerAccessor) this.server).accessor$waitUntilNextTick();
this.updateForcedChunks(world, serverChunkProvider);
((MinecraftServerAccessor) this.server).accessor$nextTickTime(Util.getMillis() + 10L);
((MinecraftServerAccessor) this.server).accessor$waitUntilNextTick();
chunkStatusListener.stop();
serverChunkProvider.getLightEngine().setTaskPerBatch(5);
// Sponge Start - Release the chunk ticket if spawn is not set to be kept loaded...
if (!((PrimaryLevelDataBridge) world.getLevelData()).bridge$performsSpawnLogic()) {
serverChunkProvider.removeRegionTicket(SpongeWorldManager.SPAWN_CHUNKS, chunkPos, 11, world.dimension().location());
}
}
use of org.spongepowered.common.bridge.server.level.ServerLevelBridge in project SpongeCommon by SpongePowered.
the class ServerLevelMixin_Tracker method tracker$associatePhaseContextDataWithBlockEvent.
@Redirect(method = "blockEvent", at = @At(value = "INVOKE", target = "Lit/unimi/dsi/fastutil/objects/ObjectLinkedOpenHashSet;add(Ljava/lang/Object;)Z", remap = false))
private boolean tracker$associatePhaseContextDataWithBlockEvent(final ObjectLinkedOpenHashSet<BlockEventData> list, final Object data, final BlockPos pos, final Block blockIn, final int eventID, final int eventParam) {
final PhaseContext<@NonNull ?> currentContext = PhaseTracker.getInstance().getPhaseContext();
final BlockEventData blockEventData = (BlockEventData) data;
final TrackableBlockEventDataBridge blockEvent = (TrackableBlockEventDataBridge) blockEventData;
// Short circuit phase states who do not track during block events
if (currentContext.ignoresBlockEvent()) {
return list.add(blockEventData);
}
final BlockState state = this.shadow$getBlockState(pos);
if (((TrackableBridge) blockIn).bridge$allowsBlockEventCreation()) {
blockEvent.bridge$setSourceUserUUID(currentContext.getActiveUserUUID());
if (((BlockStateBridge) state).bridge$hasTileEntity()) {
blockEvent.bridge$setTileEntity((BlockEntity) this.shadow$getBlockEntity(pos));
}
if (blockEvent.bridge$getTileEntity() == null) {
final LocatableBlock locatable = new SpongeLocatableBlockBuilder().world((org.spongepowered.api.world.server.ServerWorld) this).position(pos.getX(), pos.getY(), pos.getZ()).state((org.spongepowered.api.block.BlockState) state).build();
blockEvent.bridge$setTickingLocatable(locatable);
}
}
// allow tracking to take place for other/future phases
if (!((TrackableBridge) blockIn).bridge$allowsBlockEventCreation()) {
return list.add((BlockEventData) data);
}
// In pursuant with our block updates management, we chose to
// effectively allow the block event get added to the list, but
// we log the transaction so that we can call the change block event
// pre, and if needed, undo the add to the list.
currentContext.appendNotifierToBlockEvent(this, pos, blockEvent);
// This is very common with pistons as they add block events while blocks are being notified.
if (ShouldFire.CHANGE_BLOCK_EVENT_PRE) {
if (blockIn instanceof PistonBaseBlock) {
// We only fire pre events for pistons
if (SpongeCommonEventFactory.handlePistonEvent(this, pos, state, eventID)) {
return false;
}
} else {
if (SpongeCommonEventFactory.callChangeBlockEventPre((ServerLevelBridge) this, pos).isCancelled()) {
return false;
}
}
}
currentContext.getTransactor().logBlockEvent(state, this, pos, blockEvent);
return list.add(blockEventData);
}
Aggregations