Open oversword opened 3 years ago
See also #11336.
EDIT: an implementation you may find interesting is in pipeworks mod.
@hlqkj Yeah I've seen that, it has the same issues as mine as it is a table and not userdata, I think my implementation is preferable since you don't have to override each method manually
We have an implementation of minetest.is_player
that also accepts tables to allow this usage on the Lua side:
https://github.com/minetest/minetest/blob/40acfc938ce2306dbf6704f8091a89817a73c71b/builtin/game/misc.lua#L80-L84
What you are attempting to do is call into the engine with a fake player which doesn't work and likely won't anytime soon.
Instead of calling obj:right_click(fakeplayer)
you should be directly calling the Lua callback: obj:get_luaentity():on_rightclick(fakeplayer)
(or look into minetest.registered_on_rightclickplayers
if it's a player).
I agree it would be more convenient if mods didn't have to reimplement engine functionality but there is a way to make this work right now and I'm not sure how well the interaction would work between a fake player and engine (C++) code.
however some callbacks - such as the on_rightclick callback on entities require a userdata object and will throw an error if one is not provided.
...and this confused me initially because there is nothing about on_rightclick
that is preventing from passing a fake player, right_click
is a different story.
@sfan5 I was just trying to call on_rightclick
through right_click
. Let me try your suggestion quickly, I did not see any way to access the on_rightclick
callback from where I was at, but I'm just reading the API and dumping out vars
@sfan5 That worked, thanks!
call into the engine with a fake player which doesn't work and likely won't anytime soon
I'm going to leave this ticket up as it should be possible, much like the other 900 tickets that probably should be resolved but likely never will be :P but now that it's got a work-around, I'll mark it low-priority (if I can)
Edit: nope, can't add labels. Anyone reading this may feel free to mark this as unimportant if they like
@sfan5
We have an implementation of minetest.is_player that also accepts tables to allow this usage on the Lua side:
then why not add an API to get such a table when needed? Something like pipeworks and other mods does, when needing to impersonate a player. Would not only be handy, but guarantee a good and well maintained (PlayerRef could change/be extended in future) implementation available to mod devs.
you should be directly calling the Lua callback: obj:get_luaentity():on_rightclick(fakeplayer)
Indeed that's the correct way. Thee are many other callbacks which needs a digger, placer, etc. and are legit callable by mods and this imho justify the addition of such an API:
fakeplayer = minetest.create_fake_player(def)
Relevant: #9177
Originally intended for metadata changes, but could be used for a task like this as well, if the implementation is good. Please see the comments there on why it's not a great solution.
I agree with @hlqkj , the biggest problem with the pipeworks solution is that it basically copies the API manually and may fall out of date at any point, causing a crash when some random callback tries to access a new method which is not on the fake player. If creating a fake player were a core-supported feature we could guarantee that the fake player always implements the latest player API.
@oversword: exactly what I meant.
@SmallJoker: not related to #9177 (which btw should not have been closed, but a solution found). We aren't talking of impersonating an existing player in the sense of loading its data while offline, but to create a "as valid as possible" player table which can be safely passed to the mentioned callbacks...
For cases like pipeworks (eg. a node breaker/deployer) the fake player would have the same name as the node owner, that's useful for protection checks for example. On the other hand in #11336 a different use case was proposed, where the fake player wouldn't even be an actual registered player!
then why not add an API to get such a table when needed?
But that's not what this issue text is about. OP is proposing a function that creates an userdata
player that can be used to trick even engine functions.
I can see what you are proposing being useful but a few points have to be considered:
Related, as this feature would make it possible to avoid such situations: https://forum.minetest.net/viewtopic.php?f=11&t=11336&p=399579#p399579.
UP. This would be very useful for my mod arena_lib, to test minigames requiring more than one player. Instead of opening N clients, server admins could just emulate N-1 players and then join to test. This is especially true for old hardware, for team-based minigames, and to test things that are just trial and error, like HUD
I think we have to split this issue apart to get a clear view:
A corporeal player would be quite useful for testing as mentioned, it would be great for interaction feature testing in any mod.
A corporeal player would also solve my current issue, as I believe the player API is already capable of shrinking the player down, making them invisible, ...or maybe event not rendering the entity at all. As long as this player can be manipulated from mod code.
I thought it would be worth mentioning here, for anyone in need of a fake player, the release of fakelib
, which aims to be the go-to solution for fake players, at least until they get implemented in the engine.
ContentDB: https://content.minetest.net/packages/OgelGames/fakelib/ API documentation: https://github.com/OgelGames/fakelib/blob/master/API.md
Problem
Most (if not all) interaction callbacks require a player to be passed who is performing the interaction, referred to as the
clicker
,placer
,digger
etc. in the API. For the most part, this player can be faked with a table providing all the functions required, however some callbacks - such as theright_click
action on entities require auserdata
object and will throw an error if one is not provided.This kind of fake-player is required for automating tasks such as sheering sheep, which can be accomplished automatically in... other voxel games. It should be possible to accomplish this in minetest too.
Solutions
An API method should be added so that programmers can create a fake player, with the ability to override the player's methods if required. The method should return a
userdata
object which identifies as a player. At a minimum, the programmer should be able to set: the position, the look dir, the wield item, and the inventory.Alternatives
luaentity
and call the callbacks instead of the actions themselves with a table emulating a player as mentioned in the comments - it would still be preferable to use the system logic directly thoughAdditional context
Currently this is my best attempt:
Where
player
is an existing logged in player, andoverrides
is a function that returns the overrides of methods for a given method name. This works for most things, but cannot be passed toentity:right_click(clicker)
as the clicker because it is not auserdata
object.Tying this to an existing and/or logged in player is not a major issue, we could cope if this automation worked only when the owner player is logged in, I feel it's best to tie the "fake player" to a real player so that someone holds responsibility for the nodes placed or items used, if a more generic fake player is implemented I would still want to be able to override things like the player name so it is associated with a real player.
This is my current working code: https://github.com/joe7575/techpack/pull/98/files It can place a node, or use an item on a node, but cannot use an item on an entity because of the limitations described above.