Right now, there are multiple mob mods, providing different interfaces to modders. From other mods, there is no good way to tell if an entity "is a mob", because each mob framework effectively provides a different conception of what a mob is. I propose that we should have a common interface for mobs to expose, in addition to the functionality provided by frameworks. This interface would not replace mob frameworks, but would allow modders to treat mobs from different mods uniformly, to the extent that they implement the interface. The interface would go on top of whatever the frameworks already expose. An interface like this would have benefits, including:
- Modders will not have to use heuristics to tell whether an entity should be considered a mob.
- Modders can write mobs that don't use any framework, by just implementing the interface.
- Mods that operate on mobs can write code once that will work for mobs from any or no framework.
- Modders can experiment with new frameworks without worrying about incompatibilities with other mods
Concretely, the interface will consist of core features, which all implementors of the interface should implement, and optional features, which represent some concept that's not universal to all mobs, but may be fairly common, like mob ownership. Each optional feature will have a string id that can be referred to. The interface will have two parts: Fields of luaentitys, and a separate mod.
luaentity Fields
Part of the interface would be for mob entitys to have certain fields. An example of a core feature would be an "is_mob" flag that is always true. An example of an optional feature would be an owner method that returns the name of the current owner of the mob, or nil if there is none.
Mod
A separate mod serves two purposes. First, it can provide a nicer interface for modders interacting with mobs than just the raw luaentity features. Secondly, it provides a place to register global callbacks and similar things. An example of a core feature would be a register_on_punchmob function. I can't think of an example for an optional feature. An example of a utility function would be a owner function, which uses a mob's owner method if it exists, and otherwise returns nil.
Features
I think at least these two features should be in the core:
- luaentity boolean field is_mob: Always set to true for mobs. Can be used to tell if an entity is a mob.
- luaentity table field optional_features: A table of optional features, where the keys are the string ids of optional features, which only exist in the table if the entity supports the feature.
"interface mod" refers to the mod part of the interface, not implementing mods.
- (Core) lua entity method attack(puncher, time_from_last_punch, tool_capabilities, direction, owner): Implements "owned punches", where owner is a player name. Could be used for projectiles, to make sure mobs know who to become aggressive towards. If a mob doesn't use owner information, it can implement this with just a normal punch.
- (Core) luaentity method heal(amount): Heals the mob by the health given
- (Core) mod function register_on_mobdeath(func(obj, cause_of_death)): Register death callbacks for mobs, which would be required to notify the mod when they die. The interface mod could provide a notify_mobdeath function, which dying mobs need to call. cause_of_death would be some data representing what caused the mob to die (representation not determined).
- (Core) mod function register_on_punchmob(func(target, hitter, time_from_last_punch, tool_capabilities, dir, damage, owner)): similar to register_on_punchplayer, but can receive a separate owner of the punch, if it exists. An example use would be for achievements. A mob would be required to notify the mod about punches after calculating damage, but before applying it. The interface mod could provide a notify_punchmob function, which returns whether the damage mechanism should be cancelled (and the mob shouldn't apply damage if it returns true).
- (Core) mod function register_on_spawnmob(func(obj)): Called after a mob spawns and has been initialized. Not called on subsequent activations. Interface mod could provide a notify_spawnmob
- (Optional) luaentity method get_owner(): Returns the name of an owning player, if it exists.
- (Optional) luaentity method relationship("player_name"): Returns a string describing the mob's attitude toward the player, e.g. "friend", "neutral", "hostile".
- (Optional) luaentity method age(): Returns the number of seconds the mob has been alive
- (Optional) luaentity method is_adult(): Returns whether the mob is an adult
- (Optional) mod function register_on_mobbreed(func(obj1, obj2)): Called when two mobs breed. The interface mod could provide a notify_mobbreed function that should be called when two mobs breed.
Obviously, a standard like this will fail if nobody uses it, so this thread should be used to discuss any issues with it. I especially ask any mob framework/library writers to give input.
For everybody:
Do you have any problems with a standard mob interface in principle? If so, why?
How could the structure of the interface be improved?
For modders interfacing with mobs:
Which of my examples do you agree would be useful?
What changes would you make to my examples?
What would you like to see in the interface that I haven't mentioned?
What would make the interface easiest to use?
For mob framework writers:
What can be done to make the interface easier to implement?
Is there anything that would hold you back from implementing this interface?
It's important for the success of this standard that there is somebody in line to adopt it when it arrives, so I probably won't begin any major work on the mod portion of the standard unless at least one major mob framework writer is on board and ready to collaborate to make sure that the resultant design is acceptable to them.
EDIT: Forgot to add, I'll open a github repo at some point to write the actual standard in.