687a75f4d5
Overhauled the way in which CommonTickHandler triggers tick-based actions such as Limbo decay, spawning Monoliths, and regenerating rifts. Now CommonTickHandler implements an interface called IRegularTickSender, which indicates that it will periodically call on classes that implement IRegulatTickReceiver to perform some task. I added classes for each regularly scheduled task we were performing: MonolithSpawner and RiftRegenerator, plus converted LimboDecay to a normal class instead of a static class. Modified several classes so that they have access to the MonolithSpawner instance to request MonolithSpawning when needed. This improves the structure of our code and gets us away from the way we did things before, which was accessing a public static list inside CommonTickHandler from other classes and adding arrays to specify chunk coordinates. We should not be exposing the internal state of classes like that! And we should be using clearly defined objects to pass information.
203 lines
5.8 KiB
Java
203 lines
5.8 KiB
Java
package StevenDimDoors.mod_pocketDim.ticking;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Random;
|
|
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.server.MinecraftServer;
|
|
import net.minecraft.world.GameRules;
|
|
import net.minecraft.world.World;
|
|
import StevenDimDoors.mod_pocketDim.DDProperties;
|
|
import StevenDimDoors.mod_pocketDim.DimData;
|
|
import StevenDimDoors.mod_pocketDim.helpers.dimHelper;
|
|
import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper;
|
|
import StevenDimDoors.mod_pocketDim.util.ChunkLocation;
|
|
|
|
public class MonolithSpawner implements IRegularTickReceiver {
|
|
|
|
public static final int MAX_MONOLITH_SPAWNING_CHANCE = 100;
|
|
private static final String MOB_SPAWNING_RULE = "doMobSpawning";
|
|
private static final int MAX_MONOLITH_SPAWN_Y = 245;
|
|
private static final int CHUNK_SIZE = 16;
|
|
private static final int MONOLITH_SPAWNING_INTERVAL = 1;
|
|
|
|
private DDProperties properties;
|
|
private ArrayList<ChunkLocation> locations;
|
|
|
|
public MonolithSpawner(IRegularTickSender sender, DDProperties properties)
|
|
{
|
|
this.properties = properties;
|
|
this.locations = new ArrayList<ChunkLocation>();
|
|
sender.registerForTicking(this, MONOLITH_SPAWNING_INTERVAL, false);
|
|
}
|
|
|
|
@Override
|
|
public void notifyTick() {
|
|
|
|
//Check if any new spawning requests have come in
|
|
if (!locations.isEmpty())
|
|
{
|
|
//Check if mob spawning is allowed
|
|
if (isMobSpawningAllowed())
|
|
{
|
|
//Loop over the locations and call the appropriate function depending
|
|
//on whether the request is for Limbo or for a pocket dimension.
|
|
for (ChunkLocation location : locations)
|
|
{
|
|
if (location.DimensionID == properties.LimboDimensionID)
|
|
{
|
|
//Limbo chunk
|
|
placeMonolithsInLimbo(location.DimensionID, location.ChunkX, location.ChunkZ);
|
|
}
|
|
else
|
|
{
|
|
//Pocket dimension chunk
|
|
placeMonolithsInPocket(location.DimensionID, location.ChunkX, location.ChunkZ);
|
|
}
|
|
}
|
|
}
|
|
|
|
locations.clear();
|
|
}
|
|
}
|
|
|
|
public void registerChunkForPopulation(int dimensionID, int chunkX, int chunkZ)
|
|
{
|
|
ChunkLocation location = new ChunkLocation(dimensionID, chunkX, chunkZ);
|
|
locations.add(location);
|
|
}
|
|
|
|
private void placeMonolithsInPocket(int dimensionID, int chunkX, int chunkZ)
|
|
{
|
|
World pocket = dimHelper.getWorld(dimensionID);
|
|
DimData dimData = dimHelper.dimList.get(dimensionID);
|
|
int sanity = 0;
|
|
int blockID = 0;
|
|
boolean didSpawn = false;
|
|
|
|
if (pocket == null ||
|
|
dimData == null ||
|
|
dimData.dungeonGenerator == null ||
|
|
dimData.dungeonGenerator.isOpen)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//The following initialization code is based on code from ChunkProviderGenerate.
|
|
//It makes our generation depend on the world seed.
|
|
Random random = new Random(pocket.getSeed());
|
|
long factorA = random.nextLong() / 2L * 2L + 1L;
|
|
long factorB = random.nextLong() / 2L * 2L + 1L;
|
|
random.setSeed(chunkX * factorA + chunkZ * factorB ^ pocket.getSeed());
|
|
|
|
//The following code really, really needs to be rewritten... "sanity" is not a proper variable name. ~SenseiKiwi
|
|
int x, y, z;
|
|
do
|
|
{
|
|
//Select a random column within the chunk
|
|
x = chunkX * CHUNK_SIZE + random.nextInt(CHUNK_SIZE);
|
|
z = chunkZ * CHUNK_SIZE + random.nextInt(CHUNK_SIZE);
|
|
y = MAX_MONOLITH_SPAWN_Y;
|
|
blockID = pocket.getBlockId(x, y, z);
|
|
|
|
while (blockID == 0 &&y>0)
|
|
{
|
|
y--;
|
|
blockID = pocket.getBlockId(x, y, z);
|
|
|
|
}
|
|
while ((blockID == properties.FabricBlockID || blockID == properties.PermaFabricBlockID) && y > 0)
|
|
{
|
|
y--;
|
|
blockID = pocket.getBlockId(x, y, z);
|
|
}
|
|
while (blockID == 0 && y > 0)
|
|
{
|
|
y--;
|
|
blockID = pocket.getBlockId(x, y, z);
|
|
}
|
|
if(y > 0)
|
|
{
|
|
int jumpSanity = 0;
|
|
int jumpHeight = 0;
|
|
do
|
|
{
|
|
jumpHeight = y + random.nextInt(10);
|
|
jumpSanity++;
|
|
}
|
|
while (!pocket.isAirBlock(x,jumpHeight+6 , z)&&jumpSanity<20);
|
|
|
|
Entity monolith = new MobObelisk(pocket);
|
|
monolith.setLocationAndAngles(x, jumpHeight, z, 1, 1);
|
|
pocket.spawnEntityInWorld(monolith);
|
|
didSpawn = true;
|
|
}
|
|
sanity++;
|
|
}
|
|
while (sanity < 5 && !didSpawn);
|
|
}
|
|
|
|
private void placeMonolithsInLimbo(int dimensionID, int chunkX, int chunkZ)
|
|
{
|
|
World limbo = dimHelper.getWorld(dimensionID);
|
|
|
|
if (limbo == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//The following initialization code is based on code from ChunkProviderGenerate.
|
|
//It makes our generation depend on the world seed.
|
|
Random random = new Random(limbo.getSeed());
|
|
long factorA = random.nextLong() / 2L * 2L + 1L;
|
|
long factorB = random.nextLong() / 2L * 2L + 1L;
|
|
random.setSeed(chunkX * factorA + chunkZ * factorB ^ limbo.getSeed());
|
|
|
|
//Okay, the following code is full of magic constants and makes little sense. =/ ~SenseiKiwi
|
|
if (random.nextInt(MAX_MONOLITH_SPAWNING_CHANCE) < properties.MonolithSpawningChance)
|
|
{
|
|
int y = 0;
|
|
int yTest;
|
|
do
|
|
{
|
|
int x = chunkX * CHUNK_SIZE + random.nextInt(CHUNK_SIZE);
|
|
int z = chunkZ * CHUNK_SIZE + random.nextInt(CHUNK_SIZE);
|
|
|
|
while (limbo.getBlockId(x, y, z) == 0 && y <255)
|
|
{
|
|
y++;
|
|
}
|
|
y = yCoordHelper.getFirstUncovered(limbo, x, y + 2, z);
|
|
yTest = yCoordHelper.getFirstUncovered(limbo, x, y + 5, z);
|
|
if (yTest > 245)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int jumpSanity = 0;
|
|
int jumpHeight = 0;
|
|
do
|
|
{
|
|
jumpHeight = y + random.nextInt(25);
|
|
jumpSanity++;
|
|
}
|
|
while (!limbo.isAirBlock(x, jumpHeight + 6, z) && jumpSanity < 20);
|
|
|
|
|
|
Entity monolith = new MobObelisk(limbo);
|
|
monolith.setLocationAndAngles(x, jumpHeight, z, 1, 1);
|
|
limbo.spawnEntityInWorld(monolith);
|
|
}
|
|
while (yTest > y);
|
|
}
|
|
}
|
|
|
|
private static boolean isMobSpawningAllowed()
|
|
{
|
|
//This function is used to retrieve the value of doMobSpawning. The code is the same
|
|
//as the code used by Minecraft. Jaitsu requested this to make testing easier. ~SenseiKiwi
|
|
|
|
GameRules rules = MinecraftServer.getServer().worldServerForDimension(0).getGameRules();
|
|
return rules.getGameRuleBooleanValue(MOB_SPAWNING_RULE);
|
|
}
|
|
}
|