There are many ways you could go about doing this, and I don’t think there’s a single proper way of doing it.
If you want it to function identically between players and AI without duplicating the system between the two, you could just use the same PlayerState class as the players for the AI, but you’d have to manually spawn it for the AI since PlayerStates are only spawned for players by default. I wouldn’t really recommend this though, because PlayerState is an Actor, so you’re effectively spawning two Actors for each AI you spawn (the AI itself and its State).
You could also use a Struct to store the necessary information, but then you sacrifice the ability of having the functions built into it since Structs are purely data objects. Structs don’t have the overhead that comes with effectively doubling your AI Actors as the PlayerState method would, though. Also Struct variables can be replicated, so you wouldn’t need to create a separate Actor attached to your AI to handle it.
A nice compromise between these two methods may be to create a Component. Components can be replicated and can have both variables and functions. In addition to this, they are automatically spawned for each instance of the class they’re attached to, so you’re guaranteed to get an instance with each AI you spawn without having to worry about manually spawning another Actor and attaching it.
Yet another way, which I personally use, is to create a base class shared between all your characters that stores HP
, Mana
, etc. and the functions. Then, I extend that class with the AI version and the Player version. For example, I have RPGCharacter which handles basic stuff like stats, attributes, equipment, skills, etc. Then I have RPGPlayerCharacter which adds player specific functions such as input, and RPGAICharacter, which adds AI specific functions. If necessary, you can override functions in the subclasses to completely change their functionality.
I may be a bit biased, but I highly recommend the last method because, as a programmer, it makes the most sense to me. You have functionality you want to share between two classes, so you derive them from the same base class and override or extend things to change it rather than writing the same thing twice.
I hope this helps!