Jump to content

[1.10.2] Converting my IEEPs [1.8.X] to Capabilities


hugo_the_dwarf

Recommended Posts

Hey all, I just got back into modding from a long hiatus. And with a new PC and all that all my old modding setups were wiped, so I figured I'd just bring my mod up to 1.10.2 only to find so many errors. I've cleaned up quite a few but now i'm stuck on my extended props, which I had used very heavily.

 

I've been reading up on capabilities (forge document) not much help on the actual layout and implementation other than some vague "convert this, use this datatype" and anything I find on this forum or in example code is TileEntites or an attempt at an Entity. My IEEPs were mainly for Entities (Max Health bonus, stamina, mana, stats, skills, class, profession, etc.), but I also had a lot of code touching ItemStacks NBTs (weapon level, bonus stats, socketed items, etc)

 

If anyone can explain the process needed:

-Create a class of ICapabilityProvider?

-Setup Event? or Register capability?

-Etc

 

I'd greatly appreciate it or if someone can supply a working example of a Entity and a Itemstack getting capabilities assigned I think I would be able to follow along all those given classes and update my own/created missing, sending packets to update the client(s) is easy enough it doesn't appear packets have changed much from the 1.8 version I was on to 1.10.2

 

Edit:

If needed I could supply my code, however all of my IEEP classes and even the Item classes are rather large due to the amount of custom stats, getters, and setters and helper methods created for complex(not really that complex) calculations.

Link to comment
Share on other sites

Have you read the part about updating from IEEP to Capabilities? There's a separate section for that: http://mcforge.readthedocs.io/en/latest/datastorage/capabilities/#migrating-from-iextendedentityproperties.

Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support.

 

1.12 -> 1.13 primer by williewillus.

 

1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support.

 

http://www.howoldisminecraft1710.today/

Link to comment
Share on other sites

I have read it, it was actually the first part I looked at, actually it was:

https://mcforge.readthedocs.io/en/latest/datastorage/extendedentityproperties/

but thanks to the warning at the top I went to where you had linked. Read it from top to bottom and saw the migration part. However it still is very vague I'm still reading it over, hoping that some of it will sink in.

 

Registration (EntityConstructing): Attaching (AttachCapabilityEvent.Entity), the real registration of the Capability happens during pre-init.

 

I know with IEEP it was the

@SubscribeEvent
public void onEntityConstructing(EntityConstructing event)
{
// Players
	if ((event.getEntity() instanceof EntityPlayer) && (ExtendPlayer
			.get((EntityPlayer) event.getEntity()) == null))
	{
		ExtendPlayer.register((EntityPlayer) event.getEntity());
	}
}

 

but the quoted part confuses me as now I register it somewhere else, but somehow also attach it with a new event?

Link to comment
Share on other sites

Unfortunately I'm not understanding how to get it to work. I'll have to rework my mod completely now, as without being able to store mana, stamina, gold, and other vital attribute stats on players and entities.

 

Without a good reference it's impossible for me to grasp this, from the documentation all it looks like is this just handles storing items (bags, chests, etc) that is not what i'm looking for I just need to store, update, and save custom values that are unique to each player and mob so I can use them during damage and other events.

Link to comment
Share on other sites

You register your capability with

CapabilityManager.register

in preInit. You attach providers for your capability to external objects (

Entities

,

TileEntities

,

ItemStack

s, etc.) when

AttachCapabilitiesEvent<T>

is fired.

 

For examples of capabilities, you can look at the capability test mod or my own mod's capabilities (API, implementation).

 

The

IMaxHealth

capability in my mod will probably be of particular interest, this is attached to entities to store and manage an

AttributeModifier

to provide bonus max health.

  • 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

Thanks Choonster, I tried to follow your code, however you've integrated it with a design pattern of your choosing/making and it made it a bit difficult for me to follow, at least to get the basic idea of how it should flow however your comments of where to register and what events to use is helpful.

 

Thanks Ferrettomato, looking at the Wizardry code I believe is helping me, it's taking me a bit as my extended prop had a great deal of methods and variables so I'm slowly trying to mimic the Wizardry setup, which appears to be the very basic of how to use a capability, it's very helpful.

 

I have a side Question while I'm plugging away at trying to get a test run of my conversion going. For ItemStacks is it better to use a Capability for storing extra data or can we still use the NBT?

 

since my mod is Diablo and other dungeon crawl types heavy, I attach stats to items (min - max dmg, 5 base stat boosts, sockets, etc) currently my old code for ramming that data into itemstacks hasn't yelled at me yet, but I haven't gotten the old code to compile yet (starting over and moving code pieces slowly into a new project)

 

Should I also setup a Capability for ItemStack values or keep using my NBT data code?

Link to comment
Share on other sites

You can still store data in

ItemStack

NBT, but I'd recommend using a capability if your data is complex, you intend to store the same type of data for multiple different items or you intend for other mods to interact with/extend the data.

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

Makes sense, really only players benefit from items with stats, but once i figure out this Capability business I will have to convert that code too.

 

https://bitbucket.org/hugo_the_dwarf/riseoftristram2016/src/59a4ef4abd8ff735f885c7378fc7c33097be0e82/htd/rot/?at=master

 

I've made this a public Repo so hopefully it works. I've just run into an issue of trying to look at the Capability in the FMLPlayerTick event just to see if I can pull data from it. So far class wise the project is just capabilities so far, so hopefully if anyone wants to have a look and see what I'm doing wrong should be easy to navigate

 

EDIT:

 

the Storage Classes save isn't complete, because I might rewrite the data and methods in the interface since I more or less copy pasted from the Extended Prop to the DefaultCapabilityAttribute but I feel like I will scrap it and redesign it when my mind isn't on "Lets get a capability working, and understand it for other capabilities"

Link to comment
Share on other sites

https://github.com/ArtixAllMighty/Rpg-Addon-BerserkMageArcher/tree/master/subaraki/BMA/capability

 

you cannot go any simpler.

I'm only storing two integers here, so the rest stays really basic.

 

attach on attachcapabilityevent, and register with new MyDataCapability().register();

in the mod's preinit

Link to comment
Share on other sites

Awesome that is greatly more helpful (not that the other suggestions were not helpful, I was just struggling to grasp the concepts)

 

I just need to implement the packet usage to update the remote of any changes from the server. And figure out how to get it to work correctly with the clone event (as some stats like what class, profession, etc. should persist through death)

Link to comment
Share on other sites

Ok I got a simple system constructed, with a packet from server to player to update their attributes, however Since player attributes are composed of "Item given Bonuses" and "Class Base Values (berserker, wizard,etc)" it works fine as I can just design a "stats changed, update player" however.

 

Mobs get their stats when they are created, and this is causing me some grief. As I base their standard difficulty on:

Their current constructed Y value (if under sea level deeper means stronger, if higher than 100(currently) higher means stronger)

Using their given "depth" bonus some rand int bounds are given a range, and a baseBonus is given by how deep/high they are.

 

I have that math down right, but Mobs don't really need to send their stats to the clients (can remain server-side as no one can look at their stats)

I tried adding the rolling of stats in the Capabilities Data Constructor (used by the Provider) and reading up someone had this same issue as the attachment of capabilities is done before the entity is fully constructed (just was I gathered correct if wrong)

 

So I tried the EntityEvent.EntityConstructing and checked some values before calling the rollStats, not much luck as I'm guessing events go:

 

EntityConstructing

AttachCapability

 

so I don't believe I can use that, so I tried the LivingEvent.LivingUpdateEvent, checking to see if the entity is not a player, and that a certain value is at the default 0, rollStats.

 

Issue now is that all mobs get the same stats, it's like a one time deal.

 

EDIT

 

I have upaded the Repo/Source https://bitbucket.org/hugo_the_dwarf/riseoftristram2016/src?at=master

Link to comment
Share on other sites

This Method is inside the CapAttributeData class

 

public void rollStats(EntityLivingBase entity)
{
	int[] attrs = new int[attributes.length];
	int baseDepth = 62;
	int baseHeight = 100;
	int yHeight = (int) entity.posY;
	int heightBonus = yHeight < 62 ? yHeight - baseDepth : yHeight > baseHeight ? yHeight - baseHeight : 0;
	heightBonus = heightBonus < 0 ? heightBonus * -1 : heightBonus;

	int mobDifficulty = MathHelper.clamp_int(yHeight/10, 1, 25);
	int baseBonus = mobDifficulty * (mobDifficulty / 5);

	Console.out().println("Mob Stat Rolling: " +entity.getName()+ " Mob Depth: " + yHeight + " Mob Height Bonus: " + heightBonus + " Base Bonus: " + baseBonus);

	Random rand = new Random();
	for (int index = 0; index < attrs.length; index++)
	{
		attrs[index] = (int) ((rand.nextInt(12 + heightBonus) * (mobDifficulty / 4))+baseBonus);
		Console.out().println("Stat "+attributeTags[index]+ ": "+attrs[index] + "-------------");
	}
	Console.out().println("-------------------------------");
	updateAttributes(attrs);
}

Link to comment
Share on other sites

updateAttributes is also inside the CapAttributeData Class

 

public void updateAttributes(int[] attributes)
{
	int[] pulledAttributes = attributes;
	for(int index = 0; index < this.attributes.length;index++)
	{
		pulledAttributes[index] = pulledAttributes[index] > STAT_MAX_LIMIT ? STAT_MAX_LIMIT : pulledAttributes[index];
		pulledAttributes[index] = pulledAttributes[index] < (STAT_MAX_LIMIT * -1) ? (STAT_MAX_LIMIT * -1) : pulledAttributes[index];
	}
	this.attributes = pulledAttributes;
	dataChanged();
}	

public void dataChanged()
{
	if (entity != null && !entity.worldObj.isRemote && entity instanceof EntityPlayer)
	{
		PacketManager.INSTANCE.sendTo(new CapAttributePacket(attributes), (EntityPlayerMP) entity);	
	}
}

 

also included the dataChanged method

 

the updated method is in "EventAddCapability" class for now as i'm just trying to get something working:

 

	@SubscribeEvent
public void onEntityUpdate(LivingEvent.LivingUpdateEvent event)
{
	if(!event.getEntityLiving().worldObj.isRemote && !(event.getEntityLiving() instanceof EntityPlayer))
	{
		if (event.getEntityLiving().hasCapability(CapAttribute.CAPABILITY, null))
		{
			if (event.getEntityLiving().getCapability(CapAttribute.CAPABILITY, null).attributes[0] == 0)
				event.getEntityLiving().getCapability(CapAttribute.CAPABILITY, null).rollStats(event.getEntityLiving());
		}
	}
}

Link to comment
Share on other sites

When you apply the attribute you need to check if they have the attribute otherwise it will get set every update.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

ah so you mean my current attachement:

 

@SubscribeEvent
    public void onAddCapabilities(AttachCapabilitiesEvent.Entity e) 
{
	if (e.getEntity() instanceof EntityLivingBase)
	{
		EntityLivingBase ent = (EntityLivingBase)e.getEntity();
		if (canHaveAttributes(ent))
		{
			e.addCapability(CapAttributeProvider.KEY, new CapAttributeProvider(ent));
		}
	}
    }

 

I should include a "entity.hasCapability(mine,null);"

 

I only find it strange that my Console.out().Prints seem to output the exact same value for every mob including the player (on death)

Link to comment
Share on other sites

The packet only sends the stats from the server to a client, which I have limited to only the player (or a player) currently as it's only for when I setup the GUI again so players can view their own stats.

 

Also with some changes this is roughly my output

 

 

[15:39:31] [server thread/INFO] [sTDOUT]: [htd.rot.capability.CapAttributeData:rollStats:56]: Mob Stat Rolling: Chicken Mob Depth: 98 Mob Height Bonus: 0 Base Bonus: 9
[15:39:31] [server thread/INFO] [sTDOUT]: [htd.rot.capability.CapAttributeData:rollStats:62]: Stat Strength: 25-------------
[15:39:31] [server thread/INFO] [sTDOUT]: [htd.rot.capability.CapAttributeData:rollStats:62]: Stat Dexterity: 25-------------
[15:39:31] [server thread/INFO] [sTDOUT]: [htd.rot.capability.CapAttributeData:rollStats:62]: Stat Intelligence: 25-------------
[15:39:31] [server thread/INFO] [sTDOUT]: [htd.rot.capability.CapAttributeData:rollStats:62]: Stat Vitality: 21-------------
[15:39:31] [server thread/INFO] [sTDOUT]: [htd.rot.capability.CapAttributeData:rollStats:64]: -------------------------------
[15:39:37] [server thread/WARN]: Can't keep up! Did the system time change, or is the server overloaded? Running 2856ms behind, skipping 57 tick(s)
[15:39:55] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:29]: Dead Mob: Sheep
[15:39:55] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Strength=25
[15:39:55] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Dexterity=25
[15:39:55] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Intelligence=25
[15:39:55] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Vitality=21
[15:39:55] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:34]: -----------------------------------------
[15:39:56] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:29]: Dead Mob: Sheep
[15:39:56] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Strength=25
[15:39:56] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Dexterity=25
[15:39:56] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Intelligence=25
[15:39:56] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Vitality=21
[15:39:56] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:34]: -----------------------------------------
[15:39:58] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:29]: Dead Mob: Sheep
[15:39:58] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Strength=25
[15:39:58] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Dexterity=25
[15:39:58] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Intelligence=25
[15:39:58] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:32]: Vitality=21
[15:39:58] [server thread/INFO] [sTDOUT]: [htd.rot.events.EventEntityDeath:onEntityDied:34]: -----------------------------------------
[15:39:58] [server thread/WARN]: Can't keep up! Did the system time change, or is the server overloaded? Running 4020ms behind, skipping 80 tick(s)

 

 

It generates and sets the values for just one mob in this case a chicken, then all of a sudden everyone has the same values (recorded by their death event)

Link to comment
Share on other sites

packet

 

 

package htd.rot.comms.packets;

import htd.rot.Rot;
import htd.rot.capability.CapAttribute;
import htd.rot.capability.CapAttributeData;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;

public class CapAttributePacket implements IMessage 
{

int[] attributes = new int[CapAttributeData.attributes.length];

public CapAttributePacket(){}

public CapAttributePacket(int[] attributes)
{
	this.attributes = attributes;
}

@Override
public void fromBytes(ByteBuf buf)
{		
	for (int index = 0; index < attributes.length; index++)
	{
		attributes[index] = buf.readInt();
	}
}

@Override
public void toBytes(ByteBuf buf)
{
	for (int index = 0; index < attributes.length; index++)
	{
		buf.writeInt(attributes[index]);
	}
}

public static class CapAttributePacketHandler implements IMessageHandler<CapAttributePacket, IMessage>
{

	@Override
	public IMessage onMessage(CapAttributePacket message, MessageContext ctx)
	{
		EntityPlayer player = Rot.proxy.getClientPlayer();
		if (player != null) 
		{
			player.getCapability(CapAttribute.CAPABILITY, null).attributes = message.attributes;
		}				
		return null;
	}

}

}

 

Link to comment
Share on other sites

packet

 

 

package htd.rot.comms.packets;

import htd.rot.Rot;
import htd.rot.capability.CapAttribute;
import htd.rot.capability.CapAttributeData;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;

public class CapAttributePacket implements IMessage 
{

int[] attributes = new int[CapAttributeData.attributes.length];

public CapAttributePacket(){}

public CapAttributePacket(int[] attributes)
{
	this.attributes = attributes;
}

@Override
public void fromBytes(ByteBuf buf)
{		
	for (int index = 0; index < attributes.length; index++)
	{
		attributes[index] = buf.readInt();
	}
}

@Override
public void toBytes(ByteBuf buf)
{
	for (int index = 0; index < attributes.length; index++)
	{
		buf.writeInt(attributes[index]);
	}
}

public static class CapAttributePacketHandler implements IMessageHandler<CapAttributePacket, IMessage>
{

	@Override
	public IMessage onMessage(CapAttributePacket message, MessageContext ctx)
	{
		EntityPlayer player = Rot.proxy.getClientPlayer();
		if (player != null) 
		{
			player.getCapability(CapAttribute.CAPABILITY, null).attributes = message.attributes;
		}				
		return null;
	}

}

}

 

Could they have been on the same y level?

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

It's very possible they would be on the same Y

 

However the roll logic is always 0-12 + (height bonus calculated via Y level being under or above the base Depth and Height)

then that value is multiplied by the MobLevel (Difficulty) which can be 1 to 25 (clamped) / 4

then the baseBonus is added onto it (so if it's higher level mob it will have something always greater than 0)

 

I added in my code to roll on attachment (so when the provider gives it out) and on the update

 

results is I get alot of "everything is nothing" then a rare "stats rolled" but those stats are applied to everything. I may have broken it that or capabilities are shared with "all" entities (one instance to serve them all) if that's the case I want my IEEP back, at least I could have each entity own it's own unique values

 

EDIT

 

to your Y question I hope I was on the same page, even if they were on the same Y there should still be some randomness to their stats

Link to comment
Share on other sites

It's very possible they would be on the same Y

 

However the roll logic is always 0-12 + (height bonus calculated via Y level being under or above the base Depth and Height)

then that value is multiplied by the MobLevel (Difficulty) which can be 1 to 25 (clamped) / 4

then the baseBonus is added onto it (so if it's higher level mob it will have something always greater than 0)

 

I added in my code to roll on attachment (so when the provider gives it out) and on the update

 

results is I get alot of "everything is nothing" then a rare "stats rolled" but those stats are applied to everything. I may have broken it that or capabilities are shared with "all" entities (one instance to serve them all) if that's the case I want my IEEP back, at least I could have each entity own it's own unique values

 

EDIT

 

to your Y question I hope I was on the same page, even if they were on the same Y there should still be some randomness to their stats

Ok I didn't look to much in depth into your calculations so I didn't know about the randomness factor. Is it possible that attributes is a static variable?

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

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.