Jump to content

Recommended Posts

Posted

So I want to make own version of this block that will have more dynamic behavior. I made and registered a campfire item and block the extend the vanilla classes and it all looks great, except the whole food aspect. When I right click a raw food item it does not appear on the campfire, it also does not pop off when cooked but stays raw. When you destroy the block, it'll drop the 4 raw food items. I tried copying in the vanilla Minecraft code for CampfireBlock and CampfireTileEntity instead of extending them, but to no avail. Please someone shed some light, thanks. 

Posted

Show your code please. Vanilla handles many trying based on instanceof or equality checks that don’t play well with mods.

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted
On 2/1/2020 at 4:20 AM, Cadiboo said:

Show your code please. Vanilla handles many trying based on instanceof or equality checks that don’t play well with mods.

package mymod;

import java.util.Optional;
import java.util.Random;

import javax.annotation.Nullable;

import net.minecraft.block.Block;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.ContainerBlock;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.AbstractArrowEntity;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CampfireCookingRecipe;
import net.minecraft.particles.BasicParticleType;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.pathfinding.PathType;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.DirectionProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.stats.Stats;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.DamageSource;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

public class Campfire extends ContainerBlock implements IWaterLoggable {
   protected static final VoxelShape SHAPE = Block.makeCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 7.0D, 16.0D);
   public static final BooleanProperty LIT = BlockStateProperties.LIT;
   public static final BooleanProperty SIGNAL_FIRE = BlockStateProperties.SIGNAL_FIRE;
   public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
   public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;

   public Campfire(Block.Properties p_i49989_1_) {
      super(p_i49989_1_);
      this.setDefaultState(this.stateContainer.getBaseState().with(LIT, Boolean.valueOf(true)).with(SIGNAL_FIRE, Boolean.valueOf(false)).with(WATERLOGGED, Boolean.valueOf(false)).with(FACING, Direction.NORTH));
   }

   public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) {
      if (state.get(LIT)) {
         TileEntity tileentity = worldIn.getTileEntity(pos);
         if (tileentity instanceof CampfireEntity) {
            CampfireEntity CampfireEntity = (CampfireEntity)tileentity;
            ItemStack itemstack = player.getHeldItem(handIn);
            Optional<CampfireCookingRecipe> optional = CampfireEntity.findMatchingRecipe(itemstack);
            if (optional.isPresent()) {
               if (!worldIn.isRemote && CampfireEntity.addItem(player.abilities.isCreativeMode ? itemstack.copy() : itemstack, optional.get().getCookTime())) {
                  player.addStat(Stats.INTERACT_WITH_CAMPFIRE);
               }

               return true;
            }
         }
      }

      return false;
   }

   public void onEntityCollision(BlockState state, World worldIn, BlockPos pos, Entity entityIn) {
      if (!entityIn.isImmuneToFire() && state.get(LIT) && entityIn instanceof LivingEntity && !EnchantmentHelper.hasFrostWalker((LivingEntity)entityIn)) {
         entityIn.attackEntityFrom(DamageSource.IN_FIRE, 1.0F);
      }

      super.onEntityCollision(state, worldIn, pos, entityIn);
   }

   public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
      if (state.getBlock() != newState.getBlock()) {
         TileEntity tileentity = worldIn.getTileEntity(pos);
         if (tileentity instanceof CampfireEntity) {
            InventoryHelper.dropItems(worldIn, pos, ((CampfireEntity)tileentity).getInventory());
         }

         super.onReplaced(state, worldIn, pos, newState, isMoving);
      }
   }

   @Nullable
   public BlockState getStateForPlacement(BlockItemUseContext context) {
      IWorld iworld = context.getWorld();
      BlockPos blockpos = context.getPos();
      boolean flag = iworld.getFluidState(blockpos).getFluid() == Fluids.WATER;
      return this.getDefaultState().with(WATERLOGGED, Boolean.valueOf(flag)).with(SIGNAL_FIRE, Boolean.valueOf(this.isHayBlock(iworld.getBlockState(blockpos.down())))).with(LIT, Boolean.valueOf(!flag)).with(FACING, context.getPlacementHorizontalFacing());
   }

   /**
    * Update the provided state given the provided neighbor facing and neighbor state, returning a new state.
    * For example, fences make their connections to the passed in state if possible, and wet concrete powder immediately
    * returns its solidified counterpart.
    * Note that this method should ideally consider only the specific face passed in.
    */
   public BlockState updatePostPlacement(BlockState stateIn, Direction facing, BlockState facingState, IWorld worldIn, BlockPos currentPos, BlockPos facingPos) {
      if (stateIn.get(WATERLOGGED)) {
         worldIn.getPendingFluidTicks().scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickRate(worldIn));
      }

      return facing == Direction.DOWN ? stateIn.with(SIGNAL_FIRE, Boolean.valueOf(this.isHayBlock(facingState))) : super.updatePostPlacement(stateIn, facing, facingState, worldIn, currentPos, facingPos);
   }

   /**
    * Returns true if the block of the passed blockstate is a Hay block, otherwise false.
    */
   private boolean isHayBlock(BlockState stateIn) {
      return stateIn.getBlock() == Blocks.HAY_BLOCK;
   }

   /**
    * Amount of light emitted
    * @deprecated prefer calling {@link IBlockState#getLightValue()}
    */
   public int getLightValue(BlockState state) {
      return state.get(LIT) ? super.getLightValue(state) : 0;
   }

   public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
      return SHAPE;
   }

   /**
    * The type of render function called. MODEL for mixed tesr and static model, MODELBLOCK_ANIMATED for TESR-only,
    * LIQUID for vanilla liquids, INVISIBLE to skip all rendering
    * @deprecated call via {@link IBlockState#getRenderType()} whenever possible. Implementing/overriding is fine.
    */
   public BlockRenderType getRenderType(BlockState state) {
      return BlockRenderType.MODEL;
   }

   /**
    * Gets the render layer this block will render on. SOLID for solid blocks, CUTOUT or CUTOUT_MIPPED for on-off
    * transparency (glass, reeds), TRANSLUCENT for fully blended transparency (stained glass)
    */
   public BlockRenderLayer getRenderLayer() {
      return BlockRenderLayer.CUTOUT;
   }

   /**
    * Called periodically clientside on blocks near the player to show effects (like furnace fire particles). Note that
    * this method is unrelated to {@link randomTick} and {@link #needsRandomTick}, and will always be called regardless
    * of whether the block can receive random update ticks
    */
   @OnlyIn(Dist.CLIENT)
   public void animateTick(BlockState stateIn, World worldIn, BlockPos pos, Random rand) {
      if (stateIn.get(LIT)) {
         if (rand.nextInt(10) == 0) {
            worldIn.playSound((double)((float)pos.getX() + 0.5F), (double)((float)pos.getY() + 0.5F), (double)((float)pos.getZ() + 0.5F), SoundEvents.BLOCK_CAMPFIRE_CRACKLE, SoundCategory.BLOCKS, 0.5F + rand.nextFloat(), rand.nextFloat() * 0.7F + 0.6F, false);
         }

         if (rand.nextInt(5) == 0) {
            for(int i = 0; i < rand.nextInt(1) + 1; ++i) {
               worldIn.addParticle(ParticleTypes.LAVA, (double)((float)pos.getX() + 0.5F), (double)((float)pos.getY() + 0.5F), (double)((float)pos.getZ() + 0.5F), (double)(rand.nextFloat() / 2.0F), 5.0E-5D, (double)(rand.nextFloat() / 2.0F));
            }
         }

      }
   }

   public boolean receiveFluid(IWorld worldIn, BlockPos pos, BlockState state, IFluidState fluidStateIn) {
      if (!state.get(BlockStateProperties.WATERLOGGED) && fluidStateIn.getFluid() == Fluids.WATER) {
         boolean flag = state.get(LIT);
         if (flag) {
            if (worldIn.isRemote()) {
               for(int i = 0; i < 20; ++i) {
                  func_220098_a(worldIn.getWorld(), pos, state.get(SIGNAL_FIRE), true);
               }
            } else {
               worldIn.playSound((PlayerEntity)null, pos, SoundEvents.ENTITY_GENERIC_EXTINGUISH_FIRE, SoundCategory.BLOCKS, 1.0F, 1.0F);
            }

            TileEntity tileentity = worldIn.getTileEntity(pos);
            if (tileentity instanceof CampfireEntity) {
               ((CampfireEntity)tileentity).func_213986_d();
            }
         }

         worldIn.setBlockState(pos, state.with(WATERLOGGED, Boolean.valueOf(true)).with(LIT, Boolean.valueOf(false)), 3);
         worldIn.getPendingFluidTicks().scheduleTick(pos, fluidStateIn.getFluid(), fluidStateIn.getFluid().getTickRate(worldIn));
         return true;
      } else {
         return false;
      }
   }

   public void onProjectileCollision(World worldIn, BlockState state, BlockRayTraceResult hit, Entity projectile) {
      if (!worldIn.isRemote && projectile instanceof AbstractArrowEntity) {
         AbstractArrowEntity abstractarrowentity = (AbstractArrowEntity)projectile;
         if (abstractarrowentity.isBurning() && !state.get(LIT) && !state.get(WATERLOGGED)) {
            BlockPos blockpos = hit.getPos();
            worldIn.setBlockState(blockpos, state.with(BlockStateProperties.LIT, Boolean.valueOf(true)), 11);
         }
      }

   }

   public static void func_220098_a(World p_220098_0_, BlockPos pos, boolean p_220098_2_, boolean p_220098_3_) {
      Random random = p_220098_0_.getRandom();
      BasicParticleType basicparticletype = p_220098_2_ ? ParticleTypes.CAMPFIRE_SIGNAL_SMOKE : ParticleTypes.CAMPFIRE_COSY_SMOKE;
      p_220098_0_.func_217404_b(basicparticletype, true, (double)pos.getX() + 0.5D + random.nextDouble() / 3.0D * (double)(random.nextBoolean() ? 1 : -1), (double)pos.getY() + random.nextDouble() + random.nextDouble(), (double)pos.getZ() + 0.5D + random.nextDouble() / 3.0D * (double)(random.nextBoolean() ? 1 : -1), 0.0D, 0.07D, 0.0D);
      if (p_220098_3_) {
         p_220098_0_.addParticle(ParticleTypes.SMOKE, (double)pos.getX() + 0.25D + random.nextDouble() / 2.0D * (double)(random.nextBoolean() ? 1 : -1), (double)pos.getY() + 0.4D, (double)pos.getZ() + 0.25D + random.nextDouble() / 2.0D * (double)(random.nextBoolean() ? 1 : -1), 0.0D, 0.005D, 0.0D);
      }

   }

   public IFluidState getFluidState(BlockState state) {
      return state.get(WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : super.getFluidState(state);
   }

   /**
    * Returns the blockstate with the given rotation from the passed blockstate. If inapplicable, returns the passed
    * blockstate.
    * @deprecated call via {@link IBlockState#withRotation(Rotation)} whenever possible. Implementing/overriding is
    * fine.
    */
   public BlockState rotate(BlockState state, Rotation rot) {
      return state.with(FACING, rot.rotate(state.get(FACING)));
   }

   /**
    * Returns the blockstate with the given mirror of the passed blockstate. If inapplicable, returns the passed
    * blockstate.
    * @deprecated call via {@link IBlockState#withMirror(Mirror)} whenever possible. Implementing/overriding is fine.
    */
   public BlockState mirror(BlockState state, Mirror mirrorIn) {
      return state.rotate(mirrorIn.toRotation(state.get(FACING)));
   }

   protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) {
      builder.add(LIT, SIGNAL_FIRE, WATERLOGGED, FACING);
   }

   public TileEntity createNewTileEntity(IBlockReader worldIn) {
      return new CampfireEntity();
   }

   public boolean allowsMovement(BlockState state, IBlockReader worldIn, BlockPos pos, PathType type) {
      return false;
   }
}

 

package mymod;

import java.util.Optional;
import java.util.Random;

import javax.annotation.Nullable;

import net.minecraft.inventory.IClearable;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.inventory.ItemStackHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CampfireCookingRecipe;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.play.server.SUpdateTileEntityPacket;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;

public class CampfireEntity extends TileEntity implements IClearable, ITickableTileEntity {
	   private final NonNullList<ItemStack> inventory = NonNullList.withSize(4, ItemStack.EMPTY);
	   private final int[] cookingTimes = new int[4];
	   private final int[] cookingTotalTimes = new int[4];

	   public CampfireEntity() {
	      super(TileEntityType.CAMPFIRE);
	   }

	   public void tick() {
	      boolean flag = this.getBlockState().get(Campfire.LIT);
	      boolean flag1 = this.world.isRemote;
	      if (flag1) {
	         if (flag) {
	            this.addParticles();
	         }

	      } else {
	         if (flag) {
	            this.cookAndDrop();
	         } else {
	            for(int i = 0; i < this.inventory.size(); ++i) {
	               if (this.cookingTimes[i] > 0) {
	                  this.cookingTimes[i] = MathHelper.clamp(this.cookingTimes[i] - 2, 0, this.cookingTotalTimes[i]);
	               }
	            }
	         }

	      }
	   }

	   /**
	    * Individually tracks the cooking of each item, then spawns the finished product in-world and clears the
	    * corresponding held item.
	    */
	   private void cookAndDrop() {
	      for(int i = 0; i < this.inventory.size(); ++i) {
	         ItemStack itemstack = this.inventory.get(i);
	         if (!itemstack.isEmpty()) {
	            ++this.cookingTimes[i];
	            if (this.cookingTimes[i] >= this.cookingTotalTimes[i]) {
	               IInventory iinventory = new Inventory(itemstack);
	               ItemStack itemstack1 = this.world.getRecipeManager().getRecipe(IRecipeType.CAMPFIRE_COOKING, iinventory, this.world).map((p_213979_1_) -> {
	                  return p_213979_1_.getCraftingResult(iinventory);
	               }).orElse(itemstack);
	               BlockPos blockpos = this.getPos();
	               InventoryHelper.spawnItemStack(this.world, (double)blockpos.getX(), (double)blockpos.getY(), (double)blockpos.getZ(), itemstack1);
	               this.inventory.set(i, ItemStack.EMPTY);
	               this.func_213981_s();
	            }
	         }
	      }

	   }

	   private void addParticles() {
	      World world = this.getWorld();
	      if (world != null) {
	         BlockPos blockpos = this.getPos();
	         Random random = world.rand;
	         if (random.nextFloat() < 0.11F) {
	            for(int i = 0; i < random.nextInt(2) + 2; ++i) {
	               Campfire.func_220098_a(world, blockpos, this.getBlockState().get(Campfire.SIGNAL_FIRE), false);
	            }
	         }

	         int l = this.getBlockState().get(Campfire.FACING).getHorizontalIndex();

	         for(int j = 0; j < this.inventory.size(); ++j) {
	            if (!this.inventory.get(j).isEmpty() && random.nextFloat() < 0.2F) {
	               Direction direction = Direction.byHorizontalIndex(Math.floorMod(j + l, 4));
	               float f = 0.3125F;
	               double d0 = (double)blockpos.getX() + 0.5D - (double)((float)direction.getXOffset() * 0.3125F) + (double)((float)direction.rotateY().getXOffset() * 0.3125F);
	               double d1 = (double)blockpos.getY() + 0.5D;
	               double d2 = (double)blockpos.getZ() + 0.5D - (double)((float)direction.getZOffset() * 0.3125F) + (double)((float)direction.rotateY().getZOffset() * 0.3125F);

	               for(int k = 0; k < 4; ++k) {
	                  world.addParticle(ParticleTypes.SMOKE, d0, d1, d2, 0.0D, 5.0E-4D, 0.0D);
	               }
	            }
	         }

	      }
	   }

	   /**
	    * Returns a NonNullList<ItemStack> of items currently held in the campfire.
	    */
	   public NonNullList<ItemStack> getInventory() {
	      return this.inventory;
	   }

	   public void read(CompoundNBT compound) {
	      super.read(compound);
	      this.inventory.clear();
	      ItemStackHelper.loadAllItems(compound, this.inventory);
	      if (compound.contains("CookingTimes", 11)) {
	         int[] aint = compound.getIntArray("CookingTimes");
	         System.arraycopy(aint, 0, this.cookingTimes, 0, Math.min(this.cookingTotalTimes.length, aint.length));
	      }

	      if (compound.contains("CookingTotalTimes", 11)) {
	         int[] aint1 = compound.getIntArray("CookingTotalTimes");
	         System.arraycopy(aint1, 0, this.cookingTotalTimes, 0, Math.min(this.cookingTotalTimes.length, aint1.length));
	      }

	   }

	   public CompoundNBT write(CompoundNBT compound) {
	      this.writeItems(compound);
	      compound.putIntArray("CookingTimes", this.cookingTimes);
	      compound.putIntArray("CookingTotalTimes", this.cookingTotalTimes);
	      return compound;
	   }

	   private CompoundNBT writeItems(CompoundNBT compound) {
	      super.write(compound);
	      ItemStackHelper.saveAllItems(compound, this.inventory, true);
	      return compound;
	   }

	   /**
	    * Retrieves packet to send to the client whenever this Tile Entity is resynced via World.notifyBlockUpdate. For
	    * modded TE's, this packet comes back to you clientside in {@link #onDataPacket}
	    */
	   @Nullable
	   public SUpdateTileEntityPacket getUpdatePacket() {
	      return new SUpdateTileEntityPacket(this.pos, 13, this.getUpdateTag());
	   }

	   /**
	    * Get an NBT compound to sync to the client with SPacketChunkData, used for initial loading of the chunk or when
	    * many blocks change at once. This compound comes back to you clientside in {@link handleUpdateTag}
	    */
	   public CompoundNBT getUpdateTag() {
	      return this.writeItems(new CompoundNBT());
	   }

	   public Optional<CampfireCookingRecipe> findMatchingRecipe(ItemStack itemStackIn) {
	      return this.inventory.stream().noneMatch(ItemStack::isEmpty) ? Optional.empty() : this.world.getRecipeManager().getRecipe(IRecipeType.CAMPFIRE_COOKING, new Inventory(itemStackIn), this.world);
	   }

	   public boolean addItem(ItemStack itemStackIn, int cookTime) {
	      for(int i = 0; i < this.inventory.size(); ++i) {
	         ItemStack itemstack = this.inventory.get(i);
	         if (itemstack.isEmpty()) {
	            this.cookingTotalTimes[i] = cookTime;
	            this.cookingTimes[i] = 0;
	            this.inventory.set(i, itemStackIn.split(1));
	            this.func_213981_s();
	            return true;
	         }
	      }

	      return false;
	   }

	   private void func_213981_s() {
	      this.markDirty();
	      this.getWorld().notifyBlockUpdate(this.getPos(), this.getBlockState(), this.getBlockState(), 3);
	   }

	   public void clear() {
	      this.inventory.clear();
	   }

	   public void func_213986_d() {
	      if (!this.getWorld().isRemote) {
	         InventoryHelper.dropItems(this.getWorld(), this.getPos(), this.getInventory());
	      }

	      this.func_213981_s();
	   }
}

 

 @SubscribeEvent
        public static void registerBlocks(final RegistryEvent.Register<Block> event) {
            
            event.getRegistry().registerAll( 
            	
            	BlockList.campfire = new Campfire(Block.Properties.create(Material.WOOD, MaterialColor.OBSIDIAN).hardnessAndResistance(2.0F).sound(SoundType.WOOD).lightValue(15).tickRandomly())
                	.setRegistryName(location("campfire2"))
            ); 	
        }

  @SubscribeEvent
        public static void registerItems(final RegistryEvent.Register<Item> event) {
        	
        	event.getRegistry().registerAll(

        		ItemList.campfire = new BlockItem(BlockList.campfire, new Item.Properties().group(ItemGroup.MISC)).setRegistryName(BlockList.campfire.getRegistryName())
        	);
        }

 

Posted

The vanilla code is a bit of a mess of legacy code and Forge compatibility hacks. Vanilla’s code was never meant to be extended by Modders. I would either extend the vanilla class and write all the necessary hacks to get stuff to work the way you want or write my own implementation that will be much cleaner and uses forges systems. You can see an example of the latter here 

  • Thanks 1

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.