-
Posts
77 -
Joined
-
Last visited
Converted
-
Gender
Undisclosed
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
Purplicious_Cow's Achievements
Stone Miner (3/8)
1
Reputation
-
[1.16.4] [SOLVED] Config sync between client/server
Purplicious_Cow replied to Purplicious_Cow's topic in Modder Support
Just to put a cap on this one in case anyone falls into this trap, I had originally been confused by the Minecraft Forge notes found in the update to the ModConfig class, where it states that Common and Client sides are not synced, meanwhile the Server side is. From https://github.com/MinecraftForge/MinecraftForge/blob/1.16.x/src/main/java/net/minecraftforge/fml/config/ModConfig.java The description below from the Forge code could use some clarification. In the end the COMMON spec was the correct one for the case I presented above, and the error I was seeing was somewhere else in my own code. public enum Type { /** * Common mod config for configuration that needs to be loaded on both environments. * Loaded on both servers and clients. * Stored in the global config directory. * Not synced. * Suffix is "-common" by default. */ COMMON, /** * Client config is for configuration affecting the ONLY client state such as graphical options. * Only loaded on the client side. * Stored in the global config directory. * Not synced. * Suffix is "-client" by default. */ CLIENT, // /** // * Player type config is configuration that is associated with a player. // * Preferences around machine states, for example. // */ // PLAYER, /** * Server type config is configuration that is associated with a server instance. * Only loaded during server startup. * Stored in a server/save specific "serverconfig" directory. * Synced to clients during connection. * Suffix is "-server" by default. */ SERVER; public String extension() { return StringUtils.toLowerCase(name()); } } -
[1.16.4] [SOLVED] Config sync between client/server
Purplicious_Cow replied to Purplicious_Cow's topic in Modder Support
God, sometimes I wonder about my brain. I just tested several cases and proved your point. The bug was in my checking of the configuration value. No need for packets. Maybe another cup of coffee. -
[1.16.3] How to find Biome in BiomeLoadingEvent.
Purplicious_Cow replied to Pickle_Face5's topic in Modder Support
Look under Biome.Category, which can also be referenced in the BiomeLoadingEvent, under event.getCategory() -
[1.16.4] [SOLVED] Config sync between client/server
Purplicious_Cow posted a topic in Modder Support
I have a general question about Configs in 1.15/1.16. Is there a way to force sync Common config between server and client (where Server is the owner of record)? I have several common config values that should be controlled by the values from the server (when on server). With Common spec, however, users can change Common values client side and the server does not override them. This allows certain players to take advantage of game play by lowering difficulty or enabling features they shouldn't have in a group setting. If I use the Server type spec, this puts all of these 'protected' values into the Server config, which is actually stored within the 'Save' file on the World server. This means that players who use the mod primarily in a single player setting will have to update their config preferences every time they create a new world, which seems like an extraordinary inconvenience for single players. What is the recommended approach for solving this issue? Thank you for any guidance. -
[1.16.4] Custom Structures not generating in Nether
Purplicious_Cow replied to Purplicious_Cow's topic in Modder Support
Thanks, GenElectrovise. I had the same thought, but couldn't figure out how to force DimensionSettings to use field_242736_e (for the Nether). From my understanding of the code in func_242745_a, it looks like it pulls the world correct key prior to applying final settings, but I could be wrong. I may try this again, using access transformers to see if I can force the Nether key for this particular structure. -
[1.16.4] Custom Structures not generating in Nether
Purplicious_Cow posted a topic in Modder Support
I'm having issues trying to get Custom Structures to generate in the Nether. The same structure generates correctly in the Overworld (e.g., Swamp Biome works fine), but it doesn't even fire the event generation in the Nether. I suspect it's something in the way I've done registration or with the way Biome loading works in the Nether, but after two days, I haven't been able to move the needle. Any help appreciated: package com.inventorypets.worldgen; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.inventorypets.InventoryPets; import net.minecraft.util.ResourceLocation; import net.minecraft.util.registry.WorldGenRegistries; import net.minecraft.world.biome.Biome; import net.minecraft.world.gen.DimensionSettings; import net.minecraft.world.gen.GenerationStage; import net.minecraft.world.gen.feature.IFeatureConfig; import net.minecraft.world.gen.feature.NoFeatureConfig; import net.minecraft.world.gen.feature.StructureFeature; import net.minecraft.world.gen.feature.structure.IStructurePieceType; import net.minecraft.world.gen.feature.structure.Structure; import net.minecraft.world.gen.settings.DimensionStructuresSettings; import net.minecraft.world.gen.settings.StructureSeparationSettings; import net.minecraftforge.event.world.BiomeLoadingEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.RegistryObject; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; public class WorldGen { static DeferredRegister<Structure<?>> STRUCTURES = DeferredRegister.create(ForgeRegistries.STRUCTURE_FEATURES, InventoryPets.MODID); static List<Structure<?>> STRUCTURE_LIST = new ArrayList<>(); static Map<ResourceLocation, StructureSeparationSettings> STRUCTURE_SETTINGS = new HashMap<>(); static IStructurePieceType register(IStructurePieceType type, String name) { net.minecraft.util.registry.Registry.register(net.minecraft.util.registry.Registry.STRUCTURE_PIECE, new ResourceLocation(InventoryPets.MODID, name), type); return type; } static <C extends IFeatureConfig, S extends Structure<C>> StructureFeature<C, S> register(StructureFeature<C, S> feature, String name) { WorldGenRegistries.register(WorldGenRegistries.CONFIGURED_STRUCTURE_FEATURE, new ResourceLocation(InventoryPets.MODID, name), feature); return feature; } static <C extends IFeatureConfig> RegistryObject<Structure<C>> addStructure(String name, Structure<C> structure, GenerationStage.Decoration stage, StructureSeparationSettings settings) { Structure.NAME_STRUCTURE_BIMAP.put(InventoryPets.MODID + ":" + name, structure); Structure.STRUCTURE_DECORATION_STAGE_MAP.put(structure, stage); STRUCTURE_LIST.add(structure); STRUCTURE_SETTINGS.put(new ResourceLocation(InventoryPets.MODID, name), settings); if (stage == GenerationStage.Decoration.SURFACE_STRUCTURES) { Structure.field_236384_t_ = ImmutableList.<Structure<?>>builder().addAll(Structure.field_236384_t_).add(structure).build(); } return STRUCTURES.register(name, () -> structure); } public static IStructurePieceType SKY_DUNGEON_PIECE; public static IStructurePieceType SPACE_DUNGEON_PIECE; public static IStructurePieceType NETHER_DUNGEON_PIECE; public static IStructurePieceType UNDERGROUND_DUNGEON_PIECE; public static IStructurePieceType TREE_TOP_PIECE; public static IStructurePieceType SEA_CAVE_PIECE; public static RegistryObject<Structure<NoFeatureConfig>> SKY_DUNGEON_STRUCTURE = addStructure("sky_dungeon", new SkyDungeonStructure(NoFeatureConfig.field_236558_a_), GenerationStage.Decoration.RAW_GENERATION, new StructureSeparationSettings(7, 6, 1236)); public static RegistryObject<Structure<NoFeatureConfig>> SPACE_DUNGEON_STRUCTURE = addStructure("space_dungeon", new SpaceDungeonStructure(NoFeatureConfig.field_236558_a_), GenerationStage.Decoration.RAW_GENERATION, new StructureSeparationSettings(9, 5, 1337)); public static RegistryObject<Structure<NoFeatureConfig>> NETHER_DUNGEON_STRUCTURE = addStructure("nether_dungeon", new NetherDungeonStructure(NoFeatureConfig.field_236558_a_), GenerationStage.Decoration.RAW_GENERATION, new StructureSeparationSettings(6, 3, 1438)); public static RegistryObject<Structure<NoFeatureConfig>> UNDERGROUND_DUNGEON_STRUCTURE = addStructure("underground_dungeon", new UndergroundDungeonStructure(NoFeatureConfig.field_236558_a_), GenerationStage.Decoration.RAW_GENERATION, new StructureSeparationSettings(8, 6, 1539)); public static RegistryObject<Structure<NoFeatureConfig>> TREE_TOP_STRUCTURE = addStructure("tree_top", new TreeTopStructure(NoFeatureConfig.field_236558_a_), GenerationStage.Decoration.SURFACE_STRUCTURES, new StructureSeparationSettings(4, 3, 1640)); public static RegistryObject<Structure<NoFeatureConfig>> SEA_CAVE_STRUCTURE = addStructure("sea_cave", new SeaCaveStructure(NoFeatureConfig.field_236558_a_), GenerationStage.Decoration.RAW_GENERATION, new StructureSeparationSettings(8, 6, 1741)); public static StructureFeature<NoFeatureConfig, ? extends Structure<NoFeatureConfig>> SKY_DUNGEON_FEATURE; public static StructureFeature<NoFeatureConfig, ? extends Structure<NoFeatureConfig>> SPACE_DUNGEON_FEATURE; public static StructureFeature<NoFeatureConfig, ? extends Structure<NoFeatureConfig>> NETHER_DUNGEON_FEATURE; public static StructureFeature<NoFeatureConfig, ? extends Structure<NoFeatureConfig>> UNDERGROUND_DUNGEON_FEATURE; public static StructureFeature<NoFeatureConfig, ? extends Structure<NoFeatureConfig>> TREE_TOP_FEATURE; public static StructureFeature<NoFeatureConfig, ? extends Structure<NoFeatureConfig>> SEA_CAVE_FEATURE; public static void preInit() { STRUCTURES.register(FMLJavaModLoadingContext.get().getModEventBus()); } public static void init() { SKY_DUNGEON_PIECE = register(SkyDungeonStructure.Piece::new, "sky_dungeon"); SKY_DUNGEON_FEATURE = register(SKY_DUNGEON_STRUCTURE.get().withConfiguration(NoFeatureConfig.field_236559_b_), "sky_dungeon"); SPACE_DUNGEON_PIECE = register(SpaceDungeonStructure.Piece::new, "space_dungeon"); SPACE_DUNGEON_FEATURE = register(SPACE_DUNGEON_STRUCTURE.get().withConfiguration(NoFeatureConfig.field_236559_b_), "space_dungeon"); UNDERGROUND_DUNGEON_PIECE = register(UndergroundDungeonStructure.Piece::new, "underground_dungeon"); UNDERGROUND_DUNGEON_FEATURE = register(UNDERGROUND_DUNGEON_STRUCTURE.get().withConfiguration(NoFeatureConfig.field_236559_b_), "underground_dungeon"); TREE_TOP_PIECE = register(TreeTopStructure.Piece::new, "tree_top"); TREE_TOP_FEATURE = register(TREE_TOP_STRUCTURE.get().withConfiguration(NoFeatureConfig.field_236559_b_), "tree_top"); SEA_CAVE_PIECE = register(SeaCaveStructure.Piece::new, "sea_cave"); SEA_CAVE_FEATURE = register(SEA_CAVE_STRUCTURE.get().withConfiguration(NoFeatureConfig.field_236559_b_), "sea_cave"); NETHER_DUNGEON_PIECE = register(NetherDungeonStructure.Piece::new, "nether_dungeon"); NETHER_DUNGEON_FEATURE = register(NETHER_DUNGEON_STRUCTURE.get().withConfiguration(NoFeatureConfig.field_236559_b_), "nether_dungeon"); for (Structure<?> s : STRUCTURE_LIST) { ImmutableSet.of(DimensionSettings.field_242734_c, DimensionSettings.field_242736_e); DimensionStructuresSettings.field_236191_b_ = ImmutableMap.<Structure<?>, StructureSeparationSettings>builder() .putAll(DimensionStructuresSettings.field_236191_b_) .put(s, STRUCTURE_SETTINGS.get(s.getRegistryName())) .build(); DimensionSettings.field_242740_q.getStructures().field_236193_d_.put(s, STRUCTURE_SETTINGS.get(s.getRegistryName())); } } @SubscribeEvent(priority = EventPriority.HIGHEST) public void onBiomeLoad(BiomeLoadingEvent event) { event.getGeneration().withStructure(SKY_DUNGEON_FEATURE); event.getGeneration().withStructure(SPACE_DUNGEON_FEATURE); event.getGeneration().withStructure(UNDERGROUND_DUNGEON_FEATURE); if (event.getCategory() == Biome.Category.FOREST || event.getCategory() == Biome.Category.PLAINS || event.getCategory() == Biome.Category.SAVANNA || event.getCategory() == Biome.Category.TAIGA || event.getCategory() == Biome.Category.EXTREME_HILLS ) { event.getGeneration().withStructure(TREE_TOP_FEATURE); } else if (event.getCategory() == Biome.Category.OCEAN) { event.getGeneration().withStructure(SEA_CAVE_FEATURE); } else if (event.getCategory() == Biome.Category.SWAMP || event.getCategory() == Biome.Category.NETHER) { event.getGeneration().withStructure(NETHER_DUNGEON_FEATURE); } } } -
Ahhhhh! Brilliant. Thank you. I didn't realize you could create a dummy register object from another mod.
-
Thanks diesieben07. I use the getItem() method for 99.9% of cases. I had used the unlocalized name in earlier version of inventory pets to check cross-mod (e.g., identifying the bosses from OreSpawn for example, or to avoid conflicts with other mod items). The fact that the unlocalized name can change is a good reason to use getRegistryName(). Thanks both for filling in the gaps.
-
Yes, clearly the registry name, which I will change going forward (on the versions I can still do so), but that was not my question. You are hinting at a Client vs. Server issue, but not quite. This method has been in the Inventory Pets code since 1.7.10 and players have not seen issues. Is it simply a recommendation to avoid future deprecation, or is it just a performance recommendation? Was hoping for a technical answer.
-
On diesieben07's great issues and recommendations post (linked below), item #7 reads: 7. Do not use the unlocalized names for things other than displaying the name of a block/item. If you want to access the registry name for a registry entry, use IForgeRegistryEntry::getRegistryName. Can someone explain why this is an issue? I have some small bit of code doing this now, and have not experienced any issues....
-
Nice! Yes, I think I can use this. Will report back if I run into issues/questions.
-
Hello Forge friends. Long time. I'm finally updating my mods to 1.15.x (and up), and have run into an issue with one of the features in Inventory Pets, which dynamically determined which recipe set the player saw based on a config value (thereby increasing the difficulty of game by using harder to find ingredients). I see that we can no longer use the 'remove' feature from the Registry. And I see williewillus' note in his super-valuable primer that super dynamic recipes still haven't been implemented in 1.14/1.15.x (not sure if that's the same thing). The one idea I came up with was to restrict a set of recipes to be based on an advancement which is would be unlocked after checking config settings. Probably not the best experience. Am I missing another method? Thanks for any assistance. Purp
-
FYI, I went with Lycanite's solution, which is to use try/catch on all attempts to access the data. On failure, it reverts to a default state. It's not ideal, but it prevents crashing in the case there is a conflict. Example: public float getFloatFromDataManager(DataParameter<Float> key) { try { return this.getDataManager().get(key); } catch (Exception e) { return 0; } }
-
No, no, I meant, do you think it's a bad idea to use Capabilities to do the same thing that DataParameters are doing. @diesiben07, thanks for the response. Ok, so it sounds like I have to implement the data synchronization manually. For some reason, I though the entity automatically did this (writeToNBT). How would you recommend I sync manually, using network packets? Finally, I'm going to include one of my entity base classes for the Ferret, which has crashed with this error, just in case I'm doing something really dumb with this and I don't know it (distinct possibility). This one extends EntityTameable (which has its own parameters, of course) package com.animania.common.entities.rodents; import java.util.Random; import java.util.Set; import javax.annotation.Nullable; import com.animania.Animania; import com.animania.common.ModSoundEvents; import com.animania.common.capabilities.CapabilityRefs; import com.animania.common.capabilities.ICapabilityPlayer; import com.animania.common.entities.AnimalContainer; import com.animania.common.entities.AnimaniaAnimal; import com.animania.common.entities.EntityGender; import com.animania.common.entities.ISpawnable; import com.animania.common.entities.amphibians.EntityAmphibian; import com.animania.common.entities.amphibians.EntityFrogs; import com.animania.common.entities.amphibians.EntityToad; import com.animania.common.entities.chickens.EntityChickLeghorn; import com.animania.common.entities.chickens.EntityChickOrpington; import com.animania.common.entities.chickens.EntityChickPlymouthRock; import com.animania.common.entities.chickens.EntityChickRhodeIslandRed; import com.animania.common.entities.chickens.EntityChickWyandotte; import com.animania.common.entities.genericAi.EntityAnimaniaAvoidWater; import com.animania.common.entities.rodents.ai.EntityAIFerretFindFood; import com.animania.common.entities.rodents.ai.EntityAIFindWater; import com.animania.common.entities.rodents.ai.EntityAILookIdleRodent; import com.animania.common.entities.rodents.ai.EntityAIRodentEat; import com.animania.common.entities.rodents.ai.EntityAISwimmingRodents; import com.animania.common.entities.rodents.ai.EntityAITemptRodents; import com.animania.common.entities.rodents.ai.EntityAIWatchClosestFromSide; import com.animania.common.handler.ItemHandler; import com.animania.common.helper.AnimaniaHelper; import com.animania.common.items.ItemEntityEgg; import com.animania.compat.top.providers.entity.TOPInfoProviderRodent; import com.animania.config.AnimaniaConfig; import com.animania.network.client.CapSyncPacket; import com.google.common.collect.Sets; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityAgeable; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAIAttackMelee; import net.minecraft.entity.ai.EntityAIFollowOwner; import net.minecraft.entity.ai.EntityAIHurtByTarget; import net.minecraft.entity.ai.EntityAILeapAtTarget; import net.minecraft.entity.ai.EntityAINearestAttackableTarget; import net.minecraft.entity.ai.EntityAIPanic; import net.minecraft.entity.ai.EntityAISit; import net.minecraft.entity.ai.EntityAIWanderAvoidWater; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.monster.EntitySilverfish; import net.minecraft.entity.passive.EntityTameable; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.init.MobEffects; import net.minecraft.init.SoundEvents; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.potion.PotionEffect; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; public class EntityFerretBase extends EntityTameable implements TOPInfoProviderRodent, ISpawnable, AnimaniaAnimal { protected static final DataParameter<Boolean> FED = EntityDataManager.<Boolean>createKey(EntityFerretBase.class, DataSerializers.BOOLEAN); protected static final DataParameter<Boolean> WATERED = EntityDataManager.<Boolean>createKey(EntityFerretBase.class, DataSerializers.BOOLEAN); protected static final DataParameter<Boolean> TAMED = EntityDataManager.<Boolean>createKey(EntityFerretBase.class, DataSerializers.BOOLEAN); protected static final DataParameter<Boolean> SITTING = EntityDataManager.<Boolean>createKey(EntityFerretBase.class, DataSerializers.BOOLEAN); protected static final DataParameter<Boolean> RIDING = EntityDataManager.<Boolean>createKey(EntityFerretBase.class, DataSerializers.BOOLEAN); protected static final DataParameter<Boolean> AGE = EntityDataManager.<Boolean>createKey(EntityFerretBase.class, DataSerializers.BOOLEAN); protected static final Set<Item> TEMPTATION_ITEMS = Sets.newHashSet(new Item[] { Items.MUTTON, Items.EGG, ItemHandler.brownEgg, Items.CHICKEN, ItemHandler.rawWyandotteChicken, ItemHandler.rawRhodeIslandRedChicken, ItemHandler.rawRhodeIslandRedChicken, ItemHandler.rawOrpingtonChicken, ItemHandler.rawPrimeChicken }); protected int fedTimer; protected int wateredTimer; protected int happyTimer; protected int tamedTimer; public int blinkTimer; public int eatTimer; public EntityAIRodentEat entityAIEatGrass; protected int damageTimer; protected FerretType type; private int delayCount; public EntityFerretBase(World worldIn) { super(worldIn); this.setSize(.75F, .40F); this.stepHeight = 1.1F; this.fedTimer = AnimaniaConfig.careAndFeeding.feedTimer + this.rand.nextInt(100); this.wateredTimer = AnimaniaConfig.careAndFeeding.waterTimer + this.rand.nextInt(100); this.happyTimer = 60; this.tamedTimer = 120; this.blinkTimer = 70 + this.rand.nextInt(70); this.enablePersistence(); this.delayCount = 5; } @Override protected void initEntityAI() { this.aiSit = new EntityAISit(this); this.tasks.addTask(0, new EntityAISwimmingRodents(this)); if (!AnimaniaConfig.gameRules.ambianceMode) { this.tasks.addTask(2, new EntityAIFindWater(this, 1.0D)); this.tasks.addTask(3, new EntityAIFerretFindFood(this, 1.0D)); } this.tasks.addTask(2, this.aiSit); this.entityAIEatGrass = new EntityAIRodentEat(this); this.tasks.addTask(3, new EntityAILeapAtTarget(this, 0.2F)); this.tasks.addTask(4, new EntityAIAttackMelee(this, 1.0D, true)); this.tasks.addTask(6, new EntityAIFollowOwner(this, 1.0D, 10.0F, 2.0F)); this.tasks.addTask(7, new EntityAIPanic(this, 1.5D)); this.tasks.addTask(8, new EntityAIRodentEat(this)); this.tasks.addTask(9, new EntityAITemptRodents(this, 1.2D, false, EntityFerretBase.TEMPTATION_ITEMS)); this.tasks.addTask(10, this.entityAIEatGrass); this.tasks.addTask(11, new EntityAIWanderAvoidWater(this, 1.2D)); this.tasks.addTask(12, new EntityAIWatchClosestFromSide(this, EntityPlayer.class, 6.0F)); this.tasks.addTask(13, new EntityAILookIdleRodent(this)); this.tasks.addTask(14, new EntityAnimaniaAvoidWater(this)); if (AnimaniaConfig.gameRules.animalsCanAttackOthers) { this.targetTasks.addTask(1, new EntityAINearestAttackableTarget(this, EntityChickLeghorn.class, false)); this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityChickOrpington.class, false)); this.targetTasks.addTask(3, new EntityAINearestAttackableTarget(this, EntityChickPlymouthRock.class, false)); this.targetTasks.addTask(4, new EntityAINearestAttackableTarget(this, EntityChickRhodeIslandRed.class, false)); this.targetTasks.addTask(5, new EntityAINearestAttackableTarget(this, EntityChickWyandotte.class, false)); this.targetTasks.addTask(6, new EntityAINearestAttackableTarget(this, EntitySilverfish.class, false)); this.targetTasks.addTask(7, new EntityAINearestAttackableTarget(this, EntityFrogs.class, false)); this.targetTasks.addTask(8, new EntityAINearestAttackableTarget(this, EntityToad.class, false)); this.targetTasks.addTask(9, new EntityAIHurtByTarget(this, true, new Class[0])); } } @Override protected void applyEntityAttributes() { super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(8.0D); this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.35D); this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(0.5D); } @Override protected boolean canDespawn() { return false; } @Override public int getVerticalFaceSpeed() { return this.isSitting() ? 20 : super.getVerticalFaceSpeed(); } @Override protected void consumeItemFromStack(EntityPlayer player, ItemStack stack) { this.setFed(true); this.setOwnerId(player.getPersistentID()); this.setIsTamed(true); this.setTamed(true); this.setSitting(false); this.setFerretSitting(false); this.entityAIEatGrass.startExecuting(); if (!player.capabilities.isCreativeMode) if (stack != ItemStack.EMPTY) stack.setCount(stack.getCount() - 1); this.setInLove(player); } @Override public void setInLove(EntityPlayer player) { this.world.setEntityState(this, (byte) 18); } @Override protected void updateAITasks() { this.eatTimer = this.entityAIEatGrass.getEatingGrassTimer(); super.updateAITasks(); } @Override protected void dropFewItems(boolean hit, int lootlevel) { int happyDrops = 0; if (this.getWatered()) happyDrops++; if (this.getFed()) happyDrops++; ItemStack dropItem; if (AnimaniaConfig.drops.customMobDrops) { String drop = AnimaniaConfig.drops.ferretDrop; dropItem = AnimaniaHelper.getItem(drop); } else dropItem = null; ItemStack dropItem2; String drop2 = AnimaniaConfig.drops.ferretDrop2; dropItem2 = AnimaniaHelper.getItem(drop2); if (happyDrops == 2) { if (dropItem != null) { dropItem.setCount(1 + lootlevel); EntityItem entityitem = new EntityItem(this.world, this.posX + 0.5D, this.posY + 0.5D, this.posZ + 0.5D, dropItem); world.spawnEntity(entityitem); } if (dropItem2 != null) { this.dropItem(dropItem2.getItem(), AnimaniaConfig.drops.ferretDrop2Amount + lootlevel); } } else if (happyDrops == 1) { if (dropItem != null) { dropItem.setCount(1 + lootlevel); EntityItem entityitem = new EntityItem(this.world, this.posX + 0.5D, this.posY + 0.5D, this.posZ + 0.5D, dropItem); world.spawnEntity(entityitem); } if (dropItem2 != null) { this.dropItem(dropItem2.getItem(), AnimaniaConfig.drops.ferretDrop2Amount + lootlevel); } } } @Override public boolean processInteract(EntityPlayer player, EnumHand hand) { ItemStack stack = player.getHeldItem(hand); EntityPlayer entityplayer = player; if (stack != ItemStack.EMPTY && stack.getItem() == Items.WATER_BUCKET && delayCount == 0) { delayCount = 5; this.setWatered(true); this.setInLove(player); return true; } else if (stack == ItemStack.EMPTY && this.isTamed() && !this.isFerretSitting() && !player.isSneaking() && delayCount == 0) { delayCount = 5; this.setFerretSitting(true); this.setSitting(true); this.isJumping = false; this.navigator.clearPathEntity(); return true; } else if (stack == ItemStack.EMPTY && this.isTamed() && this.isFerretSitting() && !player.isSneaking() && delayCount == 0) { delayCount = 5; this.setFerretSitting(false); this.setSitting(false); this.isJumping = false; this.navigator.clearPathEntity(); return true; } else if (stack == ItemStack.EMPTY && this.isTamed() && player.isSneaking() && delayCount == 0) { delayCount = 5; ICapabilityPlayer props = CapabilityRefs.getPlayerCaps(player); if (!props.isCarrying()) { props.setAnimal(this.writeToNBT(new NBTTagCompound())); props.setCarrying(true); props.setType(EntityList.getKey(this).getResourcePath()); this.setDead(); player.swingArm(EnumHand.MAIN_HAND); Animania.network.sendToAllAround(new CapSyncPacket(props, player.getEntityId()), new NetworkRegistry.TargetPoint(player.world.provider.getDimension(), player.getPosition().getX(), player.getPosition().getY(), player.getPosition().getZ(), 64)); return true; } } return super.processInteract(player, hand); } @Override public boolean attackEntityAsMob(Entity entityIn) { boolean flag = entityIn.attackEntityFrom(DamageSource.causeMobDamage(this), 1.0F); if (flag) this.applyEnchantments(this, entityIn); if (entityIn instanceof EntityAmphibian) { this.setFed(true); } // Custom Knockback if (entityIn instanceof EntityPlayer) ((EntityLivingBase) entityIn).knockBack(this, 1, this.posX - entityIn.posX, this.posZ - entityIn.posZ); return flag; } @Override protected void entityInit() { super.entityInit(); this.dataManager.register(EntityFerretBase.FED, Boolean.valueOf(true)); this.dataManager.register(EntityFerretBase.WATERED, Boolean.valueOf(true)); this.dataManager.register(EntityFerretBase.TAMED, Boolean.valueOf(false)); this.dataManager.register(EntityFerretBase.SITTING, Boolean.valueOf(false)); this.dataManager.register(EntityFerretBase.RIDING, Boolean.valueOf(false)); this.dataManager.register(EntityFerretBase.AGE, Boolean.valueOf(false)); } @Override public void writeEntityToNBT(NBTTagCompound compound) { super.writeEntityToNBT(compound); compound.setBoolean("Fed", this.getFed()); compound.setBoolean("Watered", this.getWatered()); compound.setBoolean("IsTamed", this.getIsTamed()); compound.setBoolean("IsSitting", this.isFerretSitting()); compound.setBoolean("Riding", this.isFerretRiding()); compound.setBoolean("Age", this.getAge()); } /** * (abstract) Protected helper method to read subclass entity data from NBT. */ @Override public void readEntityFromNBT(NBTTagCompound compound) { super.readEntityFromNBT(compound); this.setFed(compound.getBoolean("Fed")); this.setWatered(compound.getBoolean("Watered")); this.setIsTamed(compound.getBoolean("IsTamed")); this.setFerretSitting(compound.getBoolean("IsSitting")); this.setFerretRiding(compound.getBoolean("Riding")); this.setAge(compound.getBoolean("Age")); } public boolean getAge() { return this.dataManager.get(EntityFerretBase.AGE).booleanValue(); } public void setAge(boolean age) { this.dataManager.set(EntityFerretBase.AGE, Boolean.valueOf(age)); } @Override public boolean canBeLeashedTo(EntityPlayer player) { return true; } @Override protected SoundEvent getAmbientSound() { int happy = 0; int num = 1; if (this.getWatered()) happy++; if (this.getFed()) happy++; if (happy == 2) num = 10; else if (happy == 1) num = 20; else num = 40; Random rand = new Random(); int chooser = rand.nextInt(num); if (chooser == 0) return ModSoundEvents.ferretLiving1; else if (chooser == 1) return ModSoundEvents.ferretLiving2; else if (chooser == 2) return ModSoundEvents.ferretLiving3; else if (chooser == 3) return ModSoundEvents.ferretLiving4; else if (chooser == 4) return ModSoundEvents.ferretLiving5; else if (chooser == 5) return ModSoundEvents.ferretLiving6; else return null; } @Override protected SoundEvent getHurtSound(DamageSource source) { Random rand = new Random(); int chooser = rand.nextInt(3); if (chooser == 0) return ModSoundEvents.ferretHurt1; else if (chooser == 1) return ModSoundEvents.ferretHurt1; else return null; } @Override protected SoundEvent getDeathSound() { return ModSoundEvents.ferretHurt1; } @Override public void playLivingSound() { SoundEvent soundevent = this.getAmbientSound(); if (soundevent != null) this.playSound(soundevent, this.getSoundVolume() - .3F, this.getSoundPitch()); } @Override protected void playStepSound(BlockPos pos, Block blockIn) { this.playSound(SoundEvents.ENTITY_WOLF_STEP, 0.02F, 1.5F); } private boolean interactRide(EntityPlayer entityplayer) { this.isRemoteMountEntity(entityplayer); return true; } private void isRemoteMountEntity(Entity par1Entity) { if (this.isFerretRiding()) { this.setFerretRiding(true); this.startRiding(par1Entity); } else if (!this.isFerretRiding()) this.dismountRidingEntity(); } @Override public void onLivingUpdate() { if (!this.getAge()) { this.setAge(true); } delayCount--; if (delayCount <= 0) { delayCount = 0; } if (this.isFerretSitting() || this.isRiding()) { if (this.getRidingEntity() != null) this.rotationYaw = this.getRidingEntity().rotationYaw; this.navigator.clearPathEntity(); this.navigator.setSpeed(0); } if (this.world.isRemote) this.eatTimer = Math.max(0, this.eatTimer - 1); if (this.blinkTimer > -1) { this.blinkTimer--; if (this.blinkTimer == 0) this.blinkTimer = 100 + this.rand.nextInt(100); } if (this.fedTimer > -1 && !AnimaniaConfig.gameRules.ambianceMode) { this.fedTimer--; if (this.fedTimer == 0) this.setFed(false); } if (this.wateredTimer > -1) { this.wateredTimer--; if (this.wateredTimer == 0 && !AnimaniaConfig.gameRules.ambianceMode) this.setWatered(false); } boolean fed = this.getFed(); boolean watered = this.getWatered(); if (!fed && !watered) { this.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 2, 1, false, false)); if (AnimaniaConfig.gameRules.animalsStarve) { if (this.damageTimer >= AnimaniaConfig.careAndFeeding.starvationTimer) { this.attackEntityFrom(DamageSource.STARVE, 4f); this.damageTimer = 0; } this.damageTimer++; } } else if (!fed || !watered) this.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 2, 0, false, false)); if (this.happyTimer > -1) { this.happyTimer--; if (this.happyTimer == 0) { this.happyTimer = 60; if (!this.getFed() && !this.getWatered() && AnimaniaConfig.gameRules.showUnhappyParticles) { double d = this.rand.nextGaussian() * 0.001D; double d1 = this.rand.nextGaussian() * 0.001D; double d2 = this.rand.nextGaussian() * 0.001D; this.world.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, this.posX + this.rand.nextFloat() * this.width - this.width, this.posY + 1.5D + this.rand.nextFloat() * this.height, this.posZ + this.rand.nextFloat() * this.width - this.width, d, d1, d2); } } } if (this.tamedTimer > -1) { this.tamedTimer--; if (this.tamedTimer == 0) { this.tamedTimer = 120; if (this.getIsTamed() && AnimaniaConfig.gameRules.showUnhappyParticles) { double d = this.rand.nextGaussian() * 0.02D; double d1 = this.rand.nextGaussian() * 0.02D; double d2 = this.rand.nextGaussian() * 0.02D; this.world.spawnParticle(EnumParticleTypes.HEART, this.posX + this.rand.nextFloat() * this.width - this.width, this.posY + 1D + this.rand.nextFloat() * this.height, this.posZ + this.rand.nextFloat() * this.width - this.width, d, d1, d2); } } } super.onLivingUpdate(); } @Override @SideOnly(Side.CLIENT) public void handleStatusUpdate(byte id) { if (id == 10) this.eatTimer = 80; else super.handleStatusUpdate(id); } public boolean isFerretSitting() { return this.dataManager.get(EntityFerretBase.SITTING).booleanValue(); } public void setFerretSitting(boolean flag) { if (flag) this.dataManager.set(EntityFerretBase.SITTING, Boolean.valueOf(true)); else this.dataManager.set(EntityFerretBase.SITTING, Boolean.valueOf(false)); } public boolean isFerretRiding() { return this.dataManager.get(EntityFerretBase.RIDING).booleanValue(); } public void setFerretRiding(boolean flag) { if (flag) this.dataManager.set(EntityFerretBase.RIDING, Boolean.valueOf(true)); else this.dataManager.set(EntityFerretBase.RIDING, Boolean.valueOf(false)); } public boolean getFed() { return this.dataManager.get(EntityFerretBase.FED).booleanValue(); } public void setFed(boolean fed) { if (fed) { this.dataManager.set(EntityFerretBase.FED, Boolean.valueOf(true)); this.fedTimer = AnimaniaConfig.careAndFeeding.feedTimer + this.rand.nextInt(100); this.setHealth(this.getHealth() + 1.0F); } else this.dataManager.set(EntityFerretBase.FED, Boolean.valueOf(false)); } public boolean getWatered() { return this.dataManager.get(EntityFerretBase.WATERED).booleanValue(); } public void setWatered(boolean watered) { if (watered) { this.dataManager.set(EntityFerretBase.WATERED, Boolean.valueOf(true)); this.wateredTimer = AnimaniaConfig.careAndFeeding.waterTimer + this.rand.nextInt(100); } else this.dataManager.set(EntityFerretBase.WATERED, Boolean.valueOf(false)); } public boolean getIsTamed() { return this.dataManager.get(EntityFerretBase.TAMED).booleanValue(); } public void setIsTamed(boolean fed) { if (fed) this.dataManager.set(EntityFerretBase.TAMED, Boolean.valueOf(true)); else this.dataManager.set(EntityFerretBase.TAMED, Boolean.valueOf(false)); } @SideOnly(Side.CLIENT) public float getHeadRotationPointY(float p_70894_1_) { return this.eatTimer <= 0 ? 0.0F : this.eatTimer >= 4 && this.eatTimer <= 176 ? 1.0F : this.eatTimer < 4 ? (this.eatTimer - p_70894_1_) / 4.0F : -(this.eatTimer - 80 - p_70894_1_) / 4.0F; } @SideOnly(Side.CLIENT) public float getHeadRotationAngleX(float p_70890_1_) { if (this.eatTimer > 4 && this.eatTimer <= 176) { float f = (this.eatTimer - 4 - p_70890_1_) / 24.0F; return (float) Math.PI / 5F + (float) Math.PI * 7F / 150F * MathHelper.sin(f * 28.7F); } else return this.eatTimer > 0 ? (float) Math.PI / 5F : this.rotationPitch * 0.017453292F; } @Override public EntityFerretBase createChild(EntityAgeable ageable) { return null; } @Override public boolean isBreedingItem(@Nullable ItemStack stack) { return stack != ItemStack.EMPTY && EntityFerretBase.TEMPTATION_ITEMS.contains(stack.getItem()); } @Override public Item getSpawnEgg() { return ItemEntityEgg.ANIMAL_EGGS.get(new AnimalContainer(this.type, EntityGender.NONE)); } @Override public ItemStack getPickedResult(RayTraceResult target) { return new ItemStack(getSpawnEgg()); } @Override public int getPrimaryEggColor() { // TODO Auto-generated method stub return 0; } @Override public int getSecondaryEggColor() { // TODO Auto-generated method stub return 0; } @Override public EntityGender getEntityGender() { return EntityGender.NONE; } }
-
Thanks, diesieben07, But I'm not going to do that for modpackers with hundreds of mods. So, to be clear... So you don't recommend using capabilities? Also.. based on your response... what if I am extending some vanilla entities (for instance EntityCow) ... could that be a source of conflict if other mods do the same and add their parameters to an extended class?