Ghost-chu / QuickShop-Reremake

QuickShop is a shop plugin that allows players to easily sell/buy any items from a chest without any commands. In fact, none of the commands that QuickShop provides are ever needed by a player.
GNU General Public License v3.0
103 stars 147 forks source link

Custom bank shops and fake Vault player issue #1510

Closed Bloodlex closed 2 years ago

Bloodlex commented 2 years ago

Hello,

I create a plugin which aim is to provide ability to create bank shops, but I'm struggling with creating new fake player accounts in order to be able to set them as QuickShop owner. I've been trying a lot of things, but I can't create a new account without player physically logging in. This account should not be spawned in game, just be used as Vault balance account to set as shop owner.

My plugin has also other commands for managing banks. I used to store my balance data in my own plugin table, but then I realized I wouldn't be able to use it in other plugins, because it doesn't utilize Vault API. So I came across a problem with creating new player accounts which would be valid for Vault.

Do you have any hints for me, how I can implement it? I would be grateful for any advise you could have for me. Thank you.

Ghost-chu commented 2 years ago

First of all, you must access the economy provider to create a account of player, for example use Vault, it looks like this:

OfflinePlayer bankAccount = Bukkit.getOfflinePlayer("SomeBankPlayer");
net.milkbowl.vault.economy.Economy economy = getSomeEconomy();
if(!ecnomy.hasAccount(bankAccount) economy.createPlayerAccount(bankAccount);

While account successfully setup, you will need set it to QuickShop shop owner.

Shop shop = getSomeShop();
shop.setOwner(bankAccount.getUniqueId());

And it done. But you will see Unknown Owner in the first line of the sign, because we created a fake player, and there no data for it.

So next, you will need to listen ShopUpdateEvent, then you will receive which one shop's has been updated. Delay 1 tick (cause it is uncancellable), call Shop#getSignText() get texts on the sign, then replace the Unknown Owner to BankAccount or other you want, and use Shop#setSignText(newContent) to set it back.

QuickShop uses hidden format code to identify the shop sign (at the second line of the texts), just make sure you keep them on the sign.

Ghost-chu commented 2 years ago

More API will be added to QuickShop v5 to allow addon to edit more stuff without complex steps.

Bloodlex commented 2 years ago

First of all, you must access the economy provider to create a account of player, for example use Vault, it looks like this:

OfflinePlayer bankAccount = Bukkit.getOfflinePlayer("SomeBankPlayer");
net.milkbowl.vault.economy.Economy economy = getSomeEconomy();
if(!ecnomy.hasAccount(bankAccount) economy.createPlayerAccount(bankAccount);

While account successfully setup, you will need set it to QuickShop shop owner.

Shop shop = getSomeShop();
shop.setOwner(bankAccount.getUniqueId());

And it done. But you will see Unknown Owner in the first line of the sign, because we created a fake player, and there no data for it.

So next, you will need to listen ShopUpdateEvent, then you will receive which one shop's has been updated. Delay 1 tick (cause it is uncancellable), call Shop#getSignText() get texts on the sign, then replace the Unknown Owner to BankAccount or other you want, and use Shop#setSignText(newContent) to set it back.

QuickShop uses hidden format code to identify the shop sign (at the second line of the texts), just make sure you keep them on the sign.

Thank you! It's really nice of you that you would like to help me, because I was really desperate lately to do it 🙁 . I think the most problematic is to create OfflinePlayer in the first place without having a player joining a game. I mean, what to do before this line:

OfflinePlayer bankAccount = Bukkit.getOfflinePlayer("SomeBankPlayer");

How can I create this offline player without actually logging in as this player? Is it possible at all? I've been trying like this:

PlayerProfile profile = Bukkit.createProfile(UUID.randomUUID(), bankName);

However I don't see that playerdata (file with .dat expension in playerdata folder in world directory) gets created. And if it's not created, many command doesn't recognize a player and simply fail. I'm also using CMI and it's version of Vault, I don't know if that's relevant here.

I've come across a lot of tutorials handling spawning a player, but I just want this account to be compatible with plugins that use Vault and not spawn a player for real.

If I know how to overcome that, I will do later just like you told me further in your answer. Would you be so nice and tell me yet how can I check if a shop being looked on belongs to the player who would execute a command to setOwner to this "player bank account"? I don't want my players to be able to change every shop on the server into their own though 😆

I came across this "Unknown player" issue during my trials and was curious why, thank you for explaining that. It seemed that Quickshop is not able to find my freshly created player (just like many other commands, because I suppose it didn't get properly created by the previously mentioned command).

More API will be added to QuickShop v5 to allow addon to edit more stuff without complex steps.

I'm really looking forward to that 🙂 Your plugin is amazing and support is excellent, it would be an honor to be able to couple it tighter with my other economy server features. My server strongly relies on Quickshop Reremake and it's fundamental for our server for really long time already.

Thank you very much for your help, it really means a lot to me.

Ghost-chu commented 2 years ago

Bukkit#getOfflinePlayer will always returns a OfflinePlayer object even player not exists.

But name will be null and uuid will use offline uuid.

Because it's a virtual account and most plugins couldn't handle it (also no name can display for it.)

Not sure how CMI handle it, my advice is storage a uuid<>name mapping by yourself. And direct access Vault API through UUID from your addon.

For commands, you can replace QuickShop sub commands to yours. Get CommandManager instance, unregister our sub-command and register yours.

Bloodlex commented 2 years ago

Bukkit#getOfflinePlayer will always returns a OfflinePlayer object even player not exists.

But name will be null and uuid will use offline uuid.

Because it's a virtual account and most plugins couldn't handle it (also no name can display for it.)

Not sure how CMI handle it, my advice is storage a uuid<>name mapping by yourself. And direct access Vault API through UUID from your addon.

For commands, you can replace QuickShop sub commands to yours. Get CommandManager instance, unregister our sub-command and register yours.

Thank you. Does it mean that it is impossible to create a player without logging in as this player? Is there no command that could create playerdata and pretend as if a new player logged in?

Sure, thanks, good idea with an own map. But would it work if no playerdata has been created? I can insert into CMI users table a new row for this player, but not sure what to do with playerdata that is stored in "world" directory 🙁 . And it seems that's the reason why many plugins thinks that this player doesn't exist I suppose.

Ghost-chu commented 2 years ago

Bukkit.createProfile seems to be a Paper API and I didn't find it from Spigot.

For creating playerdata -- as far as I know, player must be logged in so the server can store the data for that player.

Ghost-chu commented 2 years ago

Also, there have a workaround:

Directly use fake OfflinePlayer to access Vault API event it not exists, CMI should automatically create the account for them (but cannot access the account through commands, so you will need to control them through your addon).

Bloodlex commented 2 years ago

Also, there have a workaround:

Directly use fake OfflinePlayer to access Vault API event it not exists, CMI should automatically create the account for them (but cannot access the account through commands, so you will need to control them through your addon).

I thought about the same to use Vault API in order to create such account, but it is not recognized by some CMI commands like /balance set X for instance, but that is a question for CMI author I suppose and his implementation of Vault API.

Thank you for your help and hints. I'm really looking forward to the changes in v5, which would allow me to do more things with QuickShop API 🙂

Bloodlex commented 2 years ago

@Ghost-chu hey, one question more: can I completely disable this behavior which updates sign to "Unknown Owner"? I could do like you said with setting an owner back after event is fired, but the problem is that I will have more than one bank on the server and couldn't determine which one was the owner of that particular shop 🙁

Ghost-chu commented 2 years ago

@Ghost-chu hey, one question more: can I completely disable this behavior which updates sign to "Unknown Owner"? I could do like you said with setting an owner back after event is fired, but the problem is that I will have more than one bank on the server and couldn't determine which one was the owner of that particular shop 🙁

It's impossible in v4, but can be done in v5 (still WIP).

Bloodlex commented 2 years ago

@Ghost-chu hey, one question more: can I completely disable this behavior which updates sign to "Unknown Owner"? I could do like you said with setting an owner back after event is fired, but the problem is that I will have more than one bank on the server and couldn't determine which one was the owner of that particular shop 🙁

It's impossible in v4, but can be done in v5 (still WIP).

Okay, thanks a lot 🙂

Ghost-chu commented 2 years ago

API in V5: ShopOwnerNameGettingEvent Impl.