Skip to content

Commit

Permalink
Fix various issues with mod dimensions.
Browse files Browse the repository at this point in the history
* Change keepSpawnLoaded, generateSpawnOnLoad, and loadOnStartup to
Boolean's to determine when nothing is set.
* Move PlayerChunkMap chunk unload queue with no players to start of server tick.
  This avoids chunks from unloading when requested before PlayerChunkMap tick.
* Always allow chunks to load when requested from getTileEntity.
  This fixes issues with mods such as RFToolsDimensions that check for a
  specific TE to perform logic.
* Remove unregisterable dimension code as it breaks Forge.
* Fix wrong foldername being used for hot-loaded dimensions.

Fixes #910, Fixes #920, Fixes #995, Fixes #1046
Fixes #1109, Fixes #1117, Fixes #1153
  • Loading branch information
bloodmc committed Feb 6, 2017
1 parent bf0cc9f commit dbf3c82
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 64 deletions.
Expand Up @@ -50,13 +50,13 @@ public class WorldCategory extends ConfigCategory {
protected boolean worldEnabled = true;

@Setting(value = "load-on-startup", comment = "Enable if this world should be loaded on startup.")
protected boolean loadOnStartup = true;
protected Boolean loadOnStartup;

@Setting(value = "generate-spawn-on-load", comment = "Enable if you want the world to generate spawn the moment its loaded.")
protected boolean generateSpawnOnLoad = true;
protected Boolean generateSpawnOnLoad;

@Setting(value = "keep-spawn-loaded", comment = "Enable if this world's spawn should remain loaded with no players.")
protected boolean keepSpawnLoaded = true;
protected Boolean keepSpawnLoaded;

@Setting(value = "pvp-enabled", comment = "Enable if this world allows PVP combat.")
protected boolean pvpEnabled = true;
Expand Down Expand Up @@ -145,19 +145,19 @@ public void setChunkUnloadDelay(int delay) {
this.chunkUnloadDelay = delay;
}

public boolean loadOnStartup() {
public Boolean loadOnStartup() {
return this.loadOnStartup;
}

public void setLoadOnStartup(boolean state) {
public void setLoadOnStartup(Boolean state) {
this.loadOnStartup = state;
}

public boolean getKeepSpawnLoaded() {
public Boolean getKeepSpawnLoaded() {
return this.keepSpawnLoaded;
}

public void setKeepSpawnLoaded(boolean loaded) {
public void setKeepSpawnLoaded(Boolean loaded) {
this.keepSpawnLoaded = loaded;
}

Expand All @@ -169,11 +169,11 @@ public void setPVPEnabled(boolean allow) {
this.pvpEnabled = allow;
}

public boolean getGenerateSpawnOnLoad() {
public Boolean getGenerateSpawnOnLoad() {
return this.generateSpawnOnLoad;
}

public void setGenerateSpawnOnLoad(boolean allow) {
public void setGenerateSpawnOnLoad(Boolean allow) {
this.generateSpawnOnLoad = allow;
}

Expand Down
Expand Up @@ -34,6 +34,8 @@ public interface IMixinWorld {

void setWeatherStartTime(long weatherStartTime);

void setCallingWorldEvent(boolean flag);

@Nullable
EntityPlayer getClosestPlayerToEntityWhoAffectsSpawning(net.minecraft.entity.Entity entity, double d1tance);

Expand Down
Expand Up @@ -48,7 +48,6 @@
import net.minecraft.world.WorldServer;
import net.minecraft.world.WorldType;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.WorldInfo;
import org.apache.logging.log4j.Logger;
import org.spongepowered.api.Server;
import org.spongepowered.api.Sponge;
Expand Down Expand Up @@ -329,7 +328,7 @@ protected void loadAllWorlds(String overworldFolder, String worldName, long seed

WorldManager.loadAllWorlds(worldName, seed, type, generatorOptions);

this.getPlayerList().setPlayerManager(new WorldServer[]{WorldManager.getWorldByDimensionId(0).get()});
this.getPlayerList().setPlayerManager(this.worldServers);
this.setDifficultyForAllWorlds(this.getDifficulty());
this.initialWorldChunkLoad();
}
Expand Down Expand Up @@ -569,16 +568,31 @@ public String toString() {
return getClass().getSimpleName();
}

@Redirect(method = "updateTimeLightAndEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/WorldServer;getWorldInfo()Lnet/minecraft/world/storage/WorldInfo;"))
public WorldInfo onUpdateTimeLightAndEntitiesGetWorld(WorldServer worldServer) {
// ChunkGC needs to be processed before a world tick in order to guarantee any chunk queued for unload
// can still be marked active and avoid unload if accessed during the same tick.
// Note: This injection must come before Forge's pre world tick event or it will cause issues with mods.
IMixinWorldServer spongeWorld = (IMixinWorldServer) worldServer;
if (spongeWorld.getChunkGCTickInterval() > 0) {
spongeWorld.doChunkGC();
// All chunk unload queuing needs to be processed BEFORE the future tasks are run as mods/plugins may have tasks that request chunks.
// This prevents a situation where a chunk is requested to load then unloads at end of tick.
@Inject(method = "updateTimeLightAndEntities", at = @At("HEAD"))
public void onUpdateTimeLightAndEntitiesHead(CallbackInfo ci) {
for (int i = 0; i < this.worldServers.length; ++i)
{
WorldServer worldServer = this.worldServers[i];
// ChunkGC needs to be processed before a world tick in order to guarantee any chunk queued for unload
// can still be marked active and avoid unload if accessed during the same tick.
// Note: This injection must come before Forge's pre world tick event or it will cause issues with mods.
IMixinWorldServer spongeWorld = (IMixinWorldServer) worldServer;
if (spongeWorld.getChunkGCTickInterval() > 0) {
spongeWorld.doChunkGC();
}
// Moved from PlayerChunkMap to avoid chunks from unloading after being requested in same tick
if (worldServer.getPlayerChunkMap().players.isEmpty())
{
WorldProvider worldprovider = worldServer.provider;

if (!worldprovider.canRespawnHere())
{
worldServer.getChunkProvider().unloadAllChunks();
}
}
}
return worldServer.getWorldInfo();
}

@Redirect(method = "updateTimeLightAndEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/WorldServer;getEntityTracker()Lnet/minecraft/entity/EntityTracker;"))
Expand Down
Expand Up @@ -24,6 +24,7 @@
*/
package org.spongepowered.common.mixin.core.server.management;

import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.management.PlayerChunkMap;
import net.minecraft.server.management.PlayerChunkMapEntry;
import net.minecraft.world.WorldServer;
Expand All @@ -41,6 +42,8 @@
import org.spongepowered.common.interfaces.server.management.IMixinPlayerChunkMap;
import org.spongepowered.common.interfaces.world.IMixinWorldServer;

import java.util.List;

import javax.annotation.Nullable;

@Mixin(PlayerChunkMap.class)
Expand Down Expand Up @@ -76,6 +79,13 @@ private void onUnloadChunk(ChunkProviderServer chunkProvider, Chunk chunk) {
}
}

@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Ljava/util/List;isEmpty()Z", ordinal = 2))
private boolean onChunkUnloadCheck(List<EntityPlayerMP> playerList) {
// Queuing all chunks for unload when there are no players has been moved to start of tick in MixinMinecraftServer.
// This avoids chunks from reloading when any request to load a chunk is done before this call such as a mod requesting a TE.
return false;
}

@Inject(method = "tick", at = @At(value = "INVOKE", target = "Ljava/util/Set;iterator()Ljava/util/Iterator;", ordinal = 0))
public void onStartUpdateLoop(CallbackInfo ci) {
this.isUpdatingInstances = true;
Expand Down
Expand Up @@ -565,10 +565,24 @@ public void setEnabled(boolean enabled) {

@Override
public boolean loadOnStartup() {
Boolean loadOnStartup = null;
if (!this.worldConfig.getConfig().isConfigEnabled()) {
return SpongeHooks.getActiveConfig(((IMixinDimensionType) this.dimensionType).getConfigPath(), this.getWorldName()).getConfig().getWorld().loadOnStartup();
DimensionConfig dimConfig = ((IMixinDimensionType) this.dimensionType).getDimensionConfig().getConfig();
if (dimConfig.isConfigEnabled()) {
loadOnStartup = dimConfig.getWorld().loadOnStartup();
} else {
loadOnStartup = this.worldConfig.getConfig().getWorld().loadOnStartup();
}
} else {
loadOnStartup = this.worldConfig.getConfig().getWorld().loadOnStartup();
}
if (loadOnStartup == null) {
if (this.dimensionId != null) {
return ((IMixinDimensionType) this.dimensionType).shouldGenerateSpawnOnLoad();
}
return false;
}
return this.worldConfig.getConfig().getWorld().loadOnStartup();
return loadOnStartup;
}

@Override
Expand All @@ -578,10 +592,21 @@ public void setLoadOnStartup(boolean state) {

@Override
public boolean doesKeepSpawnLoaded() {
Boolean keepSpawnLoaded = null;
if (!this.worldConfig.getConfig().isConfigEnabled()) {
return SpongeHooks.getActiveConfig(((IMixinDimensionType) this.dimensionType).getConfigPath(), this.getWorldName()).getConfig().getWorld().getKeepSpawnLoaded();
DimensionConfig dimConfig = ((IMixinDimensionType) this.dimensionType).getDimensionConfig().getConfig();
if (dimConfig.isConfigEnabled()) {
keepSpawnLoaded = dimConfig.getWorld().getKeepSpawnLoaded();
} else {
keepSpawnLoaded = this.worldConfig.getConfig().getWorld().getKeepSpawnLoaded();
}
} else {
keepSpawnLoaded = this.worldConfig.getConfig().getWorld().getKeepSpawnLoaded();
}
return this.worldConfig.getConfig().getWorld().getKeepSpawnLoaded();
if (keepSpawnLoaded == null) {
return ((IMixinDimensionType) this.dimensionType).shouldGenerateSpawnOnLoad();
}
return keepSpawnLoaded;
}

@Override
Expand All @@ -591,13 +616,21 @@ public void setKeepSpawnLoaded(boolean loaded) {

@Override
public boolean doesGenerateSpawnOnLoad() {
Boolean shouldGenerateSpawn = null;
if (!this.worldConfig.getConfig().isConfigEnabled()) {
DimensionConfig dimConfig = ((IMixinDimensionType) this.dimensionType).getDimensionConfig().getConfig();
if (dimConfig.isConfigEnabled()) {
return dimConfig.getWorld().getGenerateSpawnOnLoad();
shouldGenerateSpawn = dimConfig.getWorld().getGenerateSpawnOnLoad();
} else {
shouldGenerateSpawn = this.worldConfig.getConfig().getWorld().getGenerateSpawnOnLoad();
}
} else {
shouldGenerateSpawn = this.worldConfig.getConfig().getWorld().getGenerateSpawnOnLoad();
}
if (shouldGenerateSpawn == null) {
return ((IMixinDimensionType) this.dimensionType).shouldGenerateSpawnOnLoad();
}
return this.worldConfig.getConfig().getWorld().getGenerateSpawnOnLoad();
return shouldGenerateSpawn;
}

@Override
Expand Down
Expand Up @@ -57,9 +57,7 @@ public abstract class MixinWorld_Inline_Valid_BlockPos {
@Shadow public abstract void notifyLightSet(BlockPos pos);
@Shadow public abstract IChunkProvider getChunkProvider();

@Shadow @Nullable private TileEntity getPendingTileEntityAt(BlockPos p_189508_1_) {
return null; // Shadowed
}
@Shadow @Nullable public abstract TileEntity getPendingTileEntityAt(BlockPos p_189508_1_);

/**
* @author gabizou - August 4th, 2016
Expand Down Expand Up @@ -99,12 +97,6 @@ public TileEntity getTileEntity(BlockPos pos) {
} else {
TileEntity tileentity = null;

// Sponge start - don't allow loading chunks here
if (!this.isBlockLoaded(pos)) {
return null;
}
// Sponge end

if (this.processingLoadedTiles) {
tileentity = this.getPendingTileEntityAt(pos);
}
Expand Down

0 comments on commit dbf3c82

Please sign in to comment.