Jump to content

[1.11.2] [Unsolved] Accessing an entity's gui container


OrangeVillager61

Recommended Posts

Hello! I don't know how to access my mob's container with my gui. I want my button on this gui to fire a series of functions if there are enough emeralds in the gui slot. I do not know to access the slots to check this.

 

Container:

public class ContainerIvVillagerHireNitwit extends Container{

	private IvVillager villager;
	private IItemHandler handler = villager.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
	
	public ContainerIvVillagerHireNitwit(IvVillager villager, IInventory playerInv){
		IItemHandler handler = villager.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);

		this.addSlotToContainer(new SlotItemHandler(handler, 3, 76, 47));
		int xPos = 8;
		int yPos = 84;
		
		for (int y = 0; y < 3; ++y) {
			for (int x = 0; x < 9; ++x) {
				this.addSlotToContainer(new Slot(playerInv, x + y * 9 + 9, xPos + x * 18, yPos + y * 18));
			}
		}
				
		for (int x = 0; x < 9; ++x) {
			this.addSlotToContainer(new Slot(playerInv, x, xPos + x * 18, yPos + 58));
		}
	}
	@Override
	public boolean canInteractWith(EntityPlayer player) {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public ItemStack transferStackInSlot(EntityPlayer playerIn, int fromSlot) {
	    ItemStack previous = ItemStack.EMPTY;
	    Slot slot = (Slot) this.inventorySlots.get(fromSlot);

	    if (slot != null && slot.getHasStack()) {
	        ItemStack current = slot.getStack();
	        previous = current.copy();

	        if (fromSlot < this.handler.getSlots()) {
	            // From the block breaker inventory to player's inventory
	            if (!this.mergeItemStack(current, handler.getSlots(), handler.getSlots() + 36, true))
	                return ItemStack.EMPTY;
	        } else {
	            // From the player's inventory to block breaker's inventory
	            if (!this.mergeItemStack(current, 0, handler.getSlots(), false))
	                return ItemStack.EMPTY;
	        }

	        if (current.getCount() == 0) //Use func_190916_E() instead of stackSize 1.11 only 1.11.2 use getCount()
	            slot.putStack(ItemStack.EMPTY); //Use ItemStack.field_190927_a instead of (ItemStack)null for a blank item stack. In 1.11.2 use ItemStack.EMPTY
	        else
	            slot.onSlotChanged();

	        if (current.getCount() == previous.getCount())
	            return null;
	        slot.onTake(playerIn, current);
	    }
	    return previous;
	}
}

 

GUI

public class GuiIvVillagerHireNitwit extends GuiContainer{

	private IvVillager villager;
	private IInventory playerInv;
	
	public GuiIvVillagerHireNitwit(IvVillager villager, IInventory playerInv) {
		super(new ContainerIvVillagerHireNitwit(villager, playerInv));
		
		this.xSize = 176;
		this.ySize = 166;
		
		this.villager = villager;
		this.playerInv = playerInv;
	}

	@Override
	protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
		GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
		this.mc.getTextureManager().bindTexture(new ResourceLocation(Reference.MOD_ID, "gui/hire_nitwit.png"));
		this.drawTexturedModalRect(this.getGuiLeft(), this.getGuiTop(), 0, 0, this.xSize, this.ySize);
	}
	
	@Override
	protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY)
    {
        String s = this.villager.getName();
        Boolean has_emeralds;
        this.mc.fontRenderer.drawString(s, this.xSize / 2 - this.mc.fontRenderer.getStringWidth(s) / 2, 6, 4210752);
        this.mc.fontRenderer.drawString(this.playerInv.getDisplayName().getFormattedText(), 8, 72, 4210752);
        if (){ //this is where the container needs to be accessed
        	has_emeralds = true;
        }
        else 
        {
        	has_emeralds = false;
        }
        this.addButton(new Button_Hire(0, 115, 20, 40, 25, "Hire", this.villager, has_emeralds));
    }

}

As well, does addSlotToContainer id need to be different across containers? 

Edited by OrangeVillager61
Link to comment
Share on other sites

The GuiContainer#inventorySlots field stores the Container that you pass to the GuiContainer constructor. You could have found this out for yourself by looking at the GuiContainer class in your IDE.

 

Slot IDs only have to be unique within the Container instance. Two different Container instances can each have their own Slot instance with ID 1.

  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

20 minutes ago, Choonster said:

The GuiContainer#inventorySlots field stores the Container that you pass to the GuiContainer constructor. You could have found this out for yourself by looking at the GuiContainer class in your IDE.

 

Slot IDs only have to be unique within the Container instance. Two different Container instances can each have their own Slot instance with ID 1.

Okay, thanks, however, when I compare the slot.getStack and the new ItemStack I want with a standard >=, it is undefined and I cannot seem to find an alternative.

Link to comment
Share on other sites

7 minutes ago, OrangeVillager61 said:

Okay, thanks, however, when I compare the slot.getStack and the new ItemStack I want with a standard >=, it is undefined and I cannot seem to find an alternative.

>= compares numbers, you can't compare ItemStacks with it.

  • Like 1
Link to comment
Share on other sites

2 minutes ago, OrangeVillager61 said:

Okay, thanks, however, when I compare the slot.getStack and the new ItemStack I want with a standard >=, it is undefined and I cannot seem to find an alternative.

 

Java doesn't allow operator overloading, so you can't use relational operators like >= to compare non-numeric values.

 

Use the static equality methods in the ItemStack class to check if two ItemStacks are equal or use the getter methods to get each part of the ItemStack (e.g. ItemStack#getItem to get the ItemItemStack#getCount to get the count/stack size).

 

 

  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Alright, when I try to test the GUI I get errors that arrays cannot be cast to IvVillager on the line below.

return new ContainerIvVillagerHauler((IvVillager) world.getEntitiesWithinAABB(IvVillager.class, vilSearch), player.inventory);

Since I require an IvVillager as an argument, how can I get the IvVillager and select it?

Link to comment
Share on other sites

23 minutes ago, OrangeVillager61 said:

Alright, when I try to test the GUI I get errors that arrays cannot be cast to IvVillager on the line below.


return new ContainerIvVillagerHauler((IvVillager) world.getEntitiesWithinAABB(IvVillager.class, vilSearch), player.inventory);

Since I require an IvVillager as an argument, how can I get the IvVillager and select it?

 

World#getEntitiesWithinAABB returns a List<T>, where T is the class you pass as the first argument or any super class up to Entity. You can't cast a List<T> to T, you need to get an individual element from the list.

 

This is basic Java knowledge.

Edited by Choonster
  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Ah, okay, however, whenever I call the UI, it can't find anything so the list is empty. I think it is my AxisAlignedBB since I'm not sure if I specified the right area.

 

Where the error occurs:

@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
		AxisAlignedBB vilSearch = new AxisAlignedBB(x, y - 1.0D, z, x, y + 2.0D, z);
		if (ID == Villager_Hire){
			return new ContainerIvVillagerHireNitwit((IvVillager)world.getEntitiesWithinAABB(IvVillager.class, vilSearch).get(0), player.inventory);
		}
}

Where it is called:

@Override
public boolean processInteract(EntityPlayer player, EnumHand hand){
        if (this.getHired() == false && this.getProfession() == 5 && !world.isRemote && !this.isChild())
        {
    		BlockPos blockpos = new BlockPos(this);
        	player.openGui(Iv.instance, GuiHandler.Villager_Hire, world, blockpos.getX(), blockpos.getY(), blockpos.getZ());
        	return true;
        }
}

 

Edit:

As well, when I try to register the data parameter that holds the player id, I get this:

[13:45:40] [Server thread/ERROR] [FML]: Exception caught during firing event net.minecraftforge.event.entity.EntityJoinWorldEvent@44fae74c:
java.lang.IllegalArgumentException: Duplicate id value for 15!
	at net.minecraft.network.datasync.EntityDataManager.register(EntityDataManager.java:105) ~[EntityDataManager.class:?]
	at orangeVillager61.ImprovedVillagers.Entities.IvVillager.entityInit(IvVillager.java:210) ~[IvVillager.class:?]

 

Erroring code:

        this.getDataManager().register(OWNER_DEFINED_ID, Optional.<UUID>absent());

 

Edited by OrangeVillager61
Link to comment
Share on other sites

6 hours ago, OrangeVillager61 said:

Ah, okay, however, whenever I call the UI, it can't find anything so the list is empty. I think it is my AxisAlignedBB since I'm not sure if I specified the right area.

 

Where the error occurs:


@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
		AxisAlignedBB vilSearch = new AxisAlignedBB(x, y - 1.0D, z, x, y + 2.0D, z);
		if (ID == Villager_Hire){
			return new ContainerIvVillagerHireNitwit((IvVillager)world.getEntitiesWithinAABB(IvVillager.class, vilSearch).get(0), player.inventory);
		}
}

Where it is called:


@Override
public boolean processInteract(EntityPlayer player, EnumHand hand){
        if (this.getHired() == false && this.getProfession() == 5 && !world.isRemote && !this.isChild())
        {
    		BlockPos blockpos = new BlockPos(this);
        	player.openGui(Iv.instance, GuiHandler.Villager_Hire, world, blockpos.getX(), blockpos.getY(), blockpos.getZ());
        	return true;
        }
}

 

 

You're creating an AABB with the x and z coordinates of the BlockPos as both the minimum and maximum coordinates, so the entity will only be found if its bounding box overlaps the northwest corner of the block it's standing on (the area represented by the AABB).

 

You should instead create the AABB with the x and z coordinates of the BlockPos as the minimum coordinates and the x and z coordinates plus 1 as the maximum coordinates. This way the AABB will cover the entire block instead of just the northwest corner. The  AxisAlignedBB(BlockPos) constructor does this for you, you can then use AxisAlignedBB#expand to expand it by 1 in each direction of the y axis (i.e. up and down).

 

I created this item to experiment with corner- and edge-based AABBs passed to World#getEntitiesWithinAABB.

 

Side note: You don't need to cast the result of the List#get call to IvVillager; the result of World#getEntitiesWithinAABB is a List<IvVillager> (because of the first argument), so the List#get call returns an IvVillager.

 

 

Quote

Edit:

As well, when I try to register the data parameter that holds the player id, I get this:


[13:45:40] [Server thread/ERROR] [FML]: Exception caught during firing event net.minecraftforge.event.entity.EntityJoinWorldEvent@44fae74c:
java.lang.IllegalArgumentException: Duplicate id value for 15!
	at net.minecraft.network.datasync.EntityDataManager.register(EntityDataManager.java:105) ~[EntityDataManager.class:?]
	at orangeVillager61.ImprovedVillagers.Entities.IvVillager.entityInit(IvVillager.java:210) ~[IvVillager.class:?]

 

Erroring code:


        this.getDataManager().register(OWNER_DEFINED_ID, Optional.<UUID>absent());

 

 

Are you registering the data parameter more than once? Post the IvVillager class using Gist or Pastebin.

Edited by Choonster
  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I still get nullpointerexceptions on the return hire container (I can't use Blockpos since the game requires it to be x, y and z).

 

	@Override
	public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
		AxisAlignedBB vilSearch = new AxisAlignedBB(x, y - 1, z, x + 1, y + 2, z + 1);
		if (ID == Villager_Hire){
			return new ContainerIvVillagerHireNitwit((IvVillager)world.getEntitiesWithinAABB(IvVillager.class, vilSearch).get(0), player.inventory); //Erroring code
		}
		else if (ID == Hauler){
			return new ContainerIvVillagerHauler((IvVillager)world.getEntitiesWithinAABB(IvVillager.class, vilSearch).get(0), player.inventory);
		}
		else {
			return null;
		}
	}

 

Link to comment
Share on other sites

7 hours ago, OrangeVillager61 said:

 

Data parameter IDs are automatically assigned per class hierarchy. You're passing EntityTameable.class as the first argument of EntityDataManager.createKey, so the DataParameter is being assigned the next ID for the EntityTameable class instead of the next ID for the IvVillager class. When you try to register it for the IvVillager instance, there's already a DataParamter registered for that ID so the game crashes with an IllegalArgumentException.

 

In future, please select the appropriate syntax highlighting when posting code on a site like Gist or Pastebin. To get syntax highlighting on Gist, give each file the appropriate extension (.java for Java code). To get syntax highlighting on Pastebin, select the language from the dropdown at the bottom of the page.

 

The Adult_Age data parameter is Stringly Typed. I suggest replacing the strings with an enum.

 

 

7 hours ago, OrangeVillager61 said:

I still get nullpointerexceptions on the return hire container

 

I can't see any obvious reason for this. If you haven't already, please create a Git repository for your mod, push it to a site like GitHub and link it here so I can debug it locally.

 

See my mod and its .gitignore file for an example of the repository structure to use and the files to include.

 

 

Quote

(I can't use Blockpos since the game requires it to be x, y and z).

 

 

You can still create a BlockPos from the individual coordinates.

Edited by Choonster

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

27 minutes ago, Choonster said:

 

Data parameter IDs are automatically assigned per class hierarchy. You're passing EntityTameable.class as the first argument of EntityDataManager.createKey, so the DataParameter is being assigned the next ID for the EntityTameable class instead of the next ID for the IvVillager class. When you try to register it for the IvVillager instance, there's already a DataParamter registered for that ID so the game crashes with an IllegalArgumentException.

 

Huh, interesting, I wonder when I am registering for EntityTameable? I went through entityInit() dataParameters and there is no EntityTameable between IvVillager and EntityLiving and most of all, I renamed the variable from OWNER_UNIQUE_ID to OWNER_DEFINED_ID to prevent this specific issue.

 

27 minutes ago, Choonster said:

In future, please select the appropriate syntax highlighting when posting code on a site like Gist or Pastebin. To get syntax highlighting on Gist, give each file the appropriate extension (.java for Java code). To get syntax highlighting on Pastebin, select the language from the dropdown at the bottom of the page.

 

The Adult_Age data parameter is Stringly Typed. I suggest replacing the strings with an enum.

 

Thanks for the advice.

27 minutes ago, Choonster said:

 

I can't see any obvious reason for this. If you haven't already, please create a Git repository for your mod, push it to a site like GitHub and link it here so I can debug it locally.

 

See my mod and its .gitignore file for an example of the repository structure to use and the files to include.

 

 

 

I'll make a comit containing the current code on my mod's github, https://github.com/Orange1861/Improved-Villagers/pull/4

 

Link to comment
Share on other sites

On 2017-5-29 at 1:33 AM, OrangeVillager61 said:

Huh, interesting, I wonder when I am registering for EntityTameable? I went through entityInit() dataParameters and there is no EntityTameable between IvVillager and EntityLiving and most of all, I renamed the variable from OWNER_UNIQUE_ID to OWNER_DEFINED_ID to prevent this specific issue.

 

As I said:

On 2017-5-28 at 11:40 PM, Choonster said:

 You're passing EntityTameable.class as the first argument of EntityDataManager.createKey,

 

This is in the OWNER_DEFINED_ID field initialiser.

 

The name of the field doesn't matter, you could call it FOO_BAR_BAZ and the issue would still be present.

 

 

On 2017-5-29 at 1:33 AM, OrangeVillager61 said:

I'll make a comit containing the current code on my mod's github, https://github.com/Orange1861/Improved-Villagers/pull/4

 

Please include your buildscript (build.gradle and gradle.properties) in the repository.

Edited by Choonster
  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I'll start debugging it now.

 

I also recommend using a proper Git client (either the CLI or a GUI client like GitKraken or your IDE) rather than using GitHub's upload system.

 

Edit: You should also include the Gradle wrapper (gradlew, gradlew.bat and the gradle directory) in your repository, though this isn't as essential as the buildscript.

 

Edit 2: You should also include a .gitignore file to ensure only the required files are included in the repository. I linked an example in this post.

Edited by Choonster
  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I figured out the issue: In your Container constructors you were trying to use the villager field, but you never assigned it a value so it was always null. You were also assigning the IItemHandler to a handler local variable instead of the handler field. I fixed these issues in this commit.

 

I also fixed several other issues and changed GuiHandler to use the entity ID instead of the entity's coordinates (which avoids the potential of clicking one villager and opening a GUI for another standing in the same space). You can view and/or merge my changes here.

Edited by Choonster
Fixed link to changes
  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

6 hours ago, Choonster said:

I figured out the issue: In your Container constructors you were trying to use the villager field, but you never assigned it a value so it was always null. You were also assigning the IItemHandler to a handler local variable instead of the handler field. I fixed these issues in this commit.

 

I also fixed several other issues and changed GuiHandler to use the entity ID instead of the entity's coordinates (which avoids the potential of clicking one villager and opening a GUI for another standing in the same space). You can view and/or merge my changes here.

Thank you so much! This fixed the bulk of my issues. However, my skill with GUI (especially with MC/Java) is limited and I have a major issue where when I put an item into the hire slot and the item disappears, I suspect that this may happen with the other GUI for the hired Villager which is supposed to act as a moving chest.

Link to comment
Share on other sites

17 minutes ago, OrangeVillager61 said:

Thank you so much! This fixed the bulk of my issues. However, my skill with GUI (especially with MC/Java) is limited and I have a major issue where when I put an item into the hire slot and the item disappears, I suspect that this may happen with the other GUI for the hired Villager which is supposed to act as a moving chest.

 

I also noticed that, I believe it's due to the IItemHandler returned by EntityLivingBase#getCapability being a wrapper of EntityLivingBase#handInventory and EntityLivingBase#armorArray.

 

EntityLivingBase#onUpdate replaces the contents of these each tick with the ItemStacks returned by EntityLivingBase#getItemStackFromSlot (which EntityLiving implements using its own lists: EntityLiving#inventoryHands and EntityLiving#inventoryArmor), so any changes made through the IItemHandler are overwritten the next tick.

 

I'm going to see if I can reproduce this and create a Forge issue/PR for it.

 

In the meantime, you should create your own IItemHandler field in IvVillager and expose it via hasCapability/getCapability. Currently you're using slot 0 of the combined armour/hands inventories, which is the feet slot.

  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

So something like this? Or do I need to create a capability for the items? I did have a fully functioning capability system but now since it is unused parts of it have been removed (mainly proxy references)

    public IItemHandler item_handler;

 

	public IItemHandler getCapability()
	{
		return this.item_handler;
	}

 

Link to comment
Share on other sites

You need to initialise the IItemHandler field with an instance of an IItemHandler implementation. The default implementation of IItemHandler is ItemStackHandler, which will probably suit your needs. The field should also be private.

 

Override EntityLivingBase#hasCapability (which implements ICapabilityProvider#hasCapability) to return true if the Capability argument is CapabilityItemHandler.ITEM_HANDLER_CAPABILITY or return the result of the super method if it's not

 

Override EntityLivingBase#getCapability (which implements ICapabilityProvider#getCapability) to return the IItemHandler instance if the Capability argument is CapabilityItemHandler.ITEM_HANDLER_CAPABILITY or return the result of the super method if it's not. Due to limitations of Java's generics, you'll need to call Capability#cast on CapabilityItemHandler.ITEM_HANDLER_CAPABILITY with the IItemHandler as the argument to cast it to the return type.

 

Calling the super method allows capabilities to be provided by super classes or attached with AttachCapabilityEvent.

  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

18 minutes ago, Choonster said:

Due to limitations of Java's generics, you'll need to call Capability#cast on CapabilityItemHandler.ITEM_HANDLER_CAPABILITY with the IItemHandler as the argument to cast it to the return type.

Okay, I understand the rest of the text, but I don't really understand this. Is the below what you meant?

	@Override
	public boolean hasCapability(net.minecraftforge.common.capabilities.Capability<?> capability, @Nullable net.minecraft.util.EnumFacing facing)	{
		if (capability.equals(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY))
		{
			return true;
		}
		else
		{
			return super.hasCapability(capability, facing);
		}
	}

	@SuppressWarnings("unchecked")
    @Override
    @Nullable
    public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable net.minecraft.util.EnumFacing facing)
    {
		if (capability.equals((Capability)CapabilityItemHandler.ITEM_HANDLER_CAPABILITY))
		{
			return (T) this.item_handler;
		}
		else
		{
			return super.getCapability(capability, facing);
		}
    }

 

Link to comment
Share on other sites

1 minute ago, OrangeVillager61 said:

Okay, I understand the rest of the text, but I don't really understand this. Is the below what you meant?

 

Almost, but not quite. Instead of casting this.item_handler directly to T and suppressing the unchecked warnings resulting from it, call CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.cast with this.item_handler as the argument.

 

Capability objects are singletons, compare them with the equality operator (==) rather than the Object#equals method.

 

CapabilityItemHandler.ITEM_HANDLER_CAPABILITY is a field of type Capability (more specifically Capability<IItemHandler>), there's no reason to cast it to Capability. In addition to that, there's no Capability#equals method with a Capability parameter; only Object#equals with an Object parameter. Only cast when it's required by the compiler.

 

Import classes like Capability and EnumFacing instead of using fully-qualified names. Forge only uses fully-qualified names in vanilla patches to reduce the patch size (by removing the need for an import statement).

  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

5 minutes ago, Choonster said:

 

Almost, but not quite. Instead of casting this.item_handler directly to T and suppressing the unchecked warnings resulting from it, call CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.cast with this.item_handler as the argument.

 

Capability objects are singletons, compare them with the equality operator (==) rather than the Object#equals method.

 

CapabilityItemHandler.ITEM_HANDLER_CAPABILITY is a field of type Capability (more specifically Capability<IItemHandler>), there's no reason to cast it to Capability. In addition to that, there's no Capability#equals method with a Capability parameter; only Object#equals with an Object parameter. Only cast when it's required by the compiler.

 

Import classes like Capability and EnumFacing instead of using fully-qualified names. Forge only uses fully-qualified names in vanilla patches to reduce the patch size (by removing the need for an import statement).

Oh, okay. Do I still cast this.item_handler to T since I get errors when I don't?

Link to comment
Share on other sites

1 minute ago, OrangeVillager61 said:

Oh, okay. Do I still cast this.item_handler to T since I get errors when I don't?

 

1 minute ago, OrangeVillager61 said:

Instead of casting this.item_handler directly to T and suppressing the unchecked warnings resulting from it, call CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.cast with this.item_handler as the argument.

 

Capability#cast casts it for you without the unchecked warning.

  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

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.