An attempt to create a chunk spanning gen algo
This is mostly just a proof of concept, Oil doesn't really need it.
This commit is contained in:
parent
2705e74ad0
commit
ee16c288aa
4 changed files with 246 additions and 91 deletions
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 7.1 KiB |
|
@ -90,7 +90,8 @@ public class BuildCraftEnergy {
|
|||
NetworkRegistry.instance().registerGuiHandler(instance, new GuiHandler());
|
||||
|
||||
if (BuildCraftCore.modifyWorld) {
|
||||
MinecraftForge.EVENT_BUS.register(new OilPopulate());
|
||||
MinecraftForge.EVENT_BUS.register(OilPopulate.INSTANCE);
|
||||
MinecraftForge.TERRAIN_GEN_BUS.register(OilPopulate.INSTANCE);
|
||||
}
|
||||
|
||||
new BptBlockEngine(engineBlock.blockID);
|
||||
|
@ -201,7 +202,7 @@ public class BuildCraftEnergy {
|
|||
if (id >= BiomeGenBase.biomeList.length) {
|
||||
throw new IllegalArgumentException("Biome ID must be less than " + BiomeGenBase.biomeList.length);
|
||||
}
|
||||
OilPopulate.surfaceDepositBiomes.add(id);
|
||||
OilPopulate.INSTANCE.surfaceDepositBiomes.add(id);
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger("Buildcraft").log(Level.WARNING,
|
||||
String.format("Received an invalid oil-lake-biome request %s from mod %s", m.getStringValue(), m.getSender()));
|
||||
|
@ -215,7 +216,7 @@ public class BuildCraftEnergy {
|
|||
if (id >= BiomeGenBase.biomeList.length) {
|
||||
throw new IllegalArgumentException("Biome ID must be less than " + BiomeGenBase.biomeList.length);
|
||||
}
|
||||
OilPopulate.excludedBiomes.add(id);
|
||||
OilPopulate.INSTANCE.excludedBiomes.add(id);
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger("Buildcraft").log(Level.WARNING,
|
||||
String.format("Received an invalid oil-gen-exclude request %s from mod %s", m.getStringValue(), m.getSender()));
|
||||
|
|
|
@ -13,21 +13,39 @@ import net.minecraft.block.Block;
|
|||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraftforge.event.ForgeSubscribe;
|
||||
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
|
||||
import net.minecraftforge.event.terraingen.TerrainGen;
|
||||
import buildcraft.BuildCraftCore;
|
||||
import buildcraft.BuildCraftEnergy;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import net.minecraft.block.BlockFlower;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraftforge.common.EnumHelper;
|
||||
import net.minecraftforge.common.ForgeDirection;
|
||||
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
|
||||
import net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType;
|
||||
import net.minecraftforge.event.world.ChunkDataEvent;
|
||||
|
||||
public class OilPopulate {
|
||||
|
||||
public static final Set<Integer> surfaceDepositBiomes = new HashSet<Integer>();
|
||||
public static final Set<Integer> excludedBiomes = new HashSet<Integer>();
|
||||
public static final OilPopulate INSTANCE = new OilPopulate();
|
||||
public final Set<Integer> surfaceDepositBiomes = new HashSet<Integer>();
|
||||
public final Set<Integer> excludedBiomes = new HashSet<Integer>();
|
||||
private static final String CHUNK_TAG = "buildcraft";
|
||||
private static final String SEED_TAG = "oilGenSeed";
|
||||
private static final String GROUND_TAG = "oilGenGroundLevel";
|
||||
// private static final String FINISHED_TAG = "oilGenFinished";
|
||||
private static final byte GEN_AREA = 2;
|
||||
private static final Map<Chunk, NBTTagCompound> chunkData = new HashMap<Chunk, NBTTagCompound>();
|
||||
private static EventType eventType = EnumHelper.addEnum(EventType.class, "BUILDCRAFT_OIL");
|
||||
private Chunk currentChunk;
|
||||
|
||||
static {
|
||||
private OilPopulate() {
|
||||
BuildCraftCore.debugMode = true;
|
||||
surfaceDepositBiomes.add(BiomeGenBase.desert.biomeID);
|
||||
surfaceDepositBiomes.add(BiomeGenBase.taiga.biomeID);
|
||||
|
||||
|
@ -36,23 +54,51 @@ public class OilPopulate {
|
|||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
public void populate(PopulateChunkEvent.Post event) {
|
||||
|
||||
boolean doGen = TerrainGen.populate(event.chunkProvider, event.world, event.rand, event.chunkX, event.chunkX, event.hasVillageGenerated, PopulateChunkEvent.Populate.EventType.CUSTOM);
|
||||
public void populate(PopulateChunkEvent.Populate event) {
|
||||
if (event.type != EventType.LAKE) {
|
||||
return;
|
||||
}
|
||||
boolean doGen = TerrainGen.populate(event.chunkProvider, event.world, event.rand, event.chunkX, event.chunkX, event.hasVillageGenerated, eventType);
|
||||
|
||||
if (!doGen) {
|
||||
return;
|
||||
}
|
||||
|
||||
// shift to world coordinates
|
||||
int worldX = event.chunkX << 4;
|
||||
int worldZ = event.chunkZ << 4;
|
||||
// if (event.chunkX == 17 && event.chunkZ == 19) {
|
||||
// System.out.println("tester");
|
||||
// }
|
||||
currentChunk = event.world.getChunkFromChunkCoords(event.chunkX, event.chunkZ);
|
||||
|
||||
doPopulate(event.world, event.rand, worldX, worldZ);
|
||||
for (int i = -GEN_AREA; i <= GEN_AREA; i++) {
|
||||
for (int k = -GEN_AREA; k <= GEN_AREA; k++) {
|
||||
int cx = event.chunkX + i;
|
||||
int cz = event.chunkZ + k;
|
||||
if (event.chunkProvider.chunkExists(cx, cz)) {
|
||||
// if (cx == 17 && cz == 20) {
|
||||
// System.out.println("source");
|
||||
// }
|
||||
Chunk chunk = event.world.getChunkFromChunkCoords(cx, cz);
|
||||
NBTTagCompound nbt = getChunkBuildcraftData(chunk);
|
||||
long seed;
|
||||
if (nbt.hasKey(SEED_TAG)) {
|
||||
seed = nbt.getLong(SEED_TAG);
|
||||
} else {
|
||||
seed = event.rand.nextLong();
|
||||
nbt.setLong(SEED_TAG, seed);
|
||||
}
|
||||
Random rand = new Random(seed);
|
||||
doPopulate(event.world, rand, chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void doPopulate(World world, Random rand, int x, int z) {
|
||||
BiomeGenBase biome = world.getBiomeGenForCoords(x + 16, z + 16);
|
||||
public void doPopulate(World world, Random rand, Chunk chunk) {
|
||||
// shift to world coordinates
|
||||
int x = chunk.xPosition * 16 + 8;
|
||||
int z = chunk.zPosition * 16 + 8;
|
||||
|
||||
BiomeGenBase biome = world.getBiomeGenForCoords(x + 8, z + 8);
|
||||
|
||||
// Do not generate oil in the End or Nether
|
||||
if (excludedBiomes.contains(biome.biomeID)) {
|
||||
|
@ -75,14 +121,15 @@ public class OilPopulate {
|
|||
boolean mediumDeposit = rand.nextDouble() <= 0.0015 * bonus; // 0.15%
|
||||
boolean largeDeposit = rand.nextDouble() <= 0.0005 * bonus; // 0.05%
|
||||
|
||||
if (BuildCraftCore.debugMode && x == 0 && z == 0) {
|
||||
largeDeposit = true;
|
||||
if (BuildCraftCore.debugMode) {
|
||||
largeDeposit = rand.nextDouble() < 0.01;
|
||||
}
|
||||
|
||||
// Generate a large cave deposit
|
||||
if (mediumDeposit || largeDeposit) {
|
||||
// Generate a large cave deposit
|
||||
// System.out.printf("Gen: %d, %d, %d\n", x, z, seed);
|
||||
|
||||
int baseX = x, baseZ = z;
|
||||
int wellX = x, wellZ = z;
|
||||
int wellY = 20 + rand.nextInt(10);
|
||||
int baseY;
|
||||
if (largeDeposit && BuildCraftEnergy.spawnOilSprings && (BuildCraftCore.debugMode || rand.nextDouble() <= 0.25)) {
|
||||
|
@ -107,116 +154,223 @@ public class OilPopulate {
|
|||
int distance = poolX * poolX + poolY * poolY + poolZ * poolZ;
|
||||
|
||||
if (distance <= radiusSq) {
|
||||
world.setBlock(poolX + baseX, poolY + wellY, poolZ + baseZ, BuildCraftEnergy.oilStill.blockID);
|
||||
setBlock(world, poolX + wellX, poolY + wellY, poolZ + wellZ, BuildCraftEnergy.oilStill.blockID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean started = false;
|
||||
|
||||
for (int y = world.getActualHeight(); y >= baseY; --y) {
|
||||
if (started) {
|
||||
int blockId = world.getBlockId(baseX, y, baseZ);
|
||||
if (blockId == Block.bedrock.blockID) {
|
||||
if (BuildCraftEnergy.spawnOilSprings) {
|
||||
world.setBlock(baseX, y, baseZ, BuildCraftCore.springBlock.blockID, 1, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
world.setBlock(baseX, y, baseZ, BuildCraftEnergy.oilStill.blockID);
|
||||
} else {
|
||||
int blockId = world.getBlockId(baseX, y, baseZ);
|
||||
Block block = Block.blocksList[blockId];
|
||||
if (blockId != 0 && !block.isLeaves(world, baseX, y, baseZ) && !block.isWood(world, baseX, y, baseZ)) {
|
||||
started = true;
|
||||
|
||||
if (largeDeposit) {
|
||||
generateSurfaceDeposit(world, rand, baseX, y, baseZ, 20 + rand.nextInt(20));
|
||||
} else if (mediumDeposit) {
|
||||
generateSurfaceDeposit(world, rand, baseX, y, baseZ, 5 + rand.nextInt(5));
|
||||
}
|
||||
|
||||
int wellHeight = 4;
|
||||
if (largeDeposit) {
|
||||
wellHeight = 16;
|
||||
}
|
||||
int ymax = Math.min(y + wellHeight, world.getActualHeight() - 1);
|
||||
|
||||
for (int h = y + 1; h <= ymax; ++h) {
|
||||
world.setBlock(baseX, h, baseZ, BuildCraftEnergy.oilStill.blockID);
|
||||
}
|
||||
|
||||
}
|
||||
int groundLevel = getGroundLevel(chunk);
|
||||
if (groundLevel <= 0) {
|
||||
groundLevel = getTopBlock(world, chunk, wellX, wellZ);
|
||||
setGroundLevel(chunk, groundLevel);
|
||||
}
|
||||
if (largeDeposit) {
|
||||
int lakeRadius = 20 + rand.nextInt(20);
|
||||
if (BuildCraftCore.debugMode) {
|
||||
lakeRadius += 40;
|
||||
}
|
||||
generateSurfaceDeposit(world, rand, wellX, groundLevel, wellZ, lakeRadius);
|
||||
} else if (mediumDeposit) {
|
||||
generateSurfaceDeposit(world, rand, wellX, groundLevel, wellZ, 5 + rand.nextInt(5));
|
||||
}
|
||||
|
||||
int wellHeight = 4;
|
||||
if (largeDeposit) {
|
||||
wellHeight = 16;
|
||||
}
|
||||
int maxHeight = Math.min(groundLevel + wellHeight, world.getActualHeight() - 1);
|
||||
|
||||
if (world.getBlockId(wellX, baseY, wellZ) == Block.bedrock.blockID) {
|
||||
if (BuildCraftEnergy.spawnOilSprings) {
|
||||
setBlock(world, wellX, baseY, wellZ, BuildCraftCore.springBlock.blockID, 1);
|
||||
}
|
||||
}
|
||||
for (int y = baseY + 1; y <= maxHeight; ++y) {
|
||||
setBlock(world, wellX, y, wellZ, BuildCraftEnergy.oilStill.blockID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateSurfaceDeposit(World world, Random rand, int x, int y, int z, int radius) {
|
||||
public void generateSurfaceDeposit(World world, Random rand, int x, int y, int z, int radius) {
|
||||
int depth = rand.nextDouble() < 0.5 ? 1 : 2;
|
||||
setOilWithProba(world, rand, 1, x, y, z, true, depth);
|
||||
|
||||
setOilForLake(world, x, y, z, depth);
|
||||
|
||||
for (int w = 1; w <= radius; ++w) {
|
||||
float proba = (float) (radius - w + 4) / (float) (radius + 4);
|
||||
|
||||
for (int d = -w; d <= w; ++d) {
|
||||
setOilWithProba(world, rand, proba, x + d, y, z + w, false, depth);
|
||||
setOilWithProba(world, rand, proba, x + d, y, z - w, false, depth);
|
||||
setOilWithProba(world, rand, proba, x + w, y, z + d, false, depth);
|
||||
setOilWithProba(world, rand, proba, x - w, y, z + d, false, depth);
|
||||
setOilWithProba(world, rand, proba, x + d, y, z + w, depth);
|
||||
setOilWithProba(world, rand, proba, x + d, y, z - w, depth);
|
||||
setOilWithProba(world, rand, proba, x + w, y, z + d, depth);
|
||||
setOilWithProba(world, rand, proba, x - w, y, z + d, depth);
|
||||
}
|
||||
}
|
||||
|
||||
for (int dx = x - radius; dx <= x + radius; ++dx) {
|
||||
for (int dz = z - radius; dz <= z + radius; ++dz) {
|
||||
|
||||
if (world.getBlockId(dx, y - 1, dz) != BuildCraftEnergy.oilStill.blockID) {
|
||||
if (isOil(world, dx + 1, y - 1, dz) && isOil(world, dx - 1, y - 1, dz) && isOil(world, dx, y - 1, dz + 1)
|
||||
&& isOil(world, dx, y - 1, dz - 1)) {
|
||||
setOilWithProba(world, rand, 1.0F, dx, y, dz, true, depth);
|
||||
}
|
||||
if (isOil(world, dx, y - 1, dz)) {
|
||||
continue;
|
||||
}
|
||||
if (isOilSurrounded(world, dx, y - 1, dz)) {
|
||||
setOilForLake(world, dx, y, dz, depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isOilOrWater(World world, int x, int y, int z) {
|
||||
private boolean isOilOrWater(World world, int x, int y, int z) {
|
||||
if (!world.blockExists(x, y, z)) {
|
||||
return false;
|
||||
}
|
||||
int blockId = world.getBlockId(x, y, z);
|
||||
return blockId == Block.waterMoving.blockID || blockId == Block.waterStill.blockID || blockId == BuildCraftEnergy.oilStill.blockID || blockId == BuildCraftEnergy.oilMoving.blockID;
|
||||
}
|
||||
|
||||
private static boolean isOil(World world, int x, int y, int z) {
|
||||
private boolean isOil(World world, int x, int y, int z) {
|
||||
if (!world.blockExists(x, y, z)) {
|
||||
return false;
|
||||
}
|
||||
int blockId = world.getBlockId(x, y, z);
|
||||
return (blockId == BuildCraftEnergy.oilStill.blockID || blockId == BuildCraftEnergy.oilMoving.blockID);
|
||||
}
|
||||
|
||||
public static void setOilWithProba(World world, Random rand, float proba, int x, int y, int z, boolean force, int depth) {
|
||||
if ((rand.nextFloat() <= proba && world.getBlockId(x, y - 2, z) != 0) || force) {
|
||||
boolean adjacentOil = false;
|
||||
private boolean isOilAdjacent(World world, int x, int y, int z) {
|
||||
for (int d = -1; d <= 1; ++d) {
|
||||
if (isOil(world, x + d, y, z) || isOil(world, x - d, y, z) || isOil(world, x, y, z + d) || isOil(world, x, y, z - d)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int d = -1; d <= 1; ++d) {
|
||||
if (isOil(world, x + d, y - 1, z) || isOil(world, x - d, y - 1, z) || isOil(world, x, y - 1, z + d) || isOil(world, x, y - 1, z - d)) {
|
||||
adjacentOil = true;
|
||||
}
|
||||
private boolean isOilSurrounded(World world, int x, int y, int z) {
|
||||
return isOil(world, x + 1, y, z)
|
||||
&& isOil(world, x - 1, y, z)
|
||||
&& isOil(world, x, y, z + 1)
|
||||
&& isOil(world, x, y, z - 1);
|
||||
}
|
||||
|
||||
private void setOilWithProba(World world, Random rand, float proba, int x, int y, int z, int depth) {
|
||||
if (!world.blockExists(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
if (rand.nextFloat() <= proba && world.getBlockId(x, y - 2, z) != 0) {
|
||||
if (isOilAdjacent(world, x, y - 1, z)) {
|
||||
setOilForLake(world, x, y, z, depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setOilForLake(World world, int x, int y, int z, int depth) {
|
||||
if (!world.blockExists(x, y, z)) {
|
||||
return;
|
||||
}
|
||||
if (world.isAirBlock(x, y + 1, z) || !world.isBlockOpaqueCube(x, y + 1, z) || Block.blocksList[world.getBlockId(x, y + 1, z)] instanceof BlockFlower) {
|
||||
world.setBlockToAir(x, y + 1, z);
|
||||
if (isOilOrWater(world, x, y, z)) {
|
||||
setBlock(world, x, y, z, BuildCraftEnergy.oilStill.blockID);
|
||||
} else {
|
||||
setBlock(world, x, y, z, 0, 0, 2);
|
||||
}
|
||||
|
||||
if (adjacentOil || force) {
|
||||
if (world.isAirBlock(x, y + 1, z) || !world.isBlockOpaqueCube(x, y + 1, z) || Block.blocksList[world.getBlockId(x, y + 1, z)] instanceof BlockFlower) {
|
||||
world.setBlockToAir(x, y + 1, z);
|
||||
if (isOilOrWater(world, x, y, z)) {
|
||||
world.setBlock(x, y, z, BuildCraftEnergy.oilStill.blockID);
|
||||
} else {
|
||||
world.setBlockToAir(x, y, z);
|
||||
}
|
||||
|
||||
for (int d = depth; d > 0; d--) {
|
||||
if (isOilOrWater(world, x, y - d - 1, z) || world.isBlockSolidOnSide(x, y - d - 1, z, ForgeDirection.UP)) {
|
||||
world.setBlock(x, y - d, z, BuildCraftEnergy.oilStill.blockID);
|
||||
}
|
||||
}
|
||||
for (int d = depth; d > 0; d--) {
|
||||
if (isOilOrWater(world, x, y - d - 1, z) || world.isBlockSolidOnSide(x, y - d - 1, z, ForgeDirection.UP)) {
|
||||
setBlock(world, x, y - d, z, BuildCraftEnergy.oilStill.blockID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
public void saveChunk(ChunkDataEvent.Save event) {
|
||||
NBTTagCompound nbt = chunkData.remove(event.getChunk());
|
||||
if (nbt != null && nbt.hasKey(CHUNK_TAG)) {
|
||||
event.getData().setTag(CHUNK_TAG, nbt.getTag(CHUNK_TAG));
|
||||
}
|
||||
}
|
||||
|
||||
@ForgeSubscribe
|
||||
public void loadChunk(ChunkDataEvent.Load event) {
|
||||
chunkData.put(event.getChunk(), event.getData());
|
||||
}
|
||||
|
||||
private NBTTagCompound getChunkBuildcraftData(Chunk chunk) {
|
||||
NBTTagCompound nbt = chunkData.get(chunk);
|
||||
if (nbt == null) {
|
||||
nbt = new NBTTagCompound();
|
||||
chunkData.put(chunk, nbt);
|
||||
}
|
||||
NBTTagCompound buildcraftData = nbt.getCompoundTag(CHUNK_TAG);
|
||||
if (!nbt.hasKey(CHUNK_TAG)) {
|
||||
nbt.setCompoundTag(CHUNK_TAG, buildcraftData);
|
||||
}
|
||||
return buildcraftData;
|
||||
}
|
||||
|
||||
private boolean canReplaceInChunk(World world, int chunkX, int chunkZ) {
|
||||
return currentChunk.isAtLocation(chunkX, chunkZ);
|
||||
// if (chunkX == 17 && chunkZ == 19) {
|
||||
// System.out.println("place");
|
||||
// }
|
||||
// Chunk chunk = world.getChunkFromChunkCoords(chunkX, chunkZ);
|
||||
// NBTTagCompound nbt = getChunkBuildcraftData(chunk);
|
||||
// return !nbt.getBoolean(FINISHED_TAG);
|
||||
}
|
||||
|
||||
// private void setFinished(Chunk chunk) {
|
||||
// NBTTagCompound nbt = getChunkBuildcraftData(chunk);
|
||||
// nbt.setBoolean(FINISHED_TAG, true);
|
||||
// }
|
||||
private void setGroundLevel(Chunk chunk, int height) {
|
||||
NBTTagCompound nbt = getChunkBuildcraftData(chunk);
|
||||
nbt.setInteger(GROUND_TAG, height);
|
||||
}
|
||||
|
||||
private int getGroundLevel(Chunk chunk) {
|
||||
NBTTagCompound nbt = getChunkBuildcraftData(chunk);
|
||||
return nbt.getInteger(GROUND_TAG);
|
||||
}
|
||||
|
||||
private int getTopBlock(World world, Chunk chunk, int x, int z) {
|
||||
int y = chunk.getTopFilledSegment() + 15;
|
||||
|
||||
int trimmedX = x & 15;
|
||||
int trimmedZ = z & 15;
|
||||
|
||||
for (; y > 0; --y) {
|
||||
int blockId = chunk.getBlockID(trimmedX, y, trimmedZ);
|
||||
Block block = Block.blocksList[blockId];
|
||||
if (blockId == 0 || block.blockMaterial == Material.leaves) {
|
||||
continue;
|
||||
}
|
||||
if (block instanceof BlockFlower) {
|
||||
continue;
|
||||
}
|
||||
if (Block.blocksList[blockId].isWood(world, x, y, z)) {
|
||||
continue;
|
||||
}
|
||||
if (Block.blocksList[blockId].isBlockFoliage(world, x, y, z)) {
|
||||
continue;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void setBlock(World world, int x, int y, int z, int blockId) {
|
||||
setBlock(world, x, y, z, blockId, 0, 3);
|
||||
}
|
||||
|
||||
private void setBlock(World world, int x, int y, int z, int blockId, int meta) {
|
||||
setBlock(world, x, y, z, blockId, meta, 3);
|
||||
}
|
||||
|
||||
private void setBlock(World world, int x, int y, int z, int blockId, int meta, int update) {
|
||||
if (canReplaceInChunk(world, x / 16, z / 16)) {
|
||||
world.setBlock(x, y, z, blockId, meta, update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue