EDIT
Following @jjimenezg93's answer, I created a very basic system in C# for testing, it works! See if you can add anything to it:
public interface IItem
{
List<IAttribute> Components { get; set; }
void ReceiveMessage<T>(T message);
}
public interface IAttribute
{
IItem source { get; set; }
void ReceiveMessage<T>(T message);
}
So far, IItem and IAttribute are base interfaces. There were no need(that I can think of) to have a base interface/attribute for message, so we will directly create a test message class. Now for test classes:
public class TestItem : IItem
{
private List<IAttribute> _components = new List<IAttribute>();
public List<IAttribute> Components
{
get
{
return _components;
}
set
{
_components = value;
}
}
public void ReceiveMessage<T>(T message)
{
foreach (IAttribute attribute in Components)
{
attribute.ReceiveMessage(message);
}
}
}
public class TestAttribute : IAttribute
{
string _infoRequiredFromMessage;
public TestAttribute(IItem source)
{
_source = source;
}
private IItem _source;
public IItem source
{
get
{
return _source;
}
set
{
_source = value;
}
}
public void ReceiveMessage<T>(T message)
{
TestMessage convertedMessage = message as TestMessage;
if (convertedMessage != null)
{
convertedMessage.Execute();
_infoRequiredFromMessage = convertedMessage._particularInformationThatNeedsToBePassed;
Debug.Log("Message passed : " + _infoRequiredFromMessage);
}
}
}
public class TestMessage
{
private string _messageString;
private int _messageInt;
public string _particularInformationThatNeedsToBePassed;
public TestMessage(string messageString, int messageInt, string particularInformationThatNeedsToBePassed)
{
_messageString = messageString;
_messageInt = messageInt;
_particularInformationThatNeedsToBePassed = particularInformationThatNeedsToBePassed;
}
//messages should not have methods, so this is here for fun and testing.
public void Execute()
{
Debug.Log("Desired Execution Method: \nThis is test message : " + _messageString + "\nThis is test int : " + _messageInt);
}
}
These are the setup needed. Now we can use the system(Following is for Unity).
public class TestManager : MonoBehaviour
{
// Use this for initialization
void Start()
{
TestItem testItem = new TestItem();
TestAttribute testAttribute = new TestAttribute(testItem);
testItem.Components.Add(testAttribute);
TestMessage testMessage = new TestMessage("my test message", 1, "VERYIMPORTANTINFO");
testItem.ReceiveMessage(testMessage);
}
}
Attach this TestManager script to a component in scene and you can see in debug that message is successfully passed.
In order to explain things: Every item in the game will implement IItem interface and every Attribute(name should not confuse you, it means item feature/system. Like Upgradeable, or disenchantable) will implement IAttribute. Then we have a method to process the message(why we need message will be explained in further example). So in context, you can attach attributes to an item and let the rest do for you. Which is very flexible, because you can add/remove attributes at ease. So a pseudo-example would be Disenchantable. We will have a class called Disenchantable(IAttribute) and it in Disenchant method, it will ask for:
- List ingredients(when item is disenchanted, what item should be given to player) note: IItem should be extended to have ItemType, ItemID etc.
- int resultModifier(if you implement a kind of boost the disenchant feature, you can pass an int here to increase the ingredients received when disenchanted)
- int failureChance(if disenchant process has a failure chance)
etc.
These information will be provided by a class called DisenchantManager, it will receive the item and form this message according to item(ingredients of the item when disenchanted) and player progression(resultModifier and failureChance). In order to pass this message, we will create a DisenchantMessage class, which will act as a body for this message. So DisenchantManager will populate a DisenchantMessage and send it to the item. Item will receive the message and pass it to all of it's attached Attributes. Since Disenchantable class's ReceiveMessage method will look for a DisenchantMessage, only Disenchantable attribute will receive this message and act on it. Hope this clears things as much as it did for me :).