Jump to content

[1.16] What is a good way to fill an itemstack capability with default values?


Tavi007

Recommended Posts

Hello!

 

I want to fill a capability from itemstack with default values only once. I had the same problem with livingEntities, but here I simply modified the spawning event. It seems like I won't be able to do the same for itemstacks, since there are so many possible ways for them to be created (picking up itemEntities, crafting, brewing, smelting. With other mods even more...)

 

One solution i had in mind was to add another boolean to the capability, called isFirstSpawn. It default values is true and once I copy the default values into the capability, I will also set this bool to false. This way, I could trigger the change of the cability in LivingEquipmentChangeEvent (for example) once and then never again. This method seems to be rather complicated however..

 

Do you have a better idea?

Edited by Tavi007
Link to comment
Share on other sites

That's a good idea, however the data doesn't get saved. Here is my repo. Right now I moved my code from ElementifyLivingSpawn and ElementifyProjectileSpawn to private functions in AttachCapabilityEvent. Once this is working I can change elementifyItemstack in the same fashion.

package Tavi007.ElementalCombat.events;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import Tavi007.ElementalCombat.ElementalCombat;
import Tavi007.ElementalCombat.ElementalCombatAPI;
import Tavi007.ElementalCombat.capabilities.CapabilityProviderEntityAndItem;
import Tavi007.ElementalCombat.capabilities.CapabilityProviderProjectile;
import Tavi007.ElementalCombat.capabilities.ElementalAttack;
import Tavi007.ElementalCombat.capabilities.ElementalDefense;
import Tavi007.ElementalCombat.loading.AttackFormat;
import Tavi007.ElementalCombat.loading.EntityData;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.projectile.DamagingProjectileEntity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.biome.Biome.TempCategory;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;

@Mod.EventBusSubscriber(modid = ElementalCombat.MOD_ID, bus = Bus.FORGE)
public class AttachCapabilityEvent 
{
	private static final ResourceLocation ENTITY = new ResourceLocation(ElementalCombat.MOD_ID, "entity_cap");
	private static final ResourceLocation PROJECTILE = new ResourceLocation(ElementalCombat.MOD_ID, "projectile_cap");
	private static final ResourceLocation ITEM = new ResourceLocation(ElementalCombat.MOD_ID, "item_cap");

	@SubscribeEvent
	public static void onAttachEntity(AttachCapabilitiesEvent<Entity> e)
	{
		Entity entity = e.getObject();
		if(entity instanceof LivingEntity) {
			e.addCapability(ENTITY, new CapabilityProviderEntityAndItem());
			elementifyLivingEntity((LivingEntity) entity);
		}
		if(entity instanceof DamagingProjectileEntity) {
			e.addCapability(PROJECTILE, new CapabilityProviderProjectile()); 
			elementifyProjectile((DamagingProjectileEntity) entity);
		}
	}

	@SubscribeEvent
	public static void onAttachItemStack(AttachCapabilitiesEvent<ItemStack> i)
	{
		i.addCapability(ITEM, new CapabilityProviderEntityAndItem());
		elementifyItemstack(i.getObject());
	}

	private static void elementifyLivingEntity(LivingEntity entity) {
		// load default data from dataManager
		ResourceLocation rl = new ResourceLocation(entity.getType().getRegistryName().getNamespace(), "elementalproperties/entities/" + entity.getType().getRegistryName().getPath());
		EntityData entityData = ElementalCombat.DATAMANAGER.getEntityDataFromLocation(rl);
		Set<String> weaknessSet = entityData.getWeaknessSet();
		Set<String> resistanceSet = entityData.getResistanceSet();
		Set<String> immunitySet = entityData.getImmunitySet();
		Set<String> absorbSet = entityData.getAbsorbSet();
		
		// rewrite set to mapping
		Set<AttackFormat> attackFormatSet = entityData.getAttackSet();
		Map<String, Integer> attackMap = new HashMap<String, Integer>();
		attackFormatSet.forEach((attack) ->
		{
			Integer value = attack.getValue();
			if (value <= 0){
				ElementalCombat.LOGGER.info("Elemental damage value of " + attack.getName() + " for " + entity.getName().toString() + " is <= 0. Using 1 instead.");
				value = 1;
			}
			attackMap.put(attack.getName(), value);
		});

		// player spawn should be biome independent
		if(entityData.getBiomeDependency()) 
		{
			String biomeProperties = null;
			BlockPos blockPos = new BlockPos(entity.getPositionVec());

			TempCategory category = entity.getEntityWorld().getBiome(blockPos).getTempCategory();
			if(category == TempCategory.COLD){
				biomeProperties = "ice";
			}
			else if(category == TempCategory.WARM){
				biomeProperties = "fire";
			}
			else if(category == TempCategory.OCEAN){
				biomeProperties = "water";
			}
			if(biomeProperties != null){
				resistanceSet.add(biomeProperties);
			}
		}

		// set capability
		ElementalAttack elemAtckCap = ElementalCombatAPI.getElementalAttackData(entity);
		ElementalDefense elemDefCap = ElementalCombatAPI.getElementalDefenseData(entity);
		elemAtckCap.setAttackMap(attackMap);
		elemDefCap.setWeaknessSet(weaknessSet);
		elemDefCap.setResistanceSet(resistanceSet);
		elemDefCap.setImmunitySet(immunitySet);
		elemDefCap.setAbsorbSet(absorbSet);
	}

	public static void elementifyProjectile(DamagingProjectileEntity entity) {
		if(entity.ticksExisted == 0){
			System.out.println("Newly spawned projectile found");

			DamagingProjectileEntity projectile = (DamagingProjectileEntity) entity;
			Entity  source = projectile.shootingEntity;
			if(source != null && source instanceof LivingEntity){
				LivingEntity sourceEntity = (LivingEntity) source;

				System.out.println("Shooter: " +sourceEntity.getDisplayName().getString());

				// If sourceEntity holds an item, use item data.
				// If not, use data from sourceEntity as default.
				ElementalAttack sourceData;
				if(sourceEntity.hasItemInSlot(EquipmentSlotType.MAINHAND)){
					ItemStack item = sourceEntity.getActiveItemStack();
					sourceData = ElementalCombatAPI.getElementalAttackData(item);
				}
				else{
					sourceData = ElementalCombatAPI.getElementalAttackData(sourceEntity);
				}

				//copy elemental attack capability
				ElementalAttack projectileData = ElementalCombatAPI.getElementalAttackData(projectile);
				projectileData.setAttackMap(sourceData.getAttackMap());
			}
		}
	}


	public static void elementifyItemstack(ItemStack item) {
		
	}

}

 

In these functions everything is happening as it should be, like accessing the data from DATAMANGER. However in ElementifyLivingHurtEvent I only get the (default) empty capability.

 

I know that my capability currently doesn't save its contents when leaving the world and restarting it. This is mostly likely due to an error in my saveNBT or readNBT function. Are these problems connected?

 

 

Edited by Tavi007
Link to comment
Share on other sites

44 minutes ago, Tavi007 said:

I know that my capability currently doesn't save its contents when leaving the world and restarting it. This is mostly likely due to an error in my saveNBT or readNBT function. Are these problems connected?

Not to mention your code is very everywhere and doesn't even store a LazyOptional (why do you call creating a lazy optional EVERY SINGLE TIME), you don't even store the capability you mention.

 

First thing, why in the world are you storing a capability for an ItemStack on an Entity? Second thing, why is there any reference to storing information between these two capabilities. They might have dependent data, but their read and write functions are solely independent. Go look at Choonster's test mod if you want an example. 

Link to comment
Share on other sites

46 minutes ago, ChampionAsh5357 said:

Not to mention your code is very everywhere and doesn't even store a LazyOptional (why do you call creating a lazy optional EVERY SINGLE TIME), you don't even store the capability you mention.

I used minecraftByExample as reference. I did not know, that this is bad practise...

 

Quote

First thing, why in the world are you storing a capability for an ItemStack on an Entity? Second thing, why is there any reference to storing information between these two capabilities. They might have dependent data, but their read and write functions are solely independent.

they have the same capability, but are completly independent of each other. Otherwise I would create 2 classes with identical code (but different names).

 

I will take a look at the test mod to see, how I could improve my code. But please answere me this: Why isn't the capability storing the data? What is going wrong?

Edited by Tavi007
Link to comment
Share on other sites

57 minutes ago, Tavi007 said:

they have the same capability, but are completly independent of each other. Otherwise I would create 2 classes with identical code (but different names).

Ah ok. I misread the code then.

57 minutes ago, Tavi007 said:

I will take a look at the test mod to see, how I could improve my code. But please answere me this: Why isn't the capability storing the data? What is going wrong?

I don't really see anything particularly an issue, but I also couldn't pinpoint the information with the code. I should note that you have two listeners pointing towards AttachCapbilityEvent However, there seems to be a lot of information that is just not right. Most of the information is logical server only so you most likely wouldn't detect any "rendering" changes on the logical client. There is no synchronization if I do say which would be fine if you're not retrieve information on the logical client. How did you test that your capability was returning empty? It could just be you were trying to retrieve information that is not stored on a specific side. Of course, with the mess of code, I could just be completely wrong with my assumptions.

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.



×
×
  • Create New...

Important Information

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