added aura pulling and stuff

This commit is contained in:
Ellpeck 2018-10-14 14:27:18 +02:00
parent 2be1a57e7a
commit 9901eaa786
23 changed files with 582 additions and 19 deletions

View file

@ -0,0 +1,26 @@
package de.ellpeck.naturesaura;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.List;
public final class Helper {
public static List<TileEntity> getTileEntitiesInArea(World world, BlockPos pos, int radius) {
List<TileEntity> tiles = new ArrayList<>();
for (int x = (pos.getX() - radius) >> 4; x <= (pos.getX() + radius) >> 4; x++) {
for (int z = (pos.getZ() - radius) >> 4; z <= (pos.getZ() + radius) >> 4; z++) {
for (TileEntity tile : world.getChunk(x, z).getTileEntityMap().values()) {
if (tile.getPos().distanceSq(pos) <= radius * radius) {
tiles.add(tile);
}
}
}
}
return tiles;
}
}

View file

@ -1,6 +1,7 @@
package de.ellpeck.naturesaura;
import de.ellpeck.naturesaura.blocks.ModBlocks;
import de.ellpeck.naturesaura.packet.PacketHandler;
import de.ellpeck.naturesaura.proxy.IProxy;
import de.ellpeck.naturesaura.reg.ModRegistry;
import net.minecraft.creativetab.CreativeTabs;
@ -38,6 +39,7 @@ public final class NaturesAura {
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
new ModBlocks();
PacketHandler.init();
ModRegistry.preInit(event);
proxy.preInit(event);
}

View file

@ -0,0 +1,54 @@
package de.ellpeck.naturesaura.aura;
import net.minecraft.nbt.NBTTagCompound;
public class BasicAuraContainer implements IAuraContainer {
protected final int maxAura;
protected int aura;
public BasicAuraContainer(int maxAura) {
this.maxAura = maxAura;
}
@Override
public int storeAura(int amountToStore, boolean simulate) {
int actual = Math.min(amountToStore, this.maxAura - this.aura);
if (!simulate) {
this.aura += actual;
}
return actual;
}
@Override
public int drainAura(int amountToDrain, boolean simulate) {
int actual = Math.min(amountToDrain, this.aura);
if (!simulate) {
this.aura -= actual;
}
return actual;
}
@Override
public int getStoredAura() {
return this.aura;
}
@Override
public int getMaxAura() {
return this.maxAura;
}
@Override
public int getAuraColor() {
return 0x00FF00;
}
public void writeNBT(NBTTagCompound compound) {
compound.setInteger("aura", this.aura);
}
public void readNBT(NBTTagCompound compound) {
this.aura = compound.getInteger("aura");
}
}

View file

@ -0,0 +1,14 @@
package de.ellpeck.naturesaura.aura;
public class FiniteAuraContainer extends BasicAuraContainer {
public FiniteAuraContainer(int aura) {
super(aura);
this.aura = aura;
}
@Override
public int storeAura(int amountToStore, boolean simulate) {
return 0;
}
}

View file

@ -0,0 +1,13 @@
package de.ellpeck.naturesaura.aura;
public interface IAuraContainer {
int storeAura(int amountToStore, boolean simulate);
int drainAura(int amountToDrain, boolean simulate);
int getStoredAura();
int getMaxAura();
int getAuraColor();
}

View file

@ -0,0 +1,6 @@
package de.ellpeck.naturesaura.aura;
public interface IAuraContainerProvider {
IAuraContainer container();
}

View file

@ -115,7 +115,7 @@ public class BlockAncientLeaves extends BlockLeaves implements
@Nullable
@Override
public TileEntity createNewTileEntity(World worldIn, int meta) {
return new TileEntityAncientLeaves();
return (meta & 2) != 0 ? new TileEntityAncientLeaves() : null;
}
@Override
@ -140,7 +140,7 @@ public class BlockAncientLeaves extends BlockLeaves implements
0F, 0F, 0F, 0xc46df9,
rand.nextFloat() * 2F + 0.5F,
rand.nextInt(100) + 150,
rand.nextFloat() * 0.05F + 0.005F, true);
rand.nextFloat() * 0.05F + 0.005F, true, true);
}
}

View file

@ -0,0 +1,32 @@
package de.ellpeck.naturesaura.blocks;
import de.ellpeck.naturesaura.blocks.tiles.TileEntityNatureAltar;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
public class BlockNatureAltar extends BlockContainerImpl {
private static final AxisAlignedBB BOUND_BOX = new AxisAlignedBB(0F, 0F, 0F, 1F, 12 / 16F, 1F);
public BlockNatureAltar() {
super(Material.ROCK, "nature_altar", TileEntityNatureAltar.class, "nature_altar");
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
return BOUND_BOX;
}
@Override
public boolean isFullCube(IBlockState state) {
return false;
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
}

View file

@ -10,4 +10,5 @@ public final class ModBlocks {
public static final Block ANCIENT_BARK = new BlockImpl("ancient_bark", Material.WOOD).setSoundType(SoundType.WOOD).setHardness(2F);
public static final Block ANCIENT_LEAVES = new BlockAncientLeaves();
public static final Block ANCIENT_SAPLING = new BlockAncientSapling();
public static final Block NATURE_ALTAR = new BlockNatureAltar();
}

View file

@ -1,4 +1,33 @@
package de.ellpeck.naturesaura.blocks.tiles;
public class TileEntityAncientLeaves extends TileEntityImpl {
import de.ellpeck.naturesaura.aura.FiniteAuraContainer;
import de.ellpeck.naturesaura.aura.IAuraContainer;
import de.ellpeck.naturesaura.aura.IAuraContainerProvider;
import net.minecraft.nbt.NBTTagCompound;
public class TileEntityAncientLeaves extends TileEntityImpl implements IAuraContainerProvider {
private final FiniteAuraContainer container = new FiniteAuraContainer(50) {
@Override
public int getAuraColor() {
return 0xc46df9;
}
};
@Override
public IAuraContainer container() {
return this.container;
}
@Override
public void writeNBT(NBTTagCompound compound, boolean syncing) {
super.writeNBT(compound, syncing);
this.container.writeNBT(compound);
}
@Override
public void readNBT(NBTTagCompound compound, boolean syncing) {
super.readNBT(compound, syncing);
this.container.readNBT(compound);
}
}

View file

@ -20,21 +20,20 @@ public class TileEntityImpl extends TileEntity {
@Override
public NBTTagCompound writeToNBT(NBTTagCompound compound) {
this.writeNBT(compound, false);
return super.writeToNBT(compound);
return compound;
}
@Override
public void readFromNBT(NBTTagCompound compound) {
this.readNBT(compound, false);
super.readFromNBT(compound);
}
public void writeNBT(NBTTagCompound compound, boolean syncing) {
super.writeToNBT(compound);
}
public void readNBT(NBTTagCompound compound, boolean syncing) {
super.readFromNBT(compound);
}
@Override

View file

@ -0,0 +1,202 @@
package de.ellpeck.naturesaura.blocks.tiles;
import de.ellpeck.naturesaura.Helper;
import de.ellpeck.naturesaura.NaturesAura;
import de.ellpeck.naturesaura.aura.BasicAuraContainer;
import de.ellpeck.naturesaura.aura.IAuraContainer;
import de.ellpeck.naturesaura.aura.IAuraContainerProvider;
import de.ellpeck.naturesaura.packet.PacketHandler;
import de.ellpeck.naturesaura.packet.PacketParticles;
import net.minecraft.block.BlockStoneBrick;
import net.minecraft.block.BlockStoneBrick.EnumType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.BlockPos;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class TileEntityNatureAltar extends TileEntityImpl implements ITickable, IAuraContainerProvider {
private static final BlockPos[] BRICK_POSITIONS = new BlockPos[]{
new BlockPos(-2, -1, 0),
new BlockPos(-3, -1, 0),
new BlockPos(-4, 0, 0),
new BlockPos(-4, 1, 0),
new BlockPos(2, -1, 0),
new BlockPos(3, -1, 0),
new BlockPos(4, 0, 0),
new BlockPos(4, 1, 0),
new BlockPos(0, -1, -2),
new BlockPos(0, -1, -3),
new BlockPos(0, 0, -4),
new BlockPos(0, 1, -4),
new BlockPos(0, -1, 2),
new BlockPos(0, -1, 3),
new BlockPos(0, 0, 4),
new BlockPos(0, 1, 4)
};
private static final BlockPos[] MOSSY_POSITIONS = new BlockPos[]{
new BlockPos(-4, 2, 0),
new BlockPos(4, 2, 0),
new BlockPos(0, 2, -4),
new BlockPos(0, 2, 4),
new BlockPos(-2, 0, -2),
new BlockPos(2, 0, -2),
new BlockPos(2, 0, 2),
new BlockPos(-2, 0, 2)
};
private static final BlockPos[] CHISELED_POSITIONS = new BlockPos[]{
new BlockPos(0, -1, 0),
new BlockPos(1, -1, 1),
new BlockPos(-1, -1, 1),
new BlockPos(-1, -1, -1),
new BlockPos(1, -1, -1)
};
private static final BlockPos[] GRASS_POSITIONS = new BlockPos[]{
new BlockPos(-1, -1, 0),
new BlockPos(1, -1, 0),
new BlockPos(0, -1, -1),
new BlockPos(0, -1, 1),
new BlockPos(-2, -1, -1),
new BlockPos(-3, -1, -1),
new BlockPos(-2, -1, 1),
new BlockPos(-3, -1, 1),
new BlockPos(2, -1, -1),
new BlockPos(3, -1, -1),
new BlockPos(2, -1, 1),
new BlockPos(3, -1, 1),
new BlockPos(-1, -1, -2),
new BlockPos(-1, -1, -3),
new BlockPos(1, -1, -2),
new BlockPos(1, -1, -3),
new BlockPos(-1, -1, 2),
new BlockPos(-1, -1, 3),
new BlockPos(1, -1, 2),
new BlockPos(1, -1, 3),
};
private final List<WeakReference<IAuraContainerProvider>> cachedProviders = new ArrayList<>();
private final BasicAuraContainer container = new BasicAuraContainer(5000);
public boolean structureFine;
private int lastAura;
@Override
public void update() {
Random rand = this.world.rand;
if (!this.world.isRemote) {
if (this.world.getTotalWorldTime() % 40 == 0) {
boolean fine = this.check(BRICK_POSITIONS, Blocks.STONEBRICK.getDefaultState())
&& this.check(MOSSY_POSITIONS, Blocks.STONEBRICK.getDefaultState().withProperty(BlockStoneBrick.VARIANT, EnumType.MOSSY))
&& this.check(CHISELED_POSITIONS, Blocks.STONEBRICK.getDefaultState().withProperty(BlockStoneBrick.VARIANT, EnumType.CHISELED))
&& this.check(GRASS_POSITIONS, Blocks.GRASS.getDefaultState());
if (fine != this.structureFine) {
this.structureFine = fine;
this.sendToClients();
}
}
if (this.structureFine) {
if (this.world.getTotalWorldTime() % 100 == 0) {
this.cachedProviders.clear();
for (TileEntity tile : Helper.getTileEntitiesInArea(this.world, this.pos, 15)) {
if (tile instanceof IAuraContainerProvider && tile != this) {
this.cachedProviders.add(new WeakReference<>((IAuraContainerProvider) tile));
}
}
}
if (!this.cachedProviders.isEmpty()) {
IAuraContainerProvider provider = this.cachedProviders.get(rand.nextInt(this.cachedProviders.size())).get();
if (provider != null) {
int stored = this.container.storeAura(provider.container().drainAura(5, true), false);
if (stored > 0) {
provider.container().drainAura(stored, false);
BlockPos pos = ((TileEntity) provider).getPos();
PacketHandler.sendToAllLoaded(this.world, this.pos, new PacketParticles(
pos.getX() + 0.5F, pos.getY() + 0.5F, pos.getZ() + 0.5F,
this.pos.getX() + 0.5F, this.pos.getY() + 0.5F, this.pos.getZ() + 0.5F,
rand.nextFloat() * 0.05F + 0.05F, provider.container().getAuraColor(), rand.nextFloat() * 1F + 1F
));
}
}
}
}
if (this.world.getTotalWorldTime() % 10 == 0 && this.lastAura != this.container.getStoredAura()) {
this.lastAura = this.container.getStoredAura();
this.sendToClients();
}
} else {
if (this.structureFine) {
if (rand.nextFloat() >= 0.7F) {
int fourths = this.container.getMaxAura() / 4;
if (this.container.getStoredAura() > 0) {
NaturesAura.proxy.spawnMagicParticle(this.world,
this.pos.getX() - 4F + rand.nextFloat(), this.pos.getY() + 3F, this.pos.getZ() + rand.nextFloat(),
0F, 0F, 0F, this.container.getAuraColor(), rand.nextFloat() * 3F + 1F, rand.nextInt(200) + 100, -0.025F, true, true);
}
if (this.container.getStoredAura() >= fourths) {
NaturesAura.proxy.spawnMagicParticle(this.world,
this.pos.getX() + 4F + rand.nextFloat(), this.pos.getY() + 3F, this.pos.getZ() + rand.nextFloat(),
0F, 0F, 0F, this.container.getAuraColor(), rand.nextFloat() * 3F + 1F, rand.nextInt(200) + 100, -0.025F, true, true);
}
if (this.container.getStoredAura() >= fourths * 2) {
NaturesAura.proxy.spawnMagicParticle(this.world,
this.pos.getX() + rand.nextFloat(), this.pos.getY() + 3F, this.pos.getZ() - 4F + rand.nextFloat(),
0F, 0F, 0F, this.container.getAuraColor(), rand.nextFloat() * 3F + 1F, rand.nextInt(200) + 100, -0.025F, true, true);
}
if (this.container.getStoredAura() >= fourths * 3) {
NaturesAura.proxy.spawnMagicParticle(this.world,
this.pos.getX() + rand.nextFloat(), this.pos.getY() + 3F, this.pos.getZ() + 4F + rand.nextFloat(),
0F, 0F, 0F, this.container.getAuraColor(), rand.nextFloat() * 3F + 1F, rand.nextInt(200) + 100, -0.025F, true, true);
}
}
}
}
}
private boolean check(BlockPos[] positions, IBlockState state) {
for (BlockPos offset : positions) {
if (this.world.getBlockState(this.pos.add(offset)) != state) {
return false;
}
}
return true;
}
@Override
public void writeNBT(NBTTagCompound compound, boolean syncing) {
super.writeNBT(compound, syncing);
compound.setBoolean("fine", this.structureFine);
this.container.writeNBT(compound);
}
@Override
public void readNBT(NBTTagCompound compound, boolean syncing) {
super.readNBT(compound, syncing);
this.structureFine = compound.getBoolean("fine");
this.container.readNBT(compound);
}
@Override
public IAuraContainer container() {
return this.container;
}
}

View file

@ -0,0 +1,24 @@
package de.ellpeck.naturesaura.packet;
import de.ellpeck.naturesaura.NaturesAura;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.relauncher.Side;
public final class PacketHandler {
private static SimpleNetworkWrapper network;
public static void init() {
network = new SimpleNetworkWrapper(NaturesAura.MOD_ID);
network.registerMessage(PacketParticles.Handler.class, PacketParticles.class, 0, Side.CLIENT);
}
public static void sendToAllLoaded(World world, BlockPos pos, IMessage message) {
network.sendToAllTracking(message, new NetworkRegistry.TargetPoint(world.provider.getDimension(), pos.getX(), pos.getY(), pos.getZ(), 0));
}
}

View file

@ -0,0 +1,91 @@
package de.ellpeck.naturesaura.packet;
import de.ellpeck.naturesaura.NaturesAura;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.util.vector.Vector3f;
public class PacketParticles implements IMessage {
private float startX;
private float startY;
private float startZ;
private float endX;
private float endY;
private float endZ;
private float speed;
private int color;
private float scale;
public PacketParticles(float startX, float startY, float startZ, float endX, float endY, float endZ, float speed, int color, float scale) {
this.startX = startX;
this.startY = startY;
this.startZ = startZ;
this.endX = endX;
this.endY = endY;
this.endZ = endZ;
this.speed = speed;
this.color = color;
this.scale = scale;
}
public PacketParticles() {
}
@Override
public void fromBytes(ByteBuf buf) {
this.startX = buf.readFloat();
this.startY = buf.readFloat();
this.startZ = buf.readFloat();
this.endX = buf.readFloat();
this.endY = buf.readFloat();
this.endZ = buf.readFloat();
this.speed = buf.readFloat();
this.color = buf.readInt();
this.scale = buf.readFloat();
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeFloat(this.startX);
buf.writeFloat(this.startY);
buf.writeFloat(this.startZ);
buf.writeFloat(this.endX);
buf.writeFloat(this.endY);
buf.writeFloat(this.endZ);
buf.writeFloat(this.speed);
buf.writeInt(this.color);
buf.writeFloat(this.scale);
}
public static class Handler implements IMessageHandler<PacketParticles, IMessage> {
@Override
@SideOnly(Side.CLIENT)
public IMessage onMessage(PacketParticles message, MessageContext ctx) {
NaturesAura.proxy.scheduleTask(() -> {
Vector3f dir = new Vector3f(
message.endX - message.startX,
message.endY - message.startY,
message.endZ - message.startZ);
int maxAge = (int) (dir.length() / message.speed);
dir.normalise();
NaturesAura.proxy.spawnMagicParticle(Minecraft.getMinecraft().world,
message.startX, message.startY, message.startZ,
dir.x * message.speed, dir.y * message.speed, dir.z * message.speed,
message.color, message.scale, maxAge, 0F, false, false);
});
return null;
}
}
}

View file

@ -15,13 +15,15 @@ public class ParticleMagic extends Particle {
public static final ResourceLocation TEXTURE = new ResourceLocation(NaturesAura.MOD_ID, "particles/magic_round");
private final float desiredScale;
private final boolean fade;
public ParticleMagic(World world, double posX, double posY, double posZ, double motionX, double motionY, double motionZ, int color, float scale, int maxAge, float gravity, boolean collision) {
public ParticleMagic(World world, double posX, double posY, double posZ, double motionX, double motionY, double motionZ, int color, float scale, int maxAge, float gravity, boolean collision, boolean fade) {
super(world, posX, posY, posZ);
this.desiredScale = scale;
this.particleMaxAge = maxAge;
this.canCollide = collision;
this.particleGravity = gravity;
this.fade = fade;
this.motionX = motionX;
this.motionY = motionY;
@ -32,17 +34,29 @@ public class ParticleMagic extends Particle {
TextureMap map = Minecraft.getMinecraft().getTextureMapBlocks();
this.setParticleTexture(map.getAtlasSprite(TEXTURE.toString()));
this.particleAlpha = 0F;
this.particleScale = 0F;
this.particleAlpha = 0.75F;
this.particleScale = this.desiredScale;
}
@Override
public void onUpdate() {
super.onUpdate();
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
float lifeRatio = (float) this.particleAge / (float) this.particleMaxAge;
this.particleAlpha = 0.75F - (lifeRatio * 0.75F);
this.particleScale = this.desiredScale - (this.desiredScale * lifeRatio);
this.particleAge++;
if (this.particleAge >= this.particleMaxAge) {
this.setExpired();
} else {
this.motionY -= 0.04D * (double) this.particleGravity;
this.move(this.motionX, this.motionY, this.motionZ);
if (this.fade) {
float lifeRatio = (float) this.particleAge / (float) this.particleMaxAge;
this.particleAlpha = 0.75F - (lifeRatio * 0.75F);
this.particleScale = this.desiredScale - (this.desiredScale * lifeRatio);
}
}
}
@Override

View file

@ -62,8 +62,8 @@ public class ClientProxy implements IProxy {
}
@Override
public void spawnMagicParticle(World world, double posX, double posY, double posZ, double motionX, double motionY, double motionZ, int color, float scale, int maxAge, float gravity, boolean collision) {
ParticleMagic particle = new ParticleMagic(world, posX, posY, posZ, motionX, motionY, motionZ, color, scale, maxAge, gravity, collision);
public void spawnMagicParticle(World world, double posX, double posY, double posZ, double motionX, double motionY, double motionZ, int color, float scale, int maxAge, float gravity, boolean collision, boolean fade) {
ParticleMagic particle = new ParticleMagic(world, posX, posY, posZ, motionX, motionY, motionZ, color, scale, maxAge, gravity, collision, fade);
ParticleHandler.spawnParticle(particle, posX, posY, posZ, 32);
}

View file

@ -22,7 +22,7 @@ public interface IProxy {
void addColorProvidingBlock(IColorProvidingBlock block);
void spawnMagicParticle(World world, double posX, double posY, double posZ, double motionX, double motionY, double motionZ, int color, float scale, int maxAge, float gravity, boolean collision);
void spawnMagicParticle(World world, double posX, double posY, double posZ, double motionX, double motionY, double motionZ, int color, float scale, int maxAge, float gravity, boolean collision, boolean fade);
void scheduleTask(Runnable runnable);
}

View file

@ -43,7 +43,7 @@ public class ServerProxy implements IProxy {
}
@Override
public void spawnMagicParticle(World world, double posX, double posY, double posZ, double motionX, double motionY, double motionZ, int color, float scale, int maxAge, float gravity, boolean collision) {
public void spawnMagicParticle(World world, double posX, double posY, double posZ, double motionX, double motionY, double motionZ, int color, float scale, int maxAge, float gravity, boolean collision, boolean fade) {
}

View file

@ -0,0 +1,16 @@
{
"forge_marker": 1,
"defaults": {
"model": "naturesaura:nature_altar",
"textures": {
"texture": "naturesaura:blocks/nature_altar",
"top": "naturesaura:blocks/nature_altar_top",
"particle": "#top"
},
"transform": "forge:default-block"
},
"variants": {
"normal": [{}],
"inventory": [{}]
}
}

View file

@ -3,4 +3,5 @@ itemGroup.naturesaura=Nature's Aura
tile.naturesaura.ancient_log.name=Ancient Log
tile.naturesaura.ancient_bark.name=Ancient Bark
tile.naturesaura.ancient_leaves.name=Ancient Leaves
tile.naturesaura.ancient_sapling.name=Ancient Sapling
tile.naturesaura.ancient_sapling.name=Ancient Sapling
tile.naturesaura.nature_altar.name=Natural Altar

View file

@ -0,0 +1,39 @@
{
"elements": [
{
"from": [0, 0, 0],
"to": [16, 12, 16],
"faces": {
"down": {
"uv": [0, 0, 16, 16],
"texture": "#top",
"cullface": "down"
},
"up": {
"uv": [0, 0, 16, 16],
"texture": "#top"
},
"north": {
"uv": [0, 4, 16, 16],
"texture": "#texture",
"cullface": "north"
},
"south": {
"uv": [0, 4, 16, 16],
"texture": "#texture",
"cullface": "south"
},
"west": {
"uv": [0, 4, 16, 16],
"texture": "#texture",
"cullface": "west"
},
"east": {
"uv": [0, 4, 16, 16],
"texture": "#texture",
"cullface": "east"
}
}
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B