diff --git a/.poggit.yml b/.poggit.yml index 6f74583..240b41b 100644 --- a/.poggit.yml +++ b/.poggit.yml @@ -3,18 +3,4 @@ projects: AuctionHouse: path: "" icon: icon.png - libs: - - src: SOF3/await-generator/await-generator - version: ^3.1.0 - - src: poggit/libasynql/libasynql - version: ^3.4.0 - - src: muqsit/invmenu/InvMenu - version: ^4.4.1 - branch: "4.0" - - src: ifera-mc/UpdateNotifier/UpdateNotifier - version: ^2.2.0 - branch: API-4.0.0 - - src: CortexPE/Commando/Commando - version: ^3.0.0 - branch: PM4 ... diff --git a/README.md b/README.md index 1035708..2c6ad80 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Feature-packed AuctionHouse plugin for PocketMine-MP ## Overview AuctionHouse allows players to list their items for sale and purchase items that others have listed for sale -![AuctionHouse](https://github.com/Shock95x/AuctionHouse/blob/master/img/auctionhouse.png) +![AuctionHouse](https://github.com/Shock95/AuctionHouse/blob/master/img/auctionhouse.png) --- ## Features >- Chest GUI @@ -22,7 +22,7 @@ AuctionHouse allows players to list their items for sale and purchase items that --- ## Download -Download the plugin from [Poggit](https://poggit.pmmp.io/p/AuctionHouse) or [GitHub releases](https://github.com/Shock95x/AuctionHouse/releases) +Download the plugin from [Poggit](https://poggit.pmmp.io/p/AuctionHouse) or [GitHub releases](https://github.com/Shock95/AuctionHouse/releases) --- ## Config @@ -55,7 +55,7 @@ creative-sale: false max-listings: 45 # Shows item lore on the auction house show-lore: true -# Days to automatically delete expired listings (-1 to disable) +# Days to automatically delete expired listings (0 to disable) expired-duration: 15 # Formats price with commas (ex. 1,000,000) price-formatted: true @@ -91,17 +91,20 @@ cancel_purchase: "minecraft:stained_glass_pane:14" --- ## Commands -| Command | Description | -| ------------- |:--------------| -| /ah | AuctionHouse main command, opens the shop menu if there are no specified parameters | -| /ah shop | Opens the shop menu | -| /ah sell **[price]** | Allows player to list items in their hand on the auction house. **[price]** is the amount that the player is listing the item to sell for | -| /ah listings | Shows all active listings of the player | -| /ah listings **[player]**| Shows all active listings of a specific player | -| /ah category | Opens category menu | -| /ah admin | Opens the AuctionHouse admin menu (OP Command) | -| /ah reload | Allows player to reload configuration files (OP command) | -| /ah about | Shows AuctionHouse version the server is running | +| Command | Description | +|---------------------------------|:------------------------------------------------------------------------------------| +| /ah | AuctionHouse main command, opens the shop menu if there are no specified parameters | +| /ah shop | Opens the shop menu | +| /ah sell **[price]** | Allows player to sell an item on the auction house | +| /ah listings | Shows all active listings of the player | +| /ah listings **[player]** | Allows player to see active listings of a specific player | +| /ah category | Allows player to open the category menu | +| /ah admin | Allows player to open the admin menu (OP Command) | +| /ah admin relistall | Allows player to relist all items in the auction house (OP Command) | +| /ah admin returnall | Allows player to return all items in the auction house back to players (OP Command) | +| /ah admin listings **[player]** | Allows player to see all listings of a specific player (OP Command) | +| /ah reload | Allows player to reload config files (OP command) | +| /ah about | Shows plugin version | --- ## API ### Events @@ -114,19 +117,17 @@ cancel_purchase: "minecraft:stained_glass_pane:14" | [shock95x\auctionhouse\event\MenuCloseEvent](https://github.com/Shock95x/AuctionHouse/blob/master/src/shock95x/auctionhouse/event/MenuCloseEvent.php) | Called when a menu is closed by player | ## Contributing -You can contribute to this project by creating or modifying a language file and opening a PR! -### Contributors -- [Shock95x](https://github.com/Shock95x) (English) -- [ipad54](https://github.com/ipad54) (Russian) -- [No4NaMe](https://github.com/No4NaMe) (Russian) -- [Unickorn](https://github.com/Unickorn) (German) -- Chaosfelix4451#0157 (German) +You can contribute to this project by creating or modifying a language file and opening a PR! +### Contributors +- [Shock95](https://github.com/Shock95) (English) +- [ipad54](https://github.com/ipad54), [No4NaMe](https://github.com/No4NaMe), [XackiGiFF](https://github.com/XackiGiFF) (Russian) +- [Unickorn](https://github.com/Unickorn), Chaosfelix4451 (German) - [xAliTura01](https://github.com/xAliTura01) (Turkish) - [NotEnriko](https://github.com/NotEnriko) (Indonesian) - -## Credits / Virions Used +- +## Virions Used - [InvMenu](https://github.com/Muqsit/InvMenu) (Muqsit) - [libasynql](https://github.com/poggit/libasynql) (SOFe) - [await-generator](https://github.com/SOF3/await-generator) (SOFe) -- [Commando](https://github.com/CortexPE/Commando) (CortexPE) +- [Commando](https://github.com/Paroxity/Commando) (CortexPE + Paroxity) - [UpdateNotifier](https://github.com/ifera-mc/UpdateNotifier) (Ifera) diff --git a/composer.json b/composer.json index 8623b8d..28ba18e 100644 --- a/composer.json +++ b/composer.json @@ -1,20 +1,53 @@ { - "name": "shock95x/auctionhouse", + "name": "shock95/auctionhouse", "description": "Feature-packed AuctionHouse plugin for PocketMine-MP", - "type": "project", + "type": "pocketmine-plugin", "license": "GPL-3.0-or-later", "authors": [ { - "name": "Shock95x" + "name": "Shock95" } ], "require": { - "pocketmine/pocketmine-mp": "^4.0", - "ext-json": "*" + "pocketmine/pocketmine-mp": "^5.0.0", + "sof3/await-generator": "^3.6", + "sof3/libasynql": "dev-master", + "muqsit/invmenu": "^4.6.5", + "ifera-mc/update-notifier": "dev-master", + "muqsit/simple-packet-handler": "dev-pm5", + "cortexpe/commando": "3.1.0" }, - "autoload": { - "psr-4": { - "": "./src" + "require-dev": { + "sof3/pharynx": "^0.3.4" + }, + "repositories": [ + { + "type": "package", + "package": { + "name": "cortexpe/commando", + "version": "3.1.0", + "source": { + "url": "https://github.com/Paroxity/Commando.git", + "type": "git", + "reference": "8473a5030c7e9bed6f7a25533a797361898ab47e" + }, + "autoload": { + "classmap": ["src"] + }, + "extra": { + "virion": { + "spec": "3.0", + "namespace-root": "CortexPE\\Commando" + } + } + } + }, + { + "type": "git", + "url": "https://github.com/ifera-mc/UpdateNotifier.git" } + ], + "autoload": { + "classmap": ["src"] } } \ No newline at end of file diff --git a/plugin.yml b/plugin.yml index 4edda32..ffd6d51 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,14 +1,20 @@ name: AuctionHouse main: shock95x\auctionhouse\AuctionHouse -version: 2.0.2 -api: 4.0.0 -author: Shock95x +version: 2.1.0 +api: 5.0.0 +author: "Shock95" softdepend: [BedrockEconomy] virions: ["InvMenu", "libasynql", "await-generator", "UpdateNotifier", "Commando"] permissions: + auctionhouse.command: + default: true + description: Allows player to use AuctionHouse command + auctionhouse.command.about: + default: true + description: Allows player to shows plugin information auctionhouse.command.shop: default: true - description: Allows player to open the shop menu + description: Allows player to shows AH shop menu auctionhouse.command.sell: default: true description: Allows player to list an item diff --git a/resources/config.yml b/resources/config.yml index 98c0571..be7ad83 100644 --- a/resources/config.yml +++ b/resources/config.yml @@ -22,7 +22,7 @@ creative-sale: false max-listings: 45 # Shows item lore on the auction house show-lore: true -# Days to automatically delete expired listings (-1 to disable) +# Days to automatically delete expired listings (0 to disable) expired-duration: 15 # Formats price with commas (ex. 1,000,000) price-formatted: true diff --git a/resources/language/de_DE.yml b/resources/language/de_DE.yml index 872e75c..e09a7cc 100644 --- a/resources/language/de_DE.yml +++ b/resources/language/de_DE.yml @@ -116,9 +116,7 @@ status-active: "&aAktiv" status-expired: "&cAbgelaufen" selected-listing-name: "&l&cAngebot verwalten" -duplicate-item: "&aKlickt hier um eine Kopie des Items in deinen Inventar zu erhalten" -# listing-expired: "&eClick here to make listing &cexpired" -# listing-active: "&eClick here to make listing &aactive" +copy-item: "&aKlickt hier um eine Kopie des Items in deinen Inventar zu erhalten" delete-item: "&cKlickt hier um das Angebot und das Item zu löschen" # Pagination items diff --git a/resources/language/en_US.yml b/resources/language/en_US.yml index f42e5d8..04616ca 100644 --- a/resources/language/en_US.yml +++ b/resources/language/en_US.yml @@ -20,7 +20,7 @@ cancelled-item: "&eYou have &6cancelled &ean auction. Return cancelled and expir cancelled-purchase: "&cYou have cancelled this purchase" #{PLAYER}, {ITEM}, {PRICE}, {AMOUNT} purchased-item: "&2You have bought &d{ITEM} &r&d(x{AMOUNT}) &2for &d{PRICE}" #{PLAYER}, {ITEM}, {PRICE}, {AMOUNT} seller-message: "&e{PLAYER} &bpurchased {ITEM} (x{AMOUNT}) from you for &d{PRICE}!" #{ITEM}, {AMOUNT} -returned-item: "&2You have removed &d{ITEM} &r&d(x{AMOUNT}) &2from the auction house." +returned-item: "&d{ITEM} &r&d(x{AMOUNT}) &2has been removed from the auction house" # Error messages in-creative: "&cYou cannot sell items while in creative mode." @@ -119,16 +119,13 @@ status-active: "&aActive" status-expired: "&cExpired" selected-listing-name: "&l&eManage Listing" -#duplicate-item: "&aClick here to duplicate item to inventory" -#listing-expired: "&eClick here to make listing &cexpired" -#listing-active: "&eClick here to make listing &aactive" -#delete-item: "&cClick here to delete item and listing" +copy-item: "&bCopy item" +return-item: "&6Return item" +delete-item: "&cDelete item" -duplicate-item: "&aAdd item to inventory" -listing-status: - - "Status: {STATUS}" - - "&6Change listing status" -delete-item: "&cDelete listing and item" +relist-all: "&aRelist all items" +return-all: "&6Return all items" +delete-all: "&cDelete all items" # Pagination items previous-page: diff --git a/resources/language/id_ID.yml b/resources/language/id_ID.yml index 66380a9..0a64fbe 100644 --- a/resources/language/id_ID.yml +++ b/resources/language/id_ID.yml @@ -119,15 +119,7 @@ status-active: "&aAktif" status-expired: "&cExpire" selected-listing-name: "&l&eAtur barang" -#duplicate-item: "&aKlik disini untuk mengduplikat barang ke inventory kamu" -#listing-expired: "&eKlik disini untuk membuat barang &cexpire" -#listing-active: "&eKlik disini untuk membuat barang &aaktif" -#delete-item: "&cClick here to delete item and listing" - -duplicate-item: "&aKasih barang ke inventory kamu" -listing-status: - - "Status: {STATUS}" - - "&6Ubah status barang" +copy-item: "&aKasih barang ke inventory kamu" delete-item: "&cBuang Barang dan Item" # Pagination items diff --git a/resources/language/ru_RU.yml b/resources/language/ru_RU.yml index 080be02..e59f629 100644 --- a/resources/language/ru_RU.yml +++ b/resources/language/ru_RU.yml @@ -6,10 +6,10 @@ menu-name: '&l&6Аукцион' listings-menu-name: '&6Товары на продаже' expired-menu-name: '&6Отменённые / истёкшие предметы' purchase-menu-name: 'Подтвердите покупку' -# admin-menu-name: "&l&cAdmin Menu" -# category-menu-name: "&l&6Category Menu" -# manage-listing-name: "&l&eManage Listing" -# player-listing: "&2{player}'s &6Listings" +admin-menu-name: "&l&cАдмин Меню" +category-menu-name: "&l&6Категории" +manage-listing-name: "&l&eУправление витриной" +player-listing: "&2Витрина товаров &e{player}" # Chat messages item-listed: '&2Вы выставили &d{ITEM} &r&d(x{AMOUNT}) &2 на продажу за &d{PRICE}. &eВведите /ah listings &dчтобы просмотреть все ваши товары' @@ -22,7 +22,7 @@ returned-item: '&2Вы успешно сняли &d{ITEM} &r&d(x{AMOUNT}) &2 с # Error messages in-creative: '&cВы не можете продавать предметы в творческом режиме.' max-listings: '&cВы не можете иметь более {MAX} активных товаров.' #{MAX} -invalid-price: '&cНеккоректная цена.' +invalid-price: '&cНекорректная цена.' not-enough-space: 'Недостаточно места в инвентаре' self-purchase: '&cВы не можете купить свои предметы на аукционе!' no-item: '&cВы должны держать предмет в руке!' @@ -30,12 +30,12 @@ cannot-afford: '&6У вас недостаточно денег, чтобы ку item-blacklisted: '&cЭтот предмет не может быть выставлен на аукцион!' invalid-balance: '&cУ вас недостаточно денег, чтобы выставить предмет на аукцион.' listing-gone: '&cЭтого товара больше не существует, вероятно его уже купили.' -# price-range: "&cInvalid price range" #{MIN}, {MAX} -# in-cooldown: "&cYou are currently in cooldown, please wait &b{M} minute(s) &cand &b{S} second(s)&c." #{M}, {S} -# in-cooldown: "&cYou are currently in cooldown, please wait &b{M} minute(s) &cand &b{S} second(s)&c." #{M}, {S} -# player-not-found: "&cThis player has no active listings." -# player-listings-usage: "&cView your listings with /ah listings" -# inventory-full: "&cYour inventory is full, remove some items to claim your listings." +price-range: "&cНедопустимый диапазон цен" #{MIN}, {MAX} +in-cooldown: "&cВ данный момент вы находитесь в режиме восстановления, пожалуйста, подождите &b{M} минут(ы) &cи &b{S} секудн(ы)&c." #{M}, {S} +player-not-found: "&cУ этого игрока нет активных продаж." +player-listings-usage: "&cПросмотр ваших активных продаж: /ah listings" +inventory-full: "&cВаш инвентарь переполнен, удалите некоторые товары, чтобы снять товар с витрины." +purchase-economy-error: "&cНе удалось завершить транзакцию." # Items in the menu UI listed-item: @@ -66,6 +66,14 @@ view-listed-items: - '&aв данный момент продаете на аукционе.' - '' - '&9Продажа: &e{SELLING}' +expired-item: + # {PRICE} = Price of listing + - "&7-------------------------" + - "&aНажмите здесь, чтобы получить товар." + - "" + - "" + - "&9Цена: &e{PRICE}" + - "&7-------------------------" view-expired-items: # {EXPIRED} = Количество истекших аукционов name: '&6Забрать просроченные / удалённые предметы' @@ -108,9 +116,7 @@ status-active: '&aАктивное' status-expired: '&cИстёкшие' selected-listing-name: '&l&cУправление товаром' -duplicate-item: '&aНажмите, чтобы скопировать предмет в инвентарь' -listing-expired: '&eНажмите, чтобы сделать товар &cистёкшим' -listing-active: '&eНажмите, чтобы сделать товар &aактивным' +copy-item: '&aДобавить предмет в инвентарь' delete-item: '&cНажмите, чтобы удалить товар с аукциона' # Pagination items @@ -133,7 +139,7 @@ sell-description: main-description: name: '&6Что это за страница?' lore: - - '&aЭто аукционный, здесь можно' + - '&aЭто аукционный дом, здесь можно' - '&aпродавать и покупать предметы' - '' - '&aАукцион также отличный способ заработать' diff --git a/resources/language/tr_TR.yml b/resources/language/tr_TR.yml index 56d8efe..2df7ac1 100644 --- a/resources/language/tr_TR.yml +++ b/resources/language/tr_TR.yml @@ -118,9 +118,7 @@ status-active: "&aAktif" status-expired: "&cSüresi Dolmuş" selected-listing-name: "&l&cListeyi Yönet" -duplicate-item: "&aÖğeyi envantere kopyala" -listing-expired: "&eListelemenin &csüresinin dolmasını&e sağla" -listing-active: "&eListelemenin &aaktif etmesini&e sağla" +copy-item: "&aÖğeyi envantere kopyala" delete-item: "&cÖğeyi ve listeyi sil" # Pagination items diff --git a/resources/statements/mysql.sql b/resources/statements/mysql.sql index a019edc..d582c01 100644 --- a/resources/statements/mysql.sql +++ b/resources/statements/mysql.sql @@ -2,16 +2,43 @@ -- #{ auctionhouse -- # { init + +-- # { tables +CREATE TABLE IF NOT EXISTS players( + uuid BINARY(16) PRIMARY KEY, + username VARCHAR(16) NOT NULL +); +-- #& CREATE TABLE IF NOT EXISTS listings( id INTEGER PRIMARY KEY AUTO_INCREMENT, - uuid CHAR(36), - username VARCHAR(36), + player_uuid BINARY(16), + item BLOB NOT NULL, price INT, - item JSON, - created INT, - end_time INT, - expired BOOLEAN DEFAULT FALSE + created_at BIGINT, + expires_at BIGINT, + expired BOOLEAN DEFAULT FALSE, + FOREIGN KEY (player_uuid) REFERENCES players(uuid) ON DELETE CASCADE ); +-- # } + +-- # { events +-- # :duration int +DROP PROCEDURE IF EXISTS expire_listings; +-- #& +CREATE PROCEDURE expire_listings() +BEGIN + UPDATE listings SET expired = TRUE WHERE expired = FALSE AND expires_at <= UNIX_TIMESTAMP(); + IF :duration > 0 THEN + DELETE FROM listings + WHERE expired = TRUE AND (expires_at + 120) <= UNIX_TIMESTAMP(); + END IF; +END; +-- #& +CREATE EVENT IF NOT EXISTS expire_event +ON SCHEDULE EVERY 1 MINUTE +DO CALL expire_listings(); +-- # } + -- # } -- # { count @@ -20,6 +47,11 @@ CREATE TABLE IF NOT EXISTS listings( SELECT COUNT(*) FROM listings; -- # } +-- # { username +-- # :username string +SELECT COUNT(*) FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE players.username = :username; +-- # } + -- # { active -- # { all @@ -28,14 +60,13 @@ SELECT COUNT(*) FROM listings WHERE expired = FALSE; -- # { uuid -- # :uuid string -SELECT COUNT(*) FROM listings WHERE uuid = :uuid AND expired = FALSE; +SELECT COUNT(*) FROM listings WHERE player_uuid = :uuid AND expired = FALSE; -- # } -- # { username -- # :username string -SELECT COUNT(*) FROM listings WHERE username = :username AND expired = FALSE; +SELECT COUNT(*) FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE players.username = :username AND expired = FALSE; -- # } - -- # } -- # { expired @@ -46,7 +77,12 @@ SELECT COUNT(*) FROM listings WHERE expired = TRUE; -- # { uuid -- # :uuid string -SELECT COUNT(*) FROM listings WHERE uuid = :uuid AND expired = TRUE; +SELECT COUNT(*) FROM listings WHERE player_uuid = :uuid AND expired = TRUE; +-- # } + +-- # { username +-- # :username string +SELECT COUNT(*) FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE players.username = :username AND expired = TRUE; -- # } -- # } @@ -56,36 +92,43 @@ SELECT COUNT(*) FROM listings WHERE uuid = :uuid AND expired = TRUE; -- # { fetch -- # { all --- # :id int --- # :limit int -SELECT * FROM listings LIMIT :id, :limit; +-- # :id int +-- # :limit int +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid LIMIT :id, :limit; -- # } -- # { id --- # :id int -SELECT * FROM listings WHERE id = :id; +-- # :id int +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE id = :id; +-- # } + +-- # { username +-- # :id int +-- # :limit int +-- # :username string +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE players.username = :username LIMIT :id, :limit; -- # } -- # { active -- # { next --- # :id int --- # :limit int -SELECT * FROM listings WHERE expired = FALSE LIMIT :id, :limit; +-- # :id int +-- # :limit int +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE listings.expired = FALSE LIMIT :id, :limit; -- # } -- # { uuid --- # :id int --- # :limit int --- # :uuid string -SELECT * FROM listings WHERE uuid = :uuid AND expired = FALSE LIMIT :id, :limit; +-- # :id int +-- # :limit int +-- # :uuid string +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE player_uuid = :uuid AND expired = FALSE LIMIT :id, :limit; -- # } -- # { username --- # :id int --- # :limit int --- # :username string -SELECT * FROM listings WHERE username = :username AND expired = FALSE LIMIT :id, :limit; +-- # :id int +-- # :limit int +-- # :username string +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE players.username = :username AND expired = FALSE LIMIT :id, :limit; -- # } -- # } @@ -93,16 +136,16 @@ SELECT * FROM listings WHERE username = :username AND expired = FALSE LIMIT :id, -- # { expired -- # { next --- # :id int --- # :limit int -SELECT * FROM listings WHERE expired = TRUE LIMIT :id, :limit; +-- # :id int +-- # :limit int +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE expired = TRUE LIMIT :id, :limit; -- # } -- # { uuid --- # :id int --- # :limit int --- # :uuid string -SELECT * FROM listings WHERE uuid = :uuid AND expired = TRUE LIMIT :id, :limit; +-- # :id int +-- # :limit int +-- # :uuid string +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE player_uuid = :uuid AND expired = TRUE LIMIT :id, :limit; -- # } -- # } @@ -110,25 +153,68 @@ SELECT * FROM listings WHERE uuid = :uuid AND expired = TRUE LIMIT :id, :limit; -- # } -- # { delete --- # :id int + +-- # { id +-- # :id int DELETE FROM listings WHERE id = :id; +-- # } + +-- # { username +-- # :username string +DELETE listings FROM listings JOIN players ON listings.player_uuid = players.uuid +WHERE players.username = :username; +-- # } + +-- # } + + +-- # { expire + +-- # { id +-- # :id int +UPDATE listings SET expired = TRUE WHERE id = :id; +-- # } + +-- # { username +-- # :username string +UPDATE listings JOIN players ON listings.player_uuid = players.uuid SET listings.expired = TRUE +WHERE players.username = :username; +-- # } + +-- # { all +UPDATE listings SET expired = TRUE; +-- # } + -- # } --- # { expired --- # :id int --- # :expired bool -UPDATE listings SET expired = :expired WHERE id = :id; +-- # { relist + +-- # { username +-- # :expires_at int +-- # :username string +UPDATE listings JOIN players ON listings.player_uuid = players.uuid +SET listings.expired = FALSE, listings.expires_at = :expires_at +WHERE players.username = :username; +-- # } + +-- # { all +-- # :expires_at int +UPDATE listings SET expired = FALSE, expires_at = :expires_at; +-- # } + -- # } -- # { insert --- # :uuid string +-- # :player_uuid string -- # :username string --- # :price int -- # :item string --- # :created int --- # :end_time int --- # :expired bool -INSERT INTO listings(id, uuid, username, price, item, created, end_time, expired) VALUES (NULL, :uuid, :username, :price, :item, :created, :end_time, :expired); +-- # :price int +-- # :created_at int +-- # :expires_at int +INSERT INTO players(uuid, username) VALUES (:player_uuid, :username) +ON DUPLICATE KEY UPDATE username = VALUES(username); +-- #& +INSERT INTO listings(player_uuid, item, price, created_at, expires_at) VALUES (:player_uuid, :item, :price, :created_at, :expires_at); -- # } -- # } \ No newline at end of file diff --git a/resources/statements/sqlite.sql b/resources/statements/sqlite.sql index d693adc..f758d33 100644 --- a/resources/statements/sqlite.sql +++ b/resources/statements/sqlite.sql @@ -2,16 +2,25 @@ -- #{ auctionhouse -- # { init + +-- # { tables +CREATE TABLE IF NOT EXISTS players( + uuid BINARY(16) PRIMARY KEY, + username VARCHAR(16) NOT NULL +); +-- #& CREATE TABLE IF NOT EXISTS listings( id INTEGER PRIMARY KEY AUTOINCREMENT, - uuid CHAR(36), - username VARCHAR(36), + player_uuid BINARY(16), + item BLOB NOT NULL, price INT, - item TEXT, - created INT, - end_time INT, - expired BOOLEAN DEFAULT FALSE + created_at INT, + expires_at INT, + expired BOOLEAN DEFAULT FALSE, + FOREIGN KEY (player_uuid) REFERENCES players(uuid) ON DELETE CASCADE ); +-- # } + -- # } -- # { count @@ -20,6 +29,11 @@ CREATE TABLE IF NOT EXISTS listings( SELECT COUNT(*) FROM listings; -- # } +-- # { username +-- # :username string +SELECT COUNT(*) FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE players.username = :username; +-- # } + -- # { active -- # { all @@ -28,14 +42,13 @@ SELECT COUNT(*) FROM listings WHERE expired = FALSE; -- # { uuid -- # :uuid string -SELECT COUNT(*) FROM listings WHERE uuid = :uuid AND expired = FALSE; +SELECT COUNT(*) FROM listings WHERE player_uuid = :uuid AND expired = FALSE; -- # } -- # { username -- # :username string -SELECT COUNT(*) FROM listings WHERE username = :username AND expired = FALSE; +SELECT COUNT(*) FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE players.username = :username AND expired = FALSE; -- # } - -- # } -- # { expired @@ -46,7 +59,12 @@ SELECT COUNT(*) FROM listings WHERE expired = TRUE; -- # { uuid -- # :uuid string -SELECT COUNT(*) FROM listings WHERE uuid = :uuid AND expired = TRUE; +SELECT COUNT(*) FROM listings WHERE player_uuid = :uuid AND expired = TRUE; +-- # } + +-- # { username +-- # :username string +SELECT COUNT(*) FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE players.username = :username AND expired = TRUE; -- # } -- # } @@ -58,12 +76,19 @@ SELECT COUNT(*) FROM listings WHERE uuid = :uuid AND expired = TRUE; -- # { all -- # :id int -- # :limit int -SELECT * FROM listings LIMIT :id, :limit; +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid LIMIT :id, :limit; -- # } -- # { id -- # :id int -SELECT * FROM listings WHERE id = :id; +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE id = :id; +-- # } + +-- # { username +-- # :id int +-- # :limit int +-- # :username string +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE players.username = :username LIMIT :id, :limit; -- # } -- # { active @@ -71,21 +96,21 @@ SELECT * FROM listings WHERE id = :id; -- # { next -- # :id int -- # :limit int -SELECT * FROM listings WHERE expired = FALSE LIMIT :id, :limit; +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE listings.expired = FALSE LIMIT :id, :limit; -- # } -- # { uuid -- # :id int -- # :limit int -- # :uuid string -SELECT * FROM listings WHERE uuid = :uuid AND expired = FALSE LIMIT :id, :limit; +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE player_uuid = :uuid AND expired = FALSE LIMIT :id, :limit; -- # } -- # { username -- # :id int -- # :limit int -- # :username string -SELECT * FROM listings WHERE username = :username AND expired = FALSE LIMIT :id, :limit; +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE players.username = :username AND expired = FALSE LIMIT :id, :limit; -- # } -- # } @@ -95,14 +120,14 @@ SELECT * FROM listings WHERE username = :username AND expired = FALSE LIMIT :id, -- # { next -- # :id int -- # :limit int -SELECT * FROM listings WHERE expired = TRUE LIMIT :id, :limit; +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE expired = TRUE LIMIT :id, :limit; -- # } -- # { uuid -- # :id int -- # :limit int -- # :uuid string -SELECT * FROM listings WHERE uuid = :uuid AND expired = TRUE LIMIT :id, :limit; +SELECT listings.*, players.username FROM listings JOIN players ON listings.player_uuid = players.uuid WHERE player_uuid = :uuid AND expired = TRUE LIMIT :id, :limit; -- # } -- # } @@ -110,25 +135,75 @@ SELECT * FROM listings WHERE uuid = :uuid AND expired = TRUE LIMIT :id, :limit; -- # } -- # { delete --- # :id int + +-- # { id +-- # :id int DELETE FROM listings WHERE id = :id; +-- # } + +-- # { username +-- # :username string +DELETE FROM listings +WHERE player_uuid IN ( + SELECT uuid FROM players + WHERE username = :username +); +-- # } + +-- # } + +-- # { expire + +-- # { id +-- # :id int +UPDATE listings SET expired = TRUE WHERE id = :id; +-- # } + +-- # { username +-- # :username string +UPDATE listings SET expired = TRUE +WHERE player_uuid IN ( + SELECT uuid FROM players + WHERE players.username = :username +); +-- # } + +-- # { all +UPDATE listings SET expired = TRUE; +-- # } + -- # } --- # { expired --- # :id int --- # :expired bool -UPDATE listings SET expired = :expired WHERE id = :id; +-- # { relist + +-- # { username +-- # :expires_at int +-- # :username string +UPDATE listings SET expired = FALSE, expires_at = :expires_at +WHERE player_uuid IN ( + SELECT uuid FROM players + WHERE players.username = :username +); +-- # } + +-- # { all +-- # :expires_at int +UPDATE listings SET expired = FALSE, expires_at = :expires_at; +-- # } + -- # } -- # { insert --- # :uuid string +-- # :player_uuid string -- # :username string -- # :price int -- # :item string --- # :created int --- # :end_time int --- # :expired bool -INSERT INTO listings(id, uuid, username, price, item, created, end_time, expired) VALUES (NULL, :uuid, :username, :price, :item, :created, :end_time, :expired); +-- # :created_at int +-- # :expires_at int +INSERT INTO players(uuid, username) VALUES (:player_uuid, :username) +ON CONFLICT DO UPDATE SET username = :username; +-- #& +INSERT INTO listings(player_uuid, item, price, created_at, expires_at) VALUES (:player_uuid, :item, :price, :created_at, :expires_at); -- # } -- # } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/AHListing.php b/src/shock95x/auctionhouse/AHListing.php index a0d8883..f37bd47 100644 --- a/src/shock95x/auctionhouse/AHListing.php +++ b/src/shock95x/auctionhouse/AHListing.php @@ -4,17 +4,20 @@ namespace shock95x\auctionhouse; use pocketmine\item\Item; +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\UuidInterface; use shock95x\auctionhouse\utils\Settings; +use shock95x\auctionhouse\utils\Utils; class AHListing { public function __construct( private int $id, - private string $uuid, + private UuidInterface $seller, private int $price, private string $username, - private int $created, - private int $endTime, + private int $createTime, + private int $expireTime, private bool $expired, private Item $item, ) {} @@ -38,27 +41,32 @@ public function getSeller(): string { return $this->username; } - public function getSellerUUID() : string { - return $this->uuid; + public function getSellerUUID() : UuidInterface { + return $this->seller; } public function getCreatedTime(): int { - return $this->created; + return $this->createTime; } - public function setEndTime(int $time): void { - $this->endTime = $time; - } - - public function getEndTime(): int { - return $this->endTime; - } - - public function setExpired(bool $expired = true): void { - $this->expired = $expired; + public function getExpireTime(): int { + return $this->expireTime; } public function isExpired(): bool { return $this->expired; } + + public static function fromRow(array $row): self { + return new self( + $row["id"], + Uuid::fromBytes($row["player_uuid"]), + $row["price"], + $row["username"], + $row["created_at"], + $row["expires_at"], + boolval($row["expired"]), + Utils::deserializeItem($row["item"]) + ); + } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/AuctionHouse.php b/src/shock95x/auctionhouse/AuctionHouse.php index 083ad43..dadfd97 100644 --- a/src/shock95x/auctionhouse/AuctionHouse.php +++ b/src/shock95x/auctionhouse/AuctionHouse.php @@ -16,11 +16,9 @@ use pocketmine\utils\SingletonTrait; use shock95x\auctionhouse\commands\AHCommand; use shock95x\auctionhouse\database\Database; -use shock95x\auctionhouse\database\legacy\LegacyConverter; use shock95x\auctionhouse\economy\BedrockEconomyProvider; use shock95x\auctionhouse\economy\EconomyProvider; use shock95x\auctionhouse\economy\EconomySProvider; -use shock95x\auctionhouse\task\CheckLegacyTask; use shock95x\auctionhouse\tile\AHSign; use shock95x\auctionhouse\utils\Locale; use shock95x\auctionhouse\utils\Settings; @@ -57,13 +55,9 @@ public function onEnable(): void { TileFactory::getInstance()->register(AHSign::class, ["AHSign", "auctionhouse:sign"]); EnchantmentIdMap::getInstance()->register(self::FAKE_ENCH_ID, new Enchantment("Glow", 1, ItemFlags::ALL, ItemFlags::NONE, 1)); - $pluginManager = $this->getServer()->getPluginManager(); - - $this->database = new Database($this, $this->getConfig()); - $this->database->connect(); - - LegacyConverter::getInstance()->init($this->database); + $this->database = (new Database($this))->connect($this->getConfig()); + $pluginManager = $this->getServer()->getPluginManager(); $pluginManager->registerEvents(new EventListener(), $this); if($pluginManager->getPlugin(EconomySProvider::getName()) !== null) { @@ -79,9 +73,8 @@ public function onEnable(): void { } Settings::setCurrencySymbol($this->economyProvider->getCurrencySymbol()); }), 1); - UpdateNotifier::checkUpdate($this->getDescription()->getName(), $this->getDescription()->getVersion()); $this->getServer()->getCommandMap()->register($this->getDescription()->getName(), new AHCommand($this, "ah", "AuctionHouse command")); - $this->getScheduler()->scheduleDelayedTask(new CheckLegacyTask($this), 1); + UpdateNotifier::checkUpdate($this->getDescription()->getName(), $this->getDescription()->getVersion()); } public function onDisable(): void { diff --git a/src/shock95x/auctionhouse/EventListener.php b/src/shock95x/auctionhouse/EventListener.php index ef7bcf3..e3473f1 100644 --- a/src/shock95x/auctionhouse/EventListener.php +++ b/src/shock95x/auctionhouse/EventListener.php @@ -8,7 +8,7 @@ use pocketmine\event\Listener; use pocketmine\event\player\PlayerInteractEvent; use pocketmine\utils\TextFormat; -use shock95x\auctionhouse\menu\player\PlayerListingMenu; +use shock95x\auctionhouse\menu\player\PlayerListingsMenu; use shock95x\auctionhouse\menu\ShopMenu; use shock95x\auctionhouse\menu\type\AHMenu; use shock95x\auctionhouse\tile\AHSign; @@ -53,9 +53,9 @@ public function onPlayerInteract(PlayerInteractEvent $event): void { $tile = $block->getPosition()->getWorld()->getTile($block->getPosition()); if($tile instanceof AHSign) { if($tile->getType() == AHSign::TYPE_SHOP) { - AHMenu::open(new ShopMenu($player)); + (new ShopMenu($player))->open(); } else if($tile->getType() == AHSign::TYPE_PLAYER) { - AHMenu::open(new PlayerListingMenu($player, $tile->getValue())); + (new PlayerListingsMenu($player, $tile->getValue()))->open(); } } } diff --git a/src/shock95x/auctionhouse/category/defaults/BlockCategory.php b/src/shock95x/auctionhouse/category/defaults/BlockCategory.php index 56fc9db..c254e56 100644 --- a/src/shock95x/auctionhouse/category/defaults/BlockCategory.php +++ b/src/shock95x/auctionhouse/category/defaults/BlockCategory.php @@ -3,10 +3,9 @@ namespace shock95x\auctionhouse\category\defaults; +use pocketmine\block\VanillaBlocks; use pocketmine\item\Item; use pocketmine\item\ItemBlock; -use pocketmine\item\ItemFactory; -use pocketmine\item\ItemIds; use pocketmine\utils\TextFormat; use shock95x\auctionhouse\AHListing; use shock95x\auctionhouse\category\ICategory; @@ -26,6 +25,6 @@ public function getDisplayName(): string { } public function getMenuItem(): Item { - return ItemFactory::getInstance()->get(ItemIds::BRICK_BLOCK)->setCustomName(TextFormat::RESET . $this->getDisplayName()); + return VanillaBlocks::BRICKS()->asItem()->setCustomName(TextFormat::RESET . $this->getDisplayName()); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/category/defaults/PotionCategory.php b/src/shock95x/auctionhouse/category/defaults/PotionCategory.php index 7ddb3ca..8200737 100644 --- a/src/shock95x/auctionhouse/category/defaults/PotionCategory.php +++ b/src/shock95x/auctionhouse/category/defaults/PotionCategory.php @@ -26,6 +26,6 @@ public function getDisplayName(): string { } public function getMenuItem(): Item { - return VanillaItems::WATER_POTION()->setCustomName(TextFormat::RESET . $this->getDisplayName()); + return VanillaItems::POTION()->setCustomName(TextFormat::RESET . $this->getDisplayName()); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/commands/AHCommand.php b/src/shock95x/auctionhouse/commands/AHCommand.php index 7fd817d..900c2a1 100644 --- a/src/shock95x/auctionhouse/commands/AHCommand.php +++ b/src/shock95x/auctionhouse/commands/AHCommand.php @@ -7,35 +7,33 @@ use pocketmine\command\CommandSender; use pocketmine\player\Player; use shock95x\auctionhouse\commands\subcommand\AboutCommand; -use shock95x\auctionhouse\commands\subcommand\AdminCommand; +use shock95x\auctionhouse\commands\subcommand\admin\AdminCommand; use shock95x\auctionhouse\commands\subcommand\CategoryCommand; -use shock95x\auctionhouse\commands\subcommand\ConvertCommand; use shock95x\auctionhouse\commands\subcommand\ExpiredCommand; use shock95x\auctionhouse\commands\subcommand\ListingsCommand; use shock95x\auctionhouse\commands\subcommand\ReloadCommand; use shock95x\auctionhouse\commands\subcommand\SellCommand; use shock95x\auctionhouse\commands\subcommand\ShopCommand; -use shock95x\auctionhouse\commands\subcommand\TestCommand; use shock95x\auctionhouse\menu\ShopMenu; use shock95x\auctionhouse\menu\type\AHMenu; class AHCommand extends BaseCommand { - protected function prepare(): void { - $this->registerSubCommand(new ShopCommand("shop", "Shows AH shop menu")); - $this->registerSubCommand(new AdminCommand("admin", "Opens AH admin menu")); - $this->registerSubCommand(new SellCommand("sell", "Sell item in hand to the AH")); - $this->registerSubCommand(new CategoryCommand("category", "Opens category menu")); - $this->registerSubCommand(new ListingsCommand("listings", "Shows player listings")); - $this->registerSubCommand(new ExpiredCommand("expired", "Shows expired listings")); - $this->registerSubCommand(new ReloadCommand("reload", "Reload plugin configuration files")); - $this->registerSubCommand(new AboutCommand("about", "Plugin information")); - $this->registerSubCommand(new ConvertCommand("convert", "Legacy DB conversion")); + protected function prepare() : void { + $this->setPermission("auctionhouse.command"); + $this->registerSubCommand(new ShopCommand($this->plugin, "shop", "Shows AH shop menu")); + $this->registerSubCommand(new AdminCommand($this->plugin, "admin", "Opens AH admin menu")); + $this->registerSubCommand(new SellCommand($this->plugin, "sell", "Sell item in hand to the AH")); + $this->registerSubCommand(new CategoryCommand($this->plugin, "category", "Opens category menu")); + $this->registerSubCommand(new ListingsCommand($this->plugin, "listings", "Shows player listings")); + $this->registerSubCommand(new ExpiredCommand($this->plugin, "expired", "Shows expired listings")); + $this->registerSubCommand(new ReloadCommand($this->plugin, "reload", "Reload plugin configuration files")); + $this->registerSubCommand(new AboutCommand($this->plugin, "about", "Plugin information")); } public function onRun(CommandSender $sender, string $aliasUsed, array $args): void { if(count($args) == 0 && $sender instanceof Player) { - AHMenu::open(new ShopMenu($sender)); + (new ShopMenu($sender))->open(); } } } diff --git a/src/shock95x/auctionhouse/commands/arguments/CategoryArgument.php b/src/shock95x/auctionhouse/commands/arguments/CategoryArgument.php index b773be2..ea3fcb7 100644 --- a/src/shock95x/auctionhouse/commands/arguments/CategoryArgument.php +++ b/src/shock95x/auctionhouse/commands/arguments/CategoryArgument.php @@ -19,6 +19,10 @@ public function getTypeName(): string { return "name"; } + public function getEnumName() : string { + return "category"; + } + public function parse(string $argument, CommandSender $sender): ICategory { return Category::get($argument); } diff --git a/src/shock95x/auctionhouse/commands/subcommand/AboutCommand.php b/src/shock95x/auctionhouse/commands/subcommand/AboutCommand.php index 1b070f9..1729936 100644 --- a/src/shock95x/auctionhouse/commands/subcommand/AboutCommand.php +++ b/src/shock95x/auctionhouse/commands/subcommand/AboutCommand.php @@ -10,9 +10,11 @@ class AboutCommand extends BaseSubCommand { - protected function prepare(): void {} + protected function prepare() : void{ + $this->setPermission("auctionhouse.command.about"); + } public function onRun(CommandSender $sender, string $aliasUsed, array $args): void { - $sender->sendMessage(Utils::prefixMessage(TextFormat::BLUE . "This server is running " . TextFormat::GOLD . "AuctionHouse v" . $this->getOwningPlugin()->getDescription()->getVersion() . TextFormat::BLUE . " by " . TextFormat::GREEN . "Shock95x")); + $sender->sendMessage(Utils::prefixMessage(TextFormat::BLUE . "This server is running " . TextFormat::GOLD . "AuctionHouse v" . $this->getOwningPlugin()->getDescription()->getVersion() . TextFormat::BLUE . " by " . TextFormat::GREEN . "Shock95")); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/commands/subcommand/CategoryCommand.php b/src/shock95x/auctionhouse/commands/subcommand/CategoryCommand.php index 520d611..e3993e4 100644 --- a/src/shock95x/auctionhouse/commands/subcommand/CategoryCommand.php +++ b/src/shock95x/auctionhouse/commands/subcommand/CategoryCommand.php @@ -28,12 +28,12 @@ protected function prepare(): void { public function onRun(CommandSender $sender, string $aliasUsed, array $args): void { assert($sender instanceof Player); if(!isset($args["name"])) { - AHMenu::open(new CategoryListMenu($sender, false)); + (new CategoryListMenu($sender))->open(); return; } $category = $args["name"]; if($category instanceof ICategory) { - AHMenu::open(new CategoryMenu($sender, $category)); + (new CategoryMenu($sender, $category))->open(); } } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/commands/subcommand/ConvertCommand.php b/src/shock95x/auctionhouse/commands/subcommand/ConvertCommand.php deleted file mode 100644 index 9d92ba9..0000000 --- a/src/shock95x/auctionhouse/commands/subcommand/ConvertCommand.php +++ /dev/null @@ -1,28 +0,0 @@ -addConstraint(new ConsoleRequiredConstraint($this)); - } - - public function onRun(CommandSender $sender, string $aliasUsed, array $args): void { - Await::f2c(function () use ($sender) { - $converter = LegacyConverter::getInstance(); - if (yield from $converter->isLegacy()) { - $sender->sendMessage("Starting conversion..."); - yield from $converter->convert(); - $sender->sendMessage("Conversion done!"); - } - }); - } -} \ No newline at end of file diff --git a/src/shock95x/auctionhouse/commands/subcommand/ExpiredCommand.php b/src/shock95x/auctionhouse/commands/subcommand/ExpiredCommand.php index e0c2ff3..1e9d2f8 100644 --- a/src/shock95x/auctionhouse/commands/subcommand/ExpiredCommand.php +++ b/src/shock95x/auctionhouse/commands/subcommand/ExpiredCommand.php @@ -19,6 +19,6 @@ protected function prepare(): void { public function onRun(CommandSender $sender, string $aliasUsed, array $args): void { assert($sender instanceof Player); - AHMenu::open(new ExpiredMenu($sender, false)); + (new ExpiredMenu($sender))->open(); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/commands/subcommand/ListingsCommand.php b/src/shock95x/auctionhouse/commands/subcommand/ListingsCommand.php index dfd8976..d2c4419 100644 --- a/src/shock95x/auctionhouse/commands/subcommand/ListingsCommand.php +++ b/src/shock95x/auctionhouse/commands/subcommand/ListingsCommand.php @@ -10,7 +10,7 @@ use pocketmine\player\Player; use shock95x\auctionhouse\commands\arguments\PlayerArgument; use shock95x\auctionhouse\menu\ListingsMenu; -use shock95x\auctionhouse\menu\player\PlayerListingMenu; +use shock95x\auctionhouse\menu\player\PlayerListingsMenu; use shock95x\auctionhouse\menu\type\AHMenu; use shock95x\auctionhouse\utils\Locale; @@ -28,7 +28,7 @@ protected function prepare(): void { public function onRun(CommandSender $sender, string $aliasUsed, array $args): void { assert($sender instanceof Player); if(!isset($args["player"])) { - AHMenu::open(new ListingsMenu($sender, false)); + (new ListingsMenu($sender))->open(); return; } $player = strtolower($args["player"]); @@ -36,6 +36,6 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo Locale::sendMessage($sender, "player-listings-usage"); return; } - AHMenu::open(new PlayerListingMenu($sender, $args["player"])); + (new PlayerListingsMenu($sender, $args["player"]))->open(); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/commands/subcommand/SellCommand.php b/src/shock95x/auctionhouse/commands/subcommand/SellCommand.php index 5219009..19dafc0 100644 --- a/src/shock95x/auctionhouse/commands/subcommand/SellCommand.php +++ b/src/shock95x/auctionhouse/commands/subcommand/SellCommand.php @@ -11,8 +11,9 @@ use pocketmine\command\CommandSender; use pocketmine\player\Player; use pocketmine\scheduler\ClosureTask; +use shock95x\auctionhouse\AHListing; use shock95x\auctionhouse\AuctionHouse; -use shock95x\auctionhouse\database\storage\DataStorage; +use shock95x\auctionhouse\database\Database; use shock95x\auctionhouse\economy\EconomyProvider; use shock95x\auctionhouse\event\ItemListedEvent; use shock95x\auctionhouse\manager\CooldownManager; @@ -35,6 +36,8 @@ protected function prepare(): void { public function onRun(CommandSender $sender, string $aliasUsed, array $args): void { assert($sender instanceof Player); Await::f2c(function () use ($sender, $args) { + /** @var Database $database */ + $database = $this->plugin->getDatabase(); $item = $sender->getInventory()->getItemInHand(); if($item->isNull()) { Locale::sendMessage($sender, "no-item"); @@ -53,7 +56,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo return; } $price = $args["price"]; - $listingCount = yield from Await::promise(fn($result) => DataStorage::getInstance()->getActiveCountByPlayer($sender, $result)); + $listingCount = yield from Await::promise(fn($result) => $database->getActiveCountByPlayer($sender->getUniqueId(), $result)); if($listingCount >= (Utils::getMaxListings($sender))) { $sender->sendMessage(str_ireplace(["{MAX}"], [Utils::getMaxListings($sender)], Locale::get($sender, "max-listings", true))); return; @@ -79,9 +82,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo $listingPrice = Settings::getListingPrice(); if($listingPrice > 0) { - $subtractMoneyOk = yield from Await::promise(function($result) use ($listingPrice, $sender) { - $this->getEconomy()->subtractMoney($sender, $listingPrice, $result); - }); + $subtractMoneyOk = yield from $this->getEconomy()->subtractMoneyAsync($sender, $listingPrice); if(!$subtractMoneyOk) { return; } @@ -91,9 +92,7 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo $event->call(); if($event->isCancelled()) { // refund the listing price - $addMoneyOk = yield from Await::promise(function($result) use ($listingPrice, $sender) { - $this->getEconomy()->addMoney($sender, $listingPrice, $result); - }); + $addMoneyOk = yield from $this->getEconomy()->addMoneyAsync($sender, $listingPrice); if(!$addMoneyOk) { // TODO we failed to refund; what now? } @@ -103,7 +102,8 @@ public function onRun(CommandSender $sender, string $aliasUsed, array $args): vo $count = $item->getCount(); Utils::removeItem($sender, $item); - $listing = yield from DataStorage::getInstance()->createListingAsync($sender, $item->setCount($count), (int) $price); + /** @var AHListing $listing */ + $listing = yield from $database->createListingAsync($sender, $item->setCount($count), (int) $price); $sender->sendMessage(str_ireplace(["{PLAYER}", "{ITEM}", "{PRICE}", "{AMOUNT}"], [$sender->getName(), $item->getName(), $listing->getPrice(true, Settings::formatPrice()), $count], Locale::get($sender, "item-listed", true))); }); } diff --git a/src/shock95x/auctionhouse/commands/subcommand/ShopCommand.php b/src/shock95x/auctionhouse/commands/subcommand/ShopCommand.php index 0f78044..1c8ba46 100644 --- a/src/shock95x/auctionhouse/commands/subcommand/ShopCommand.php +++ b/src/shock95x/auctionhouse/commands/subcommand/ShopCommand.php @@ -19,6 +19,6 @@ protected function prepare(): void { public function onRun(CommandSender $sender, string $aliasUsed, array $args): void { assert($sender instanceof Player); - AHMenu::open(new ShopMenu($sender)); + (new ShopMenu($sender))->open(); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/commands/subcommand/admin/AdminCommand.php b/src/shock95x/auctionhouse/commands/subcommand/admin/AdminCommand.php new file mode 100644 index 0000000..a96e3df --- /dev/null +++ b/src/shock95x/auctionhouse/commands/subcommand/admin/AdminCommand.php @@ -0,0 +1,26 @@ +setPermission("auctionhouse.command.admin"); + $this->registerSubCommand(new AdminListingsSubCommand($this->plugin, "listings", "View a player's listings")); + $this->registerSubCommand(new AdminRelistAllSubCommand($this->plugin, "relistall", "Relist all items")); + $this->registerSubCommand(new AdminReturnAllSubCommand($this->plugin, "returnall", "Return all items")); + } + + public function onRun(CommandSender $sender, string $aliasUsed, array $args) : void{ + if($sender instanceof Player){ + (new AdminMenu($sender))->open(); + } + } +} \ No newline at end of file diff --git a/src/shock95x/auctionhouse/commands/subcommand/AdminCommand.php b/src/shock95x/auctionhouse/commands/subcommand/admin/AdminListingsSubCommand.php similarity index 55% rename from src/shock95x/auctionhouse/commands/subcommand/AdminCommand.php rename to src/shock95x/auctionhouse/commands/subcommand/admin/AdminListingsSubCommand.php index 35a059e..3ec2975 100644 --- a/src/shock95x/auctionhouse/commands/subcommand/AdminCommand.php +++ b/src/shock95x/auctionhouse/commands/subcommand/admin/AdminListingsSubCommand.php @@ -1,24 +1,24 @@ setPermission("auctionhouse.command.admin"); $this->addConstraint(new InGameRequiredConstraint($this)); + $this->registerArgument(0, new PlayerArgument("player", false)); } public function onRun(CommandSender $sender, string $aliasUsed, array $args): void { assert($sender instanceof Player); - AHMenu::open(new AdminMenu($sender, false)); + (new AdminListingsMenu($sender, $args["player"]))->open(); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/commands/subcommand/admin/AdminRelistAllSubCommand.php b/src/shock95x/auctionhouse/commands/subcommand/admin/AdminRelistAllSubCommand.php new file mode 100644 index 0000000..10736a2 --- /dev/null +++ b/src/shock95x/auctionhouse/commands/subcommand/admin/AdminRelistAllSubCommand.php @@ -0,0 +1,23 @@ +getDatabase(); + $expireTime = Utils::getExpireTime(time()); + yield from $database->getConnector()->asyncChange(Query::RELIST_ALL, ["expires_at" => $expireTime]); + }); + } +} \ No newline at end of file diff --git a/src/shock95x/auctionhouse/commands/subcommand/admin/AdminReturnAllSubCommand.php b/src/shock95x/auctionhouse/commands/subcommand/admin/AdminReturnAllSubCommand.php new file mode 100644 index 0000000..1b17b6a --- /dev/null +++ b/src/shock95x/auctionhouse/commands/subcommand/admin/AdminReturnAllSubCommand.php @@ -0,0 +1,21 @@ +getDatabase(); + yield from $database->getConnector()->asyncChange(Query::EXPIRE_ALL); + }); + } +} \ No newline at end of file diff --git a/src/shock95x/auctionhouse/database/Database.php b/src/shock95x/auctionhouse/database/Database.php index 7a942a1..b81f7e5 100644 --- a/src/shock95x/auctionhouse/database/Database.php +++ b/src/shock95x/auctionhouse/database/Database.php @@ -5,104 +5,262 @@ use Generator; use pocketmine\item\Item; +use pocketmine\player\Player; use pocketmine\utils\Config; use poggit\libasynql\DataConnector; use poggit\libasynql\libasynql; +use poggit\libasynql\result\SqlChangeResult; +use poggit\libasynql\result\SqlInsertResult; +use poggit\libasynql\result\SqlSelectResult; use poggit\libasynql\SqlError; +use poggit\libasynql\SqlResult; use poggit\libasynql\SqlThread; +use Ramsey\Uuid\UuidInterface; use shock95x\auctionhouse\AHListing; use shock95x\auctionhouse\AuctionHouse; +use shock95x\auctionhouse\database\legacy\LegacyConverter; use shock95x\auctionhouse\database\storage\DataStorage; -use shock95x\auctionhouse\task\ListingExpireTask; +use shock95x\auctionhouse\event\AuctionStartEvent; +use shock95x\auctionhouse\task\SQLiteExpireTask; +use shock95x\auctionhouse\utils\Settings; +use shock95x\auctionhouse\utils\Utils; use SOFe\AwaitGenerator\Await; -class Database { +enum DatabaseType: string { + case MySQL = "mysql"; + case SQLite = "sqlite"; +} - private string $type; +class Database { - private AuctionHouse $plugin; - private Config $config; + private DatabaseType $type; private DataConnector $connector; + private AuctionHouse $plugin; - public function __construct(AuctionHouse $plugin, Config $config) { + public function __construct(AuctionHouse $plugin) { $this->plugin = $plugin; - $this->config = $config; } - public function connect(): self { + public function connect(Config $config): self { try { - $this->type = $this->config->getNested("database.type"); - $this->connector = libasynql::create($this->plugin, $this->config->get("database"), [ + $this->type = DatabaseType::from($config->getNested("database.type")); + $this->connector = libasynql::create($this->plugin, $config->get("database"), [ "sqlite" => "statements/sqlite.sql", "mysql" => "statements/mysql.sql" ], true); - $this->connector->executeGeneric(Query::INIT); } catch(SqlError $error) { $this->plugin->getLogger()->error($error->getMessage()); - } finally { - $this->connector->waitAll(); - DataStorage::getInstance()->init($this); - $this->plugin->getScheduler()->scheduleRepeatingTask(new ListingExpireTask($this), 1200); } + Await::f2c(function () { + yield from $this->executeMultiAsync(Query::INIT); + LegacyConverter::getInstance()->init($this); + yield from LegacyConverter::getInstance()->convert(); + if($this->type == DatabaseType::SQLite) { + yield from $this->asyncChangeRaw("PRAGMA foreign_keys = ON;"); + $this->plugin->getScheduler()->scheduleRepeatingTask(new SQLiteExpireTask($this), 1200); + } else if($this->type == DatabaseType::MySQL) { + yield from $this->connector->asyncChange("auctionhouse.init.events", ["duration" => Settings::getExpiredDuration()]); + } + }); + $this->connector->waitAll(); + DataStorage::getInstance()->init($this); return $this; } - public function fetchAll(): Generator { - $this->connector->executeSelect(Query::FETCH_ALL, [], yield, yield Await::REJECT); - return yield Await::ONCE; + public function getConnector(): DataConnector { + return $this->connector; } - public function setExpired(int $id, bool $expired = true, ?callable $onSuccess = null, ?callable $onError = null): void { - $this->connector->executeGeneric(Query::SET_EXPIRED, ["id" => $id, "expired" => $expired]); - } - - public function delete(int $id, ?callable $onSuccess = null, ?callable $onError = null): void { - $this->connector->executeGeneric(Query::DELETE, ["id" => $id], $onSuccess, $onError); + public function getType(): DatabaseType { + return $this->type; } - public function close(): void { - $this->connector?->waitAll(); - $this->connector?->close(); + $this->connector->waitAll(); + $this->connector->close(); } - public function getConnector(): DataConnector { - return $this->connector; + public function getListingById(int $id, callable $callback): void { + $this->connector->executeSelect(Query::FETCH_ID, ["id" => $id], function(array $rows) use ($callback): void { + $callback(empty($rows) ? null : AHListing::fromRow($rows[0])); + }); } - public function getType(): string { - return $this->type; + public function getListings(callable $callback, int $offset = 0, int $limit = 45) { + $this->connector->executeSelect(Query::FETCH_ALL, ["id" => $offset, "limit" => $limit], function(array $rows) use ($callback): void { + /** @var AHListing[] $listings */ + $listings = []; + foreach ($rows as $listing) { + $listings[] = AHListing::fromRow($listing); + } + $callback($listings); + }); } - public function asyncSelectRaw(string $query, array $args = []): Generator { - return yield from Await::promise(function ($resolve, $reject) use ($query, $args) { - $this->connector->executeImplRaw([$query], [$args], [SqlThread::MODE_SELECT], $resolve, $reject); + public function getListingsByUsername(callable $callback, string $username, int $offset = 0, int $limit = 45): void { + $this->connector->executeSelect(Query::FETCH_USERNAME, ["username" => $username, "id" => $offset, "limit" => $limit], function(array $rows) use ($callback): void { + /** @var AHListing[] $listings */ + $listings = []; + foreach ($rows as $listing) { + $listings[] = AHListing::fromRow($listing); + } + $callback($listings); }); } - public function asyncGenericRaw(string $query, array $args = []): Generator { - return yield from Await::promise(function ($resolve, $reject) use ($query, $args) { - $this->connector->executeImplRaw([$query], [$args], [SqlThread::MODE_GENERIC], $resolve, $reject); + public function getActiveListings(callable $callback, int $offset = 0, int $limit = 45) { + $this->connector->executeSelect(Query::FETCH_ACTIVE_NEXT, ["id" => $offset, "limit" => $limit], function(array $rows) use ($callback): void { + /** @var AHListing[] $listings */ + $listings = []; + foreach ($rows as $listing) { + $listings[] = AHListing::fromRow($listing); + } + $callback($listings); }); } - public function asyncChangeRaw(string $query, array $args = []): Generator { - return yield from Await::promise(function ($resolve, $reject) use ($query, $args) { - $this->connector->executeImplRaw([$query], [$args], [SqlThread::MODE_CHANGE], $resolve, $reject); + public function getActiveListingsByUsername(callable $callback, string $username, int $offset = 0, int $limit = 45): void { + $this->connector->executeSelect(Query::FETCH_ACTIVE_USERNAME, ["username" => $username, "id" => $offset, "limit" => $limit], function(array $rows) use ($callback): void { + /** @var AHListing[] $listings */ + $listings = []; + foreach ($rows as $listing) { + $listings[] = AHListing::fromRow($listing); + } + $callback($listings); + }); + } + + public function getActiveListingsByPlayer(callable $callback, UuidInterface $player, int $offset = 0, int $limit = 45): void { + $this->connector->executeSelect(Query::FETCH_ACTIVE_UUID, ["uuid" => $player->getBytes(), "id" => $offset, "limit" => $limit], function(array $rows) use ($callback): void { + /** @var AHListing[] $listings */ + $listings = []; + foreach ($rows as $listing) { + $listings[] = AHListing::fromRow($listing); + } + $callback($listings); }); } - public function createListingFromRows(array $rows): AHListing { - return new AHListing( - $rows["id"], - $rows["uuid"], - $rows["price"], - $rows["username"], - $rows["created"], - $rows["end_time"], - boolval($rows["expired"]), - Item::jsonDeserialize(json_decode($rows["item"], true)) + public function getExpiredListingsByPlayer(callable $callback, UuidInterface $player, int $offset = 0, int $limit = 45): void { + $this->connector->executeSelect(Query::FETCH_EXPIRED_UUID, ["uuid" => $player->getBytes(), "id" => $offset, "limit" => $limit], function(array $rows) use ($callback): void { + /** @var AHListing[] $listings */ + $listings = []; + foreach ($rows as $listing) { + $listings[] = AHListing::fromRow($listing); + } + $callback($listings); + }, fn() => $callback([])); + } + + public function getListingsCount(callable $callback): void { + $this->connector->executeSelect(Query::COUNT_ALL, [], function(array $rows) use ($callback): void { + $callback($rows[0]["COUNT(*)"]); + }, fn() => $callback(false)); + } + + public function getActiveListingsCount(callable $callback) { + $this->connector->executeSelect(Query::COUNT_ACTIVE, [], function(array $rows) use ($callback): void { + $callback($rows[0]["COUNT(*)"]); + }, fn() => $callback(false)); + } + + public function getActiveCountByPlayer(UuidInterface $player, callable $callback) { + $this->connector->executeSelect(Query::COUNT_ACTIVE_UUID, ["uuid" => $player->getBytes()], function(array $rows) use ($callback): void { + $callback($rows[0]["COUNT(*)"]); + }, fn() => $callback(false)); + } + + public function getActiveCountByUsername(string $username, callable $callback) { + $this->connector->executeSelect(Query::COUNT_ACTIVE_USERNAME, ["username" => $username], function(array $rows) use ($callback): void { + $callback($rows[0]["COUNT(*)"]); + }, fn() => $callback(false)); + } + + public function getExpiredCountByUsername(string $username, callable $callback) { + $this->connector->executeSelect(Query::COUNT_EXPIRED_USERNAME, ["username" => $username], function(array $rows) use ($callback): void { + $callback($rows[0]["COUNT(*)"]); + }, fn() => $callback(false)); + } + + public function getListingsCountByUsername(string $username, callable $callback) { + $this->connector->executeSelect(Query::COUNT_USERNAME, ["username" => $username], function(array $rows) use ($callback): void { + $callback($rows[0]["COUNT(*)"]); + }, fn() => $callback(false)); + } + + public function getExpiredCount(callable $callback) { + $this->connector->executeSelect(Query::COUNT_EXPIRED, [], function(array $rows) use ($callback): void { + $callback($rows[0]["COUNT(*)"]); + }, fn() => $callback(false)); + } + + public function getExpiredCountByPlayer(UuidInterface $player, callable $callback) { + $this->connector->executeSelect(Query::COUNT_EXPIRED_UUID, ["uuid" => $player->getBytes()], function(array $rows) use ($callback): void { + $callback($rows[0]["COUNT(*)"]); + }, fn() => $callback(false)); + } + + public function setExpired(int $id, callable $callback) { + $this->connector->executeChange(Query::EXPIRE_ID, ["id" => $id], $callback, fn() => $callback(false)); + } + + public function removeListing(int $id, callable $callback): void { + $this->connector->executeChange(Query::DELETE_ID, ["id" => $id], $callback, fn() => $callback(false)); + } + + public function createListing(Player $player, Item $item, int $price, callable $callback): void { + $username = $player->getName(); + $uuid = $player->getUniqueId(); + $createdTime = time(); + $expireTime = Utils::getExpireTime($createdTime); + $this->connector->executeMulti(Query::INSERT, [ + "player_uuid" => $uuid->getBytes(), + "username" => $username, + "price" => $price, + "item" => Utils::serializeItem($item), + "created_at" => $createdTime, + "expires_at" => $expireTime], + SqlThread::MODE_INSERT, + function($results) use ($expireTime, $item, $createdTime, $username, $price, $uuid, $callback) { + /** @var SqlInsertResult[] $results */ + $id = $results[1]->getInsertId(); + $listing = new AHListing($id, $uuid, $price, $username, $createdTime, $expireTime, false, $item); + (new AuctionStartEvent($listing))->call(); + $callback($listing); + }, fn() => $callback(null) ); } + + public function setExpiredAsync(int $id): Generator { + return yield from Await::promise(fn($res) => $this->setExpired($id, $res)); + } + + public function removeListingAsync(int $id): Generator { + return yield from Await::promise(fn($res) => $this->removeListing($id, $res)); + } + + public function createListingAsync(Player $player, Item $item, int $price): Generator { + return yield from Await::promise(fn($cb) => $this->createListing($player, $item, $price, $cb)); + } + + public function asyncGenericRaw(string $query, array $args = []): Generator { + return yield from Await::promise(fn ($resolve, $reject) => $this->connector->executeImplRaw([$query], [$args], [SqlThread::MODE_GENERIC], $resolve, $reject)); + } + + public function asyncChangeRaw(string $query, array $args = []): Generator { + return yield from Await::promise(fn ($resolve, $reject) => $this->connector->executeImplRaw([$query], [$args], [SqlThread::MODE_CHANGE], $resolve, $reject)); + } + + public function asyncInsertRaw(string $query, array $args = []): Generator { + return yield from Await::promise(fn ($resolve, $reject) => $this->connector->executeImplRaw([$query], [$args], [SqlThread::MODE_INSERT], $resolve, $reject)); + } + + public function asyncSelectRaw(string $query, array $args = []): Generator { + return yield from Await::promise(fn ($resolve, $reject) => $this->connector->executeImplRaw([$query], [$args], [SqlThread::MODE_SELECT], $resolve, $reject)); + } + + public function executeMultiAsync(string $queryName, array $args = [], int $mode = SqlThread::MODE_GENERIC): Generator { + return yield from Await::promise(fn ($resolve, $reject) => $this->connector->executeMulti($queryName, [$args], $mode , $resolve, $reject)); + } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/database/Query.php b/src/shock95x/auctionhouse/database/Query.php index ba00ca4..a474390 100644 --- a/src/shock95x/auctionhouse/database/Query.php +++ b/src/shock95x/auctionhouse/database/Query.php @@ -3,25 +3,36 @@ namespace shock95x\auctionhouse\database; -class Query{ +class Query { + + const INIT = "auctionhouse.init.tables"; - const INIT = "auctionhouse.init"; const INSERT = "auctionhouse.insert"; - const DELETE = "auctionhouse.delete"; - const SET_EXPIRED = "auctionhouse.expired"; + + const EXPIRE_ALL = "auctionhouse.expire.all"; + const EXPIRE_ID = "auctionhouse.expire.id"; + const EXPIRE_USERNAME = "auctionhouse.expire.username"; + + const RELIST_ALL = "auctionhouse.relist.all"; + const RELIST_USERNAME = "auctionhouse.relist.username"; const COUNT_ALL = "auctionhouse.count.all"; + const COUNT_USERNAME = "auctionhouse.count.username"; const COUNT_ACTIVE = "auctionhouse.count.active.all"; const COUNT_ACTIVE_UUID = "auctionhouse.count.active.uuid"; const COUNT_ACTIVE_USERNAME = "auctionhouse.count.active.username"; const COUNT_EXPIRED = "auctionhouse.count.expired.all"; const COUNT_EXPIRED_UUID = "auctionhouse.count.expired.uuid"; + const COUNT_EXPIRED_USERNAME = "auctionhouse.count.expired.username"; + + const DELETE_ID = "auctionhouse.delete.id"; + const DELETE_USERNAME = "auctionhouse.delete.username"; const FETCH_ID = "auctionhouse.fetch.id"; const FETCH_ALL = "auctionhouse.fetch.all"; + const FETCH_USERNAME = "auctionhouse.fetch.username"; const FETCH_ACTIVE_NEXT = "auctionhouse.fetch.active.next"; const FETCH_ACTIVE_UUID = "auctionhouse.fetch.active.uuid"; const FETCH_ACTIVE_USERNAME = "auctionhouse.fetch.active.username"; - const FETCH_EXPIRED_UUID = "auctionhouse.fetch.expired.uuid"; } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/database/legacy/LegacyConverter.php b/src/shock95x/auctionhouse/database/legacy/LegacyConverter.php index 15a2af3..82fe8c2 100644 --- a/src/shock95x/auctionhouse/database/legacy/LegacyConverter.php +++ b/src/shock95x/auctionhouse/database/legacy/LegacyConverter.php @@ -1,45 +1,59 @@ database = $database; - $this->nbt = new BigEndianNbtSerializer(); - } - - public function isLegacy(): Generator { - $type = $this->database->getType(); - $rowCount = count(yield from $this->database->asyncSelectRaw($type == "mysql" ? "DESCRIBE auctions;" : "PRAGMA table_info(auctions);")); - return $rowCount == 7; } public function convert(): Generator { - yield from $this->database->getConnector()->asyncGeneric(Query::INIT); - yield from $this->database->asyncGenericRaw("INSERT INTO listings (uuid, username, item, price, created, end_time, expired) SELECT uuid, username, nbt, price, id, end_time, expired FROM auctions;"); - $rows = yield from $this->database->asyncSelectRaw("SELECT * from listings;"); - foreach ($rows as $listing) { - try { - $uuid = Uuid::fromBytes($listing['uuid']); - $nbt = $this->nbt->read(zlib_decode($listing["item"])); - $item = Item::nbtDeserialize($nbt->mustGetCompoundTag()); - yield from $this->database->asyncGenericRaw("UPDATE listings SET uuid = :uuid, item = :item WHERE id = :id;", ["uuid" => $uuid->toString(), "item" => json_encode($item->jsonSerialize()), "id" => $listing['id']]); - } catch (Exception) {} + $type = $this->database->getType(); + /** @var SqlSelectResult[] $columns */ + $columns = yield from $this->database->asyncSelectRaw($type == DatabaseType::MySQL ? "DESCRIBE listings" : "pragma table_info(listings)"); + foreach($columns[0]->getRows() as $column) { + $name = $column[$type == DatabaseType::MySQL ? "Field" : "name"]; + $columnType = strtolower($column[$type == DatabaseType::MySQL ? "Type" : "type"]); + if($name == "item" && ($columnType == "text" || $columnType == "json")) { + AuctionHouse::getInstance()->getLogger()->notice("Migrating to new database schema"); + yield from $this->database->asyncGenericRaw("CREATE TABLE IF NOT EXISTS temp AS SELECT * FROM listings;"); + yield from $this->database->asyncGenericRaw("DROP TABLE listings;"); + yield from $this->database->getConnector()->asyncGeneric(Query::INIT); + /** @var SqlSelectResult[] $listings */ + $listings = yield from $this->database->asyncSelectRaw("SELECT * from temp;"); + foreach($listings[0]->getRows() as $listing) { + $jsonItem = json_decode($listing["item"], true); + if(is_array($jsonItem)) { + $item = Item::legacyJsonDeserialize($jsonItem); + $listing["item"] = Utils::serializeItem($item); + } else { + $item = trim($listing["item"],'"'); + $listing["item"] = hex2bin($item); + } + $listing["created_at"] = $listing["created"]; + $listing["expires_at"] = $listing["end_time"]; + $listing["player_uuid"] = Uuid::fromString($listing["uuid"])->getBytes(); + yield from $this->database->getConnector()->asyncInsert(Query::INSERT, $listing); + } + yield from $this->database->asyncGenericRaw("DROP TABLE temp;"); + AuctionHouse::getInstance()->getLogger()->notice("Migration successfully completed"); + break; + } } - yield from $this->database->asyncChangeRaw("DROP TABLE auctions;"); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/database/storage/DataStorage.php b/src/shock95x/auctionhouse/database/storage/DataStorage.php index 2321bb9..d8b1d30 100644 --- a/src/shock95x/auctionhouse/database/storage/DataStorage.php +++ b/src/shock95x/auctionhouse/database/storage/DataStorage.php @@ -13,6 +13,10 @@ use shock95x\auctionhouse\utils\Utils; use SOFe\AwaitGenerator\Await; +/** + * Use AuctionHouse->getDatabase() + * @deprecated + */ class DataStorage { use SingletonTrait; @@ -26,7 +30,7 @@ public function init(Database $database): void { public function getListingById(int $id, callable $callback): void { $this->database->getConnector()->executeSelect(Query::FETCH_ID, ["id" => $id], function(array $rows) use ($callback): void { foreach ($rows as $listing) { - $callback($this->database->createListingFromRows($listing)); + $callback(AHListing::fromRow($listing)); return; } $callback(null); @@ -38,7 +42,7 @@ public function getListings(callable $callback, int $offset = 0, int $limit = 45 /** @var AHListing[] $listings */ $listings = []; foreach ($rows as $listing) { - $listings[] = $this->database->createListingFromRows($listing); + $listings[] = AHListing::fromRow($listing); } $callback($listings); }); @@ -49,7 +53,7 @@ public function getActiveListings(callable $callback, int $offset = 0, int $limi /** @var AHListing[] $listings */ $listings = []; foreach ($rows as $listing) { - $listings[] = $this->database->createListingFromRows($listing); + $listings[] = AHListing::fromRow($listing); } $callback($listings); }); @@ -60,29 +64,29 @@ public function getActiveListingsByUsername(callable $callback, string $username /** @var AHListing[] $listings */ $listings = []; foreach ($rows as $listing) { - $listings[] = $this->database->createListingFromRows($listing); + $listings[] = AHListing::fromRow($listing); } $callback($listings); }); } public function getActiveListingsByPlayer(callable $callback, Player $player, int $offset = 0, int $limit = 45): void { - $this->database->getConnector()->executeSelect(Query::FETCH_ACTIVE_UUID, ["uuid" => $player->getUniqueId()->toString(), "id" => $offset, "limit" => $limit], function(array $rows) use ($callback): void { + $this->database->getConnector()->executeSelect(Query::FETCH_ACTIVE_UUID, ["uuid" => $player->getUniqueId()->getBytes(), "id" => $offset, "limit" => $limit], function(array $rows) use ($callback): void { /** @var AHListing[] $listings */ $listings = []; foreach ($rows as $listing) { - $listings[] = $this->database->createListingFromRows($listing); + $listings[] = AHListing::fromRow($listing); } $callback($listings); }); } public function getExpiredListingsByPlayer(callable $callback, Player $player, int $offset = 0, int $limit = 45): void { - $this->database->getConnector()->executeSelect(Query::FETCH_EXPIRED_UUID, ["uuid" => $player->getUniqueId()->toString(), "id" => $offset, "limit" => $limit], function(array $rows) use ($callback): void { + $this->database->getConnector()->executeSelect(Query::FETCH_EXPIRED_UUID, ["uuid" => $player->getUniqueId()->getBytes(), "id" => $offset, "limit" => $limit], function(array $rows) use ($callback): void { /** @var AHListing[] $listings */ $listings = []; foreach ($rows as $listing) { - $listings[] = $this->database->createListingFromRows($listing); + $listings[] = AHListing::fromRow($listing); } $callback($listings); }, fn() => $callback([])); @@ -101,7 +105,7 @@ public function getActiveListingCount(callable $callback) { } public function getActiveCountByPlayer(Player $player, callable $callback) { - $this->database->getConnector()->executeSelect(Query::COUNT_ACTIVE_UUID, ["uuid" => $player->getUniqueId()->toString()], function(array $rows) use ($callback): void { + $this->database->getConnector()->executeSelect(Query::COUNT_ACTIVE_UUID, ["uuid" => $player->getUniqueId()->getBytes()], function(array $rows) use ($callback): void { $callback($rows[0]["COUNT(*)"]); }, fn() => $callback(false)); } @@ -119,39 +123,36 @@ public function getExpiredCount(callable $callback) { } public function getExpiredCountByPlayer(Player $player, callable $callback) { - $this->database->getConnector()->executeSelect(Query::COUNT_EXPIRED_UUID, ["uuid" => $player->getUniqueId()->toString()], function(array $rows) use ($callback): void { + $this->database->getConnector()->executeSelect(Query::COUNT_EXPIRED_UUID, ["uuid" => $player->getUniqueId()->getBytes()], function(array $rows) use ($callback): void { $callback($rows[0]["COUNT(*)"]); }, fn() => $callback(false)); } - public function setExpired(AHListing $listing, $value = true, ?callable $onSuccess = null, ?callable $onError = null) { - $this->database->getConnector()->executeGeneric(Query::SET_EXPIRED, ["id" => $listing->getId(), "expired" => $value], $onSuccess, $onError); + public function setExpired(AHListing $listing, ?callable $onSuccess = null, ?callable $onError = null) { + $this->database->getConnector()->executeGeneric(Query::EXPIRE_ID, ["id" => $listing->getId()], $onSuccess, $onError); } public function removeListing(AHListing $listing, ?callable $onSuccess = null, ?callable $onError = null): void { - $listing->setExpired(); $this->removeListingById($listing->getId(), $onSuccess, $onError); } public function removeListingById(int $id, ?callable $onSuccess = null, ?callable $onError = null): void { - $this->database->getConnector()->executeGeneric(Query::DELETE, ["id" => $id], $onSuccess, $onError); + $this->database->getConnector()->executeGeneric(Query::DELETE_ID, ["id" => $id], $onSuccess, $onError); } public function createListing(Player $player, Item $item, int $price, ?callable $callback = null): void { - $uuid = $player->getUniqueId()->toString(); + $uuid = $player->getUniqueId()->getBytes(); $name = $player->getName(); $created = time(); - $endTime = Utils::getEndTime(); - + $endTime = Utils::getExpireTime($created); $this->database->getConnector()->executeInsert(Query::INSERT, [ "uuid" => $uuid, "username" => $name, "price" => $price, - "item" => json_encode($item->jsonSerialize()), + "item" => Utils::serializeItem($item), "created" => $created, "end_time" => $endTime, "expired" => false], - function($id) use ($endTime, $item, $created, $name, $price, $uuid, $callback) { $listing = new AHListing($id, $uuid, $price, $name, $created, $endTime, false, $item); (new AuctionStartEvent($listing))->call(); @@ -161,26 +162,6 @@ function($id) use ($endTime, $item, $created, $name, $price, $uuid, $callback) { } public function createListingAsync(Player $player, Item $item, int $price): Generator { - $created = time(); - $uuid = $player->getUniqueId()->toString(); - $name = $player->getName(); - $endTime = Utils::getEndTime(); - - $id = yield from Await::promise(function($resolve, $reject) use ($endTime, $created, $item, $price, $name, $uuid, $player) { - $this->database->getConnector()->executeInsert(Query::INSERT, [ - "uuid" => $uuid, - "username" => $name, - "price" => $price, - "item" => json_encode($item->jsonSerialize()), - "created" => $created, - "end_time" => $endTime, - "expired" => false], $resolve, $reject); - }); - - if(!is_numeric($id)) return null; - - $listing = new AHListing($id, $uuid, $price, $name, $created, $endTime, false, $item); - (new AuctionStartEvent($listing))->call(); - return $listing; + return yield from Await::promise(fn($cb) => $this->createListing($player, $item, $price)); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/economy/BedrockEconomyProvider.php b/src/shock95x/auctionhouse/economy/BedrockEconomyProvider.php index 6282995..94d98e8 100644 --- a/src/shock95x/auctionhouse/economy/BedrockEconomyProvider.php +++ b/src/shock95x/auctionhouse/economy/BedrockEconomyProvider.php @@ -2,30 +2,35 @@ namespace shock95x\auctionhouse\economy; +use cooldogedev\BedrockEconomy\api\BedrockEconomyAPI; +use cooldogedev\BedrockEconomy\api\type\LegacyAPI; +use cooldogedev\BedrockEconomy\api\util\ClosureContext; use cooldogedev\BedrockEconomy\BedrockEconomy; -use cooldogedev\BedrockEconomy\libs\cooldogedev\libSQL\context\ClosureContext; use pocketmine\player\Player; +use pocketmine\Server; -class BedrockEconomyProvider implements EconomyProvider { +class BedrockEconomyProvider extends EconomyProvider { - protected ?BedrockEconomy $economy; + protected ?LegacyAPI $economy; - public function __construct() { - $this->economy = BedrockEconomy::getInstance(); + public function __construct(){ + $this->economy = BedrockEconomyAPI::legacy(); } - public function addMoney(string|Player $player, float $amount, callable $callback): void { + public function addMoney(string|Player $player, int $amount, callable $callback) : void { if($player instanceof Player) $player = $player->getName(); - $this->economy->getAPI()->addToPlayerBalance($player, $amount, ClosureContext::create(fn (bool $r) => $callback($r))); + $this->economy->addToPlayerBalance($player, $amount, ClosureContext::create(fn (bool $r) => $callback($r))); } - public function subtractMoney(string|Player $player, float $amount, callable $callback): void { + public function subtractMoney(string|Player $player, int $amount, callable $callback): void { if($player instanceof Player) $player = $player->getName(); - $this->economy->getAPI()->subtractFromPlayerBalance($player, $amount, ClosureContext::create(fn (bool $r) => $callback($r))); + $this->economy->subtractFromPlayerBalance($player, $amount, ClosureContext::create(fn (bool $r) => $callback($r))); } public function getCurrencySymbol(): string { - return $this->economy->getCurrencyManager()->getSymbol(); + /** @var BedrockEconomy $eco */ + $eco = Server::getInstance()->getPluginManager()->getPlugin(self::getName()); + return $eco->getCurrencyManager()->getSymbol(); } public static function getName(): string { diff --git a/src/shock95x/auctionhouse/economy/EconomyProvider.php b/src/shock95x/auctionhouse/economy/EconomyProvider.php index 6370062..853710d 100644 --- a/src/shock95x/auctionhouse/economy/EconomyProvider.php +++ b/src/shock95x/auctionhouse/economy/EconomyProvider.php @@ -4,22 +4,31 @@ namespace shock95x\auctionhouse\economy; use pocketmine\player\Player; +use SOFe\AwaitGenerator\Await; -interface EconomyProvider { +abstract class EconomyProvider { - public function addMoney(string|Player $player, float $amount, callable $callback): void; + public abstract function addMoney(string|Player $player, int $amount, callable $callback): void; - public function subtractMoney(string|Player $player, float $amount, callable $callback): void; + public function addMoneyAsync(string|Player $player, int $amount): \Generator { + return yield from Await::promise(fn($resolve) => $this->addMoney($player, $amount, $resolve)); + } + + public abstract function subtractMoney(string|Player $player, int $amount, callable $callback): void; + + public function subtractMoneyAsync(string|Player $player, int $amount): \Generator { + return yield from Await::promise(fn($resolve) => $this->subtractMoney($player, $amount, $resolve)); + } /** * Get currency symbol of economy provider * @return string */ - public function getCurrencySymbol(): string; + public abstract function getCurrencySymbol(): string; /** * Get name of economy provider * @return string */ - public static function getName() : string; + public abstract static function getName() : string; } diff --git a/src/shock95x/auctionhouse/economy/EconomySProvider.php b/src/shock95x/auctionhouse/economy/EconomySProvider.php index b83e63a..162bd6e 100644 --- a/src/shock95x/auctionhouse/economy/EconomySProvider.php +++ b/src/shock95x/auctionhouse/economy/EconomySProvider.php @@ -7,7 +7,7 @@ use pocketmine\player\Player; -class EconomySProvider implements EconomyProvider { +class EconomySProvider extends EconomyProvider { protected ?EconomyAPI $economyAPI; @@ -15,12 +15,12 @@ public function __construct() { $this->economyAPI = EconomyAPI::getInstance(); } - public function addMoney(string|Player $player, float $amount, callable $callback): void { + public function addMoney(string|Player $player, int $amount, callable $callback): void { $ret = $this->economyAPI->addMoney($player, $amount); $callback($ret === EconomyAPI::RET_SUCCESS); } - public function subtractMoney(string|Player $player, float $amount, callable $callback): void { + public function subtractMoney(string|Player $player, int $amount, callable $callback): void { $ret = $this->economyAPI->reduceMoney($player, $amount); $callback($ret === EconomyAPI::RET_SUCCESS); } diff --git a/src/shock95x/auctionhouse/event/AuctionEndEvent.php b/src/shock95x/auctionhouse/event/AuctionEndEvent.php index 0274f48..ca0159b 100644 --- a/src/shock95x/auctionhouse/event/AuctionEndEvent.php +++ b/src/shock95x/auctionhouse/event/AuctionEndEvent.php @@ -12,16 +12,13 @@ class AuctionEndEvent extends Event { const CANCELLED = 0; - const EXPIRED = 1; - const PURCHASED = 2; - const EXPIRED_PURGED = 3; - const ADMIN_PURGED = 4; - const ADMIN_REMOVED = 5; + const PURCHASED = 1; + const ADMIN_REMOVED = 2; public function __construct( private AHListing $listing, private int $type, - private ?Player $purchaser = null + private ?Player $buyer = null ) {} public function getListing() : AHListing { @@ -32,12 +29,12 @@ public function getType() : int { return $this->type; } - public function getPurchaser() : ?Player { - return $this->purchaser; + public function getBuyer() : ?Player { + return $this->buyer; } public function getSeller() : ?IPlayer { $listing = $this->listing; - return Server::getInstance()->getPlayerByRawUUID($listing->getSellerUUID()) ?? Server::getInstance()->getOfflinePlayer($listing->getSeller()); + return Server::getInstance()->getPlayerByUUID($listing->getSellerUUID()) ?? Server::getInstance()->getOfflinePlayer($listing->getSeller()); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/event/AuctionStartEvent.php b/src/shock95x/auctionhouse/event/AuctionStartEvent.php index 53bf20c..fe7c517 100644 --- a/src/shock95x/auctionhouse/event/AuctionStartEvent.php +++ b/src/shock95x/auctionhouse/event/AuctionStartEvent.php @@ -19,6 +19,6 @@ public function getListing() : AHListing { } public function getPlayer() : ?Player { - return Server::getInstance()->getPlayerByRawUUID($this->listing->getSellerUUID()); + return Server::getInstance()->getPlayerByUUID($this->listing->getSellerUUID()); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/menu/ConfirmPurchaseMenu.php b/src/shock95x/auctionhouse/menu/ConfirmPurchaseMenu.php index 13424c4..b9fa818 100644 --- a/src/shock95x/auctionhouse/menu/ConfirmPurchaseMenu.php +++ b/src/shock95x/auctionhouse/menu/ConfirmPurchaseMenu.php @@ -7,14 +7,11 @@ use pocketmine\inventory\Inventory; use pocketmine\item\Item; use pocketmine\player\Player; -use pocketmine\Server; use pocketmine\utils\TextFormat; use pocketmine\world\sound\FizzSound; use Ramsey\Uuid\Uuid; use shock95x\auctionhouse\AHListing; use shock95x\auctionhouse\AuctionHouse; -use shock95x\auctionhouse\database\storage\DataStorage; -use shock95x\auctionhouse\economy\EconomyProvider; use shock95x\auctionhouse\event\AuctionEndEvent; use shock95x\auctionhouse\event\ItemPurchasedEvent; use shock95x\auctionhouse\menu\type\AHMenu; @@ -22,6 +19,7 @@ use shock95x\auctionhouse\utils\Settings; use shock95x\auctionhouse\utils\Utils; use SOFe\AwaitGenerator\Await; +use function PHPUnit\Framework\equalTo; class ConfirmPurchaseMenu extends AHMenu { @@ -37,13 +35,13 @@ public function __construct(Player $player, AHListing $listing) { } public function renderButtons(): void { - foreach (self::INDEX_CONFIRM as $x) { - $confirmItem = Utils::getButtonItem($this->player, "confirm_purchase", "purchase-confirm"); - $this->getInventory()->setItem($x, $confirmItem); + $confirm = Utils::getButtonItem($this->player, "confirm_purchase", "purchase-confirm"); + $cancel = Utils::getButtonItem($this->player, "cancel_purchase", "purchase-cancel"); + foreach(self::INDEX_CONFIRM as $x) { + $this->getInventory()->setItem($x, $confirm); } - foreach (self::INDEX_CANCEL as $x) { - $cancelItem = Utils::getButtonItem($this->player, "cancel_purchase", "purchase-cancel"); - $this->getInventory()->setItem($x, $cancelItem); + foreach(self::INDEX_CANCEL as $x) { + $this->getInventory()->setItem($x, $cancel); } } @@ -69,14 +67,15 @@ public function handle(Player $player, Item $itemClicked, Inventory $inventory, if (!in_array($slot, self::INDEX_CONFIRM)) return false; Await::f2c(function () use ($player) { - $storage = DataStorage::getInstance(); + $database = AuctionHouse::getInstance()->getDatabase(); /** @var ?AHListing $listing */ - $listing = yield from Await::promise(fn($resolve) => $storage->getListingById($this->getListings()[0]?->getId(), $resolve)); + $listing = yield from Await::promise(fn($resolve) => $database->getListingById($this->getListings()[0]?->getId(), $resolve)); if($listing == null || $listing->isExpired()) { + $player->removeCurrentWindow(); Locale::sendMessage($player, "listing-gone"); return; } - if ($listing->getSellerUUID() == $player->getUniqueId()) { + if ($listing->getSellerUUID()->equals($player->getUniqueId())) { $player->removeCurrentWindow(); Locale::sendMessage($player, "self-purchase"); return; @@ -92,26 +91,30 @@ public function handle(Player $player, Item $itemClicked, Inventory $inventory, $event->call(); if($event->isCancelled()) return; - $storage->removeListing($listing); - - $res = yield from Await::promise(fn($resolve) => $economy->subtractMoney($player, $listing->getPrice(), $resolve)); - if(!$res) { + $sub = yield from $economy->subtractMoneyAsync($player, $listing->getPrice()); + if(!$sub) { Locale::sendMessage($player, "cannot-afford"); return; } - $res = yield from Await::promise(fn($resolve) => $economy->addMoney($listing->getSeller(), $listing->getPrice(), $resolve)); - if(!$res) { - yield from Await::promise(fn($resolve) => $economy->addMoney($player, $listing->getPrice(), $resolve)); + $add = yield from $economy->addMoneyAsync($listing->getSeller(), $listing->getPrice()); + if(!$add) { + yield from $economy->addMoneyAsync($player, $listing->getPrice()); Locale::sendMessage($player, "purchase-economy-error"); return; } + $res = yield from $database->removeListingAsync($listing->getId()); + if(!$res) { + $player->removeCurrentWindow(); + Locale::sendMessage($player, "listing-gone"); + return; + } $player->removeCurrentWindow(); $player->getInventory()->addItem($item); $player->sendMessage(str_ireplace(["{PLAYER}", "{ITEM}", "{PRICE}", "{AMOUNT}"], [$player->getName(), $item->getName(), $listing->getPrice(true, Settings::formatPrice()), $item->getCount()], Locale::get($player, "purchased-item", true))); - $seller = AuctionHouse::getInstance()->getServer()->getPlayerByUUID(Uuid::fromString($listing->getSellerUUID())); - $seller?->getWorld()->addSound($seller?->getPosition(), new FizzSound(), [$seller]); - $seller?->sendMessage(str_ireplace(["{PLAYER}", "{ITEM}", "{PRICE}", "{AMOUNT}"], [$player->getName(), $item->getName(), $listing->getPrice(true, Settings::formatPrice()), $item->getCount()], Locale::get($player, "seller-message", true))); + $seller = AuctionHouse::getInstance()->getServer()->getPlayerByUUID($listing->getSellerUUID()); + $seller?->getWorld()->addSound($seller->getPosition(), new FizzSound(), [$seller]); + $seller?->sendMessage(str_ireplace(["{PLAYER}", "{ITEM}", "{PRICE}", "{AMOUNT}"], [$player->getName(), $item->getName(), $listing->getPrice(true, Settings::formatPrice()), $item->getCount()], Locale::get($seller, "seller-message", true))); (new AuctionEndEvent($listing, AuctionEndEvent::PURCHASED, $player))->call(); }); return true; diff --git a/src/shock95x/auctionhouse/menu/ExpiredMenu.php b/src/shock95x/auctionhouse/menu/ExpiredMenu.php index 675db46..57fbded 100644 --- a/src/shock95x/auctionhouse/menu/ExpiredMenu.php +++ b/src/shock95x/auctionhouse/menu/ExpiredMenu.php @@ -5,12 +5,13 @@ use pocketmine\inventory\Inventory; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; use pocketmine\item\VanillaItems; use pocketmine\player\Player; use pocketmine\utils\TextFormat; -use shock95x\auctionhouse\database\storage\DataStorage; -use shock95x\auctionhouse\manager\MenuManager; +use shock95x\auctionhouse\AHListing; +use shock95x\auctionhouse\AuctionHouse; +use shock95x\auctionhouse\database\Database; +use shock95x\auctionhouse\event\AuctionEndEvent; use shock95x\auctionhouse\menu\type\PagingMenu; use shock95x\auctionhouse\utils\Locale; use shock95x\auctionhouse\utils\Settings; @@ -19,29 +20,24 @@ class ExpiredMenu extends PagingMenu { - private int $total; - const INDEX_RETURN_ALL = 49; - public function __construct(Player $player, bool $returnMain = true) { + public function __construct(Player $player) { $this->setName(Locale::get($player, "expired-menu-name")); - parent::__construct($player, $returnMain); + parent::__construct($player); } - protected function init(DataStorage $storage): void { - Await::f2c(function () use ($storage) { - $this->setListings(yield from Await::promise(fn($resolve) => $storage->getExpiredListingsByPlayer($resolve, $this->player, (45 * $this->page) - 45))); - $this->total = yield from Await::promise(fn($resolve) => $storage->getExpiredCountByPlayer($this->player, $resolve)); - $this->pages = (int) ceil($this->total / 45); - parent::init($storage); + protected function init(Database $database): void { + Await::f2c(function () use ($database) { + $this->setListings(yield from Await::promise(fn($resolve) => $database->getExpiredListingsByPlayer($resolve, $this->player->getUniqueId(), $this->getItemOffset()))); + $this->setTotalCount(yield from Await::promise(fn($resolve) => $database->getExpiredCountByPlayer($this->player->getUniqueId(), $resolve))); + parent::init($database); }); } public function renderButtons() : void { parent::renderButtons(); - - $stats = Utils::getButtonItem($this->player, "return_all", "expired-stats", ["{PAGE}", "{MAX}", "{TOTAL}"], [$this->page, $this->page, $this->total]); - + $stats = Utils::getButtonItem($this->player, "return_all", "expired-stats", ["{PAGE}", "{MAX}", "{TOTAL}"], [$this->getPage(), $this->getPageCount(), $this->getTotalCount()]); $this->getInventory()->setItem(53, Utils::getButtonItem($this->player, "info", "main-description")); $this->getInventory()->setItem(49, $stats); } @@ -63,29 +59,33 @@ public function renderListings(): void { public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { Await::f2c(function () use ($player, $slot, $itemClicked, $inventory) { - $storage = DataStorage::getInstance(); + $database = AuctionHouse::getInstance()->getDatabase(); if($slot <= 44 && isset($this->getListings()[$slot])) { $id = $this->getListings()[$slot]->getId(); - $listing = yield from Await::promise(fn($resolve) => $storage->getListingById($id, $resolve)); - if($listing == null || $listing->getSellerUUID() != $player->getUniqueId()->toString()) { + /** @var AHListing $listing */ + $listing = yield from Await::promise(fn($resolve) => $database->getListingById($id, $resolve)); + if($listing == null || !$listing->getSellerUUID()->equals($player->getUniqueId())) { return; } $item = $listing->getItem(); if($player->getInventory()->canAddItem($item)) { - $storage->removeListing($listing); + $res = yield from $database->removeListingAsync($id); + if(!$res) return; $inventory->setItem($slot, VanillaItems::AIR()); $player->getInventory()->addItem($item); $player->sendMessage(str_ireplace(["{ITEM}", "{AMOUNT}"], [$item->getName(), $item->getCount()], Locale::get($player, "returned-item", true))); } } if($slot == self::INDEX_RETURN_ALL) { - if(Utils::getEmptySlotCount($player->getInventory()) < $this->total) { + if(Utils::getEmptySlotCount($player->getInventory()) < $this->getTotalCount()) { Locale::sendMessage($player, "inventory-full"); return; } foreach ($this->getListings() as $index => $expired) { if ($player->getInventory()->canAddItem($expired->getItem())) { - $storage->removeListing($expired); + $res = yield from $database->removeListingAsync($expired->getId()); + if(!$res) return; + (new AuctionEndEvent($expired, AuctionEndEvent::CANCELLED))->call(); $inventory->setItem($index, VanillaItems::AIR()); $player->getInventory()->addItem($expired->getItem()); } diff --git a/src/shock95x/auctionhouse/menu/ListingsMenu.php b/src/shock95x/auctionhouse/menu/ListingsMenu.php index 1ab07be..ffe9e22 100644 --- a/src/shock95x/auctionhouse/menu/ListingsMenu.php +++ b/src/shock95x/auctionhouse/menu/ListingsMenu.php @@ -6,11 +6,11 @@ use DateTime; use pocketmine\inventory\Inventory; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; use pocketmine\item\VanillaItems; use pocketmine\player\Player; use pocketmine\utils\TextFormat; -use shock95x\auctionhouse\database\storage\DataStorage; +use shock95x\auctionhouse\AuctionHouse; +use shock95x\auctionhouse\database\Database; use shock95x\auctionhouse\event\AuctionEndEvent; use shock95x\auctionhouse\menu\type\PagingMenu; use shock95x\auctionhouse\utils\Locale; @@ -20,27 +20,23 @@ class ListingsMenu extends PagingMenu { - private int $total; - - public function __construct(Player $player, bool $returnMain = true) { + public function __construct(Player $player) { $this->setName(Locale::get($player, "listings-menu-name")); - parent::__construct($player, $returnMain); + parent::__construct($player); } - protected function init(DataStorage $storage): void { - Await::f2c(function () use ($storage) { - $this->setListings(yield from Await::promise(fn($resolve) => $storage->getActiveListingsByPlayer($resolve, $this->player, (45 * $this->page) - 45))); - $this->total = yield from Await::promise(fn($resolve) => $storage->getActiveCountByPlayer($this->player, $resolve)); - $this->pages = (int) ceil($this->total / 45); - parent::init($storage); + protected function init(Database $database): void { + Await::f2c(function () use ($database) { + $this->setListings(yield from Await::promise(fn($resolve) => $database->getActiveListingsByPlayer($resolve, $this->player->getUniqueId(), $this->getItemOffset()))); + $this->setTotalCount(yield from Await::promise(fn($resolve) => $database->getActiveCountByPlayer($this->player->getUniqueId(), $resolve))); + parent::init($database); }); } public function renderButtons(): void { parent::renderButtons(); $info = Utils::getButtonItem($this->player, "info", "listings-description"); - $stats = Utils::getButtonItem($this->player, "stats", "listings-stats", ["{PAGE}", "{MAX}", "{TOTAL}"], [$this->page, $this->pages, $this->total]); - + $stats = Utils::getButtonItem($this->player, "stats", "listings-stats", ["{PAGE}", "{MAX}", "{TOTAL}"], [$this->getPage(), $this->getPageCount(), $this->getTotalCount()]); $this->getInventory()->setItem(53, $info); $this->getInventory()->setItem(49, $stats); } @@ -49,7 +45,7 @@ public function renderListings(): void { foreach($this->getListings() as $index => $listing) { $item = clone $listing->getItem(); - $endTime = (new DateTime())->diff((new DateTime())->setTimestamp($listing->getEndTime())); + $endTime = (new DateTime())->diff((new DateTime())->setTimestamp($listing->getExpireTime())); $listedItem = Locale::get($this->player, "your-listed-item"); $lore = str_ireplace(["{PRICE}", "{D}", "{H}", "{M}"], [$listing->getPrice(true, Settings::formatPrice()), $endTime->days, $endTime->h, $endTime->i], preg_filter('/^/', TextFormat::RESET, $listedItem)); @@ -63,7 +59,8 @@ public function renderListings(): void { public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { if($slot <= 44 && isset($this->getListings()[$slot])) { $listing = $this->getListings()[$slot]; - DataStorage::getInstance()->setExpired($listing, true, function() use ($itemClicked, $player, $listing, $slot, $inventory) { + AuctionHouse::getInstance()->getDatabase()->setExpired($listing->getId(), function($res) use ($itemClicked, $player, $listing, $slot, $inventory) { + if(!$res) return; $inventory->setItem($slot, VanillaItems::AIR()); (new AuctionEndEvent($listing, AuctionEndEvent::CANCELLED, $player))->call(); }); diff --git a/src/shock95x/auctionhouse/menu/player/PlayerListingMenu.php b/src/shock95x/auctionhouse/menu/PlayerListingsMenu.php similarity index 65% rename from src/shock95x/auctionhouse/menu/player/PlayerListingMenu.php rename to src/shock95x/auctionhouse/menu/PlayerListingsMenu.php index 7cb636a..7c452c7 100644 --- a/src/shock95x/auctionhouse/menu/player/PlayerListingMenu.php +++ b/src/shock95x/auctionhouse/menu/PlayerListingsMenu.php @@ -6,45 +6,44 @@ use DateTime; use pocketmine\inventory\Inventory; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; use pocketmine\player\Player; use pocketmine\utils\TextFormat; -use shock95x\auctionhouse\database\storage\DataStorage; -use shock95x\auctionhouse\manager\MenuManager; +use shock95x\auctionhouse\database\Database; +use shock95x\auctionhouse\menu\ConfirmPurchaseMenu; use shock95x\auctionhouse\menu\type\PagingMenu; use shock95x\auctionhouse\utils\Locale; use shock95x\auctionhouse\utils\Settings; use shock95x\auctionhouse\utils\Utils; use SOFe\AwaitGenerator\Await; -class PlayerListingMenu extends PagingMenu { +class PlayerListingsMenu extends PagingMenu { - private int $total; private string $username; public function __construct(Player $player, string $username) { $this->username = $username; $this->setName(str_ireplace("{player}", $username, Locale::get($player, "player-listing"))); - parent::__construct($player, true); + parent::__construct($player); } - protected function init(DataStorage $storage): void { - Await::f2c(function () use ($storage) { - $this->setListings(yield from Await::promise(fn($resolve) => $storage->getActiveListingsByUsername($resolve, $this->username, (45 * $this->page) - 45))); - $this->total = yield from Await::promise(fn($resolve) => $storage->getActiveCountByUsername($this->username, $resolve)); - $this->pages = (int) ceil($this->total / 45); - }, fn() => parent::init($storage)); + protected function init(Database $database): void { + Await::f2c(function () use ($database) { + $this->setListings(yield from Await::promise(fn($resolve) => $database->getActiveListingsByUsername($resolve, $this->username, $this->getItemOffset()))); + $this->setTotalCount(yield from Await::promise(fn($resolve) => $database->getActiveCountByUsername($this->username, $resolve))); + parent::init($database); + }); } - public function renderButtons() : void { - $stats = Utils::getButtonItem($this->player, "stats", "listings-stats", ["{PAGE}", "{MAX}", "{TOTAL}"], [$this->page, $this->pages, $this->total]); + public function renderButtons(): void { + parent::renderButtons(); + $stats = Utils::getButtonItem($this->player, "stats", "listings-stats", ["{PAGE}", "{MAX}", "{TOTAL}"], [$this->getPage(), $this->getPageCount(), $this->getTotalCount()]); $this->getInventory()->setItem(49, $stats); } public function renderListings(): void { foreach($this->getListings() as $index => $listing) { $item = clone $listing->getItem(); - $endTime = (new DateTime())->diff((new DateTime())->setTimestamp($listing->getEndTime())); + $endTime = (new DateTime())->diff((new DateTime())->setTimestamp($listing->getExpireTime())); $listedItem = Locale::get($this->player, "listed-item"); $lore = str_ireplace(["{PRICE}", "{SELLER}", "{D}", "{H}", "{M}"], [$listing->getPrice(true, Settings::formatPrice()), $listing->getSeller(), $endTime->days, $endTime->h, $endTime->i], preg_filter('/^/', TextFormat::RESET, $listedItem)); @@ -57,7 +56,10 @@ public function renderListings(): void { } public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { - $this->openListing($slot); + if(isset($this->getListings()[$slot])) { + (new ConfirmPurchaseMenu($player, $this->getListings()[$slot]))->open(); + return true; + } return parent::handle($player, $itemClicked, $inventory, $slot); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/menu/ShopMenu.php b/src/shock95x/auctionhouse/menu/ShopMenu.php index a0e5490..295b105 100644 --- a/src/shock95x/auctionhouse/menu/ShopMenu.php +++ b/src/shock95x/auctionhouse/menu/ShopMenu.php @@ -8,11 +8,10 @@ use pocketmine\inventory\Inventory; use pocketmine\item\enchantment\EnchantmentInstance; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; use pocketmine\player\Player; use pocketmine\utils\TextFormat; use shock95x\auctionhouse\AuctionHouse; -use shock95x\auctionhouse\database\storage\DataStorage; +use shock95x\auctionhouse\database\Database; use shock95x\auctionhouse\menu\admin\AdminMenu; use shock95x\auctionhouse\menu\type\PagingMenu; use shock95x\auctionhouse\utils\Locale; @@ -22,59 +21,54 @@ class ShopMenu extends PagingMenu { - const INDEX_STATS = 49; const INDEX_LISTINGS = 45; const INDEX_EXPIRED = 46; - const INDEX_ADMIN = [47, 51]; + const INDEX_STATS = 49; - private int $selling = 0; - private int $expired = 0; - private int $total = 0; + private int $sellingCount = 0; + private int $expiredCount = 0; public function __construct(Player $player) { $this->setName(Locale::get($player, "menu-name")); - parent::__construct($player, false); + parent::__construct($player); } - protected function init(DataStorage $storage): void { - Await::f2c(function () use ($storage) { - $this->setListings(yield from Await::promise(fn($resolve) => $storage->getActiveListings($resolve, (45 * $this->page) - 45))); - $this->selling = yield from Await::promise(fn($resolve) => $storage->getActiveCountByPlayer($this->player, $resolve)); - $this->expired = yield from Await::promise(fn($resolve) => $storage->getExpiredCountByPlayer($this->player, $resolve)); - $this->total = yield from Await::promise(fn($resolve) => $storage->getActiveListingCount($resolve)); - $this->pages = (int) ceil($this->total / 45); - parent::init($storage); + protected function init(Database $database): void { + Await::f2c(function() use ($database) { + $this->setListings(yield from Await::promise(fn($resolve) => $database->getActiveListings($resolve, $this->getItemOffset()))); + $this->setTotalCount(yield from Await::promise(fn($resolve) => $database->getActiveListingsCount($resolve))); + $this->sellingCount = yield from Await::promise(fn($resolve) => $database->getActiveCountByPlayer($this->player->getUniqueId(), $resolve)); + $this->expiredCount = yield from Await::promise(fn($resolve) => $database->getExpiredCountByPlayer($this->player->getUniqueId(), $resolve)); + parent::init($database); }); } public function renderButtons(): void { parent::renderButtons(); - $stats = Utils::getButtonItem($this->player, "stats", "main-stats", ["{PAGE}", "{MAX}", "{TOTAL}"], [$this->page, $this->pages, $this->total]); + $stats = Utils::getButtonItem($this->player, "stats", "main-stats", ["{PAGE}", "{MAX}", "{TOTAL}"], [$this->getPage(), $this->getPageCount(), $this->getTotalCount()]); $howto = Utils::getButtonItem($this->player, "howto", "sell-description"); $info = Utils::getButtonItem($this->player, "info", "main-description"); - $listings = Utils::getButtonItem($this->player, "player_listings", "view-listed-items", ["{SELLING}"], [$this->selling]); - $expired = Utils::getButtonItem($this->player, "expired_listings", "view-expired-items", ["{EXPIRED}"], [$this->expired]); + $listings = Utils::getButtonItem($this->player, "player_listings", "view-listed-items", ["{SELLING}"], [$this->sellingCount]); + $expired = Utils::getButtonItem($this->player, "expired_listings", "view-expired-items", ["{EXPIRED}"], [$this->expiredCount]); - $items = [ - self::INDEX_STATS => $stats, - self::INDEX_LISTINGS => $listings, - self::INDEX_EXPIRED => $expired, - 52 => $howto, - 53 => $info - ]; + $this->getInventory()->setItem(self::INDEX_STATS, $stats); + $this->getInventory()->setItem(self::INDEX_LISTINGS, $listings); + $this->getInventory()->setItem(self::INDEX_EXPIRED, $expired); + $this->getInventory()->setItem(52, $howto); + $this->getInventory()->setItem(53, $info); if($this->player->hasPermission("auctionhouse.command.admin")) { $admin = Utils::getButtonItem($this->player, "admin_menu", "view-admin-menu"); $admin->addEnchantment(new EnchantmentInstance(EnchantmentIdMap::getInstance()->fromId(AuctionHouse::FAKE_ENCH_ID))); - $items[47] = $items[51] = $admin; + $this->getInventory()->setItem(47, $admin); + $this->getInventory()->setItem(51, $admin); } - foreach ($items as $slot => $item) $this->getInventory()->setItem($slot, $item); } public function renderListings(): void { - foreach($this->getListings() as $index => $listing) { + foreach($this->getListings() as $index => $listing) { $item = clone $listing->getItem(); - $endTime = (new DateTime())->diff((new DateTime())->setTimestamp($listing->getEndTime())); + $endTime = (new DateTime())->diff((new DateTime())->setTimestamp($listing->getExpireTime())); $listedItem = Locale::get($this->player, "listed-item"); $lore = str_ireplace(["{PRICE}", "{SELLER}", "{D}","{H}", "{M}"], [$listing->getPrice(true, Settings::formatPrice()), $listing->getSeller(), $endTime->days, $endTime->h, $endTime->i], preg_filter('/^/', TextFormat::RESET, $listedItem)); @@ -88,18 +82,22 @@ public function renderListings(): void { public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { switch ($slot) { case self::INDEX_LISTINGS: - self::open(new ListingsMenu($this->player), false); - return false; + (new ListingsMenu($player))->setReturnMenu($this)->open(); + break; case self::INDEX_EXPIRED: - self::open(new ExpiredMenu($this->player), false); - return false; + (new ExpiredMenu($player))->setReturnMenu($this)->open(); + break; case 47: case 51: if($player->hasPermission("auctionhouse.command.admin")) { - self::open(new AdminMenu($this->player), false); + (new AdminMenu($player))->setReturnMenu($this)->open(); + break; } - return false; + return true; + } + if(isset($this->getListings()[$slot])) { + (new ConfirmPurchaseMenu($player, $this->getListings()[$slot]))->open(); + return true; } - $this->openListing($slot); return parent::handle($player, $itemClicked, $inventory, $slot); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/menu/admin/AdminListingsMenu.php b/src/shock95x/auctionhouse/menu/admin/AdminListingsMenu.php new file mode 100644 index 0000000..8cae3ee --- /dev/null +++ b/src/shock95x/auctionhouse/menu/admin/AdminListingsMenu.php @@ -0,0 +1,101 @@ +username = $username; + $this->setName(str_ireplace("{player}", $username, Locale::get($player, "player-listing"))); + parent::__construct($player); + } + + protected function init(Database $database): void { + Await::f2c(function () use ($database) { + $this->setListings(yield from Await::promise(fn($resolve) => $database->getListingsByUsername($resolve, $this->username, (45 * $this->getPage()) - 45))); + $this->expiredCount = yield from Await::promise(fn($resolve) => $database->getExpiredCountByUsername($this->username, $resolve)); + $this->setTotalCount(yield from Await::promise(fn($resolve) => $database->getListingsCountByUsername($this->username, $resolve))); + parent::init($database); + }); + } + + public function renderButtons(): void { + parent::renderButtons(); + $fakeEnchant = new EnchantmentInstance(EnchantmentIdMap::getInstance()->fromId(AuctionHouse::FAKE_ENCH_ID)); + + $stats = Utils::getButtonItem($this->player, "stats", "main-stats-admin", ["{PAGE}", "{MAX}", "{EXPIRED}", "{TOTAL}"], [$this->getPage(), $this->getPageCount(), $this->expiredCount, $this->getTotalCount()]); + $deleteAll = VanillaBlocks::BARRIER()->asItem()->setCustomName(TextFormat::RESET . Locale::get($this->player, "delete-all")) + ->addEnchantment($fakeEnchant); + $relistALl = VanillaItems::EMERALD()->setCustomName(TextFormat::RESET . Locale::get($this->player, "relist-all")) + ->addEnchantment($fakeEnchant); + $returnAll = VanillaItems::POISONOUS_POTATO()->setCustomName(TextFormat::RESET . Locale::get($this->player, "return-all")) + ->addEnchantment($fakeEnchant); + + $this->getInventory()->setItem(self::INDEX_REFRESH, $stats); + $this->getInventory()->setItem(self::INDEX_DELETE_ALL, $deleteAll); + $this->getInventory()->setItem(self::INDEX_RELIST_ALL, $relistALl); + $this->getInventory()->setItem(self::INDEX_RETURN_ALL, $returnAll); + } + + public function renderListings(): void { + foreach($this->getListings() as $index => $listing) { + $item = clone $listing->getItem(); + $status = Locale::get($this->player, $listing->isExpired() ? "status-expired" : "status-active"); + $listedItem = Locale::get($this->player, "listed-item-admin"); + $item->setLore(str_ireplace(["{PRICE}", "{SELLER}", "{STATUS}"], [$listing->getPrice(true, Settings::formatPrice()), $listing->getSeller(), $status], preg_filter('/^/', TextFormat::RESET, $listedItem))); + $this->getInventory()->setItem($index, $item); + } + parent::renderListings(); + } + + public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { + Await::f2c(function() use ($player, $slot){ + if($slot <= 44 && isset($this->getListings()[$slot])) { + $listing = $this->getListings()[$slot]; + (new ManageListingMenu($player, $listing))->open(); + return; + } + $database = AuctionHouse::getInstance()->getDatabase(); + switch($slot) { + case self::INDEX_RELIST_ALL: + $expireTime = Utils::getExpireTime(time()); + yield from $database->getConnector()->asyncChange(Query::RELIST_USERNAME, ["username" => $this->username, "expires_at" => $expireTime]); + $this->init($database); + break; + case self::INDEX_RETURN_ALL: + yield from $database->getConnector()->asyncChange(Query::EXPIRE_USERNAME, ["username" => $this->username]); + $this->init($database); + break; + case self::INDEX_DELETE_ALL: + yield from $database->getConnector()->asyncChange(Query::DELETE_USERNAME, ["username" => $this->username]); + $this->init($database); + break; + } + }); + return parent::handle($player, $itemClicked, $inventory, $slot); + } +} \ No newline at end of file diff --git a/src/shock95x/auctionhouse/menu/admin/AdminMenu.php b/src/shock95x/auctionhouse/menu/admin/AdminMenu.php index 5fc375d..31487c1 100644 --- a/src/shock95x/auctionhouse/menu/admin/AdminMenu.php +++ b/src/shock95x/auctionhouse/menu/admin/AdminMenu.php @@ -7,12 +7,12 @@ use pocketmine\inventory\Inventory; use pocketmine\item\enchantment\EnchantmentInstance; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; +use pocketmine\item\VanillaItems; use pocketmine\player\Player; use pocketmine\utils\TextFormat; use shock95x\auctionhouse\AuctionHouse; -use shock95x\auctionhouse\database\storage\DataStorage; -use shock95x\auctionhouse\manager\MenuManager; +use shock95x\auctionhouse\database\Database; +use shock95x\auctionhouse\database\Query; use shock95x\auctionhouse\menu\type\PagingMenu; use shock95x\auctionhouse\utils\Locale; use shock95x\auctionhouse\utils\Settings; @@ -21,29 +21,39 @@ class AdminMenu extends PagingMenu { - protected int $expired; - protected int $total; + protected int $expiredCount; - public function __construct(Player $player, bool $returnMain = true) { + const INDEX_RELIST_ALL = 52; + const INDEX_RETURN_ALL = 53; + + public function __construct(Player $player) { $this->setName(Locale::get($player, "admin-menu-name")); - parent::__construct($player, $returnMain); + parent::__construct($player); } - protected function init(DataStorage $storage): void { - Await::f2c(function () use ($storage) { - $this->setListings(yield from Await::promise(fn($resolve) => $storage->getListings($resolve, (45 * $this->page) - 45))); - $this->expired = yield from Await::promise(fn($resolve) => $storage->getExpiredCount($resolve)); - $this->total = yield from Await::promise(fn($resolve) => $storage->getTotalListingCount($resolve)); - $this->pages = (int) ceil($this->total / 45); - parent::init($storage); + protected function init(Database $database): void { + Await::f2c(function () use ($database) { + $this->setListings(yield from Await::promise(fn($resolve) => $database->getListings($resolve, (45 * $this->getPage()) - 45))); + $this->expiredCount = yield from Await::promise(fn($resolve) => $database->getExpiredCount($resolve)); + $this->setTotalCount(yield from Await::promise(fn($resolve) => $database->getListingsCount($resolve))); + parent::init($database); }); } public function renderButtons(): void { parent::renderButtons(); - $stats = Utils::getButtonItem($this->player, "stats", "main-stats-admin", ["{PAGE}", "{MAX}", "{EXPIRED}", "{TOTAL}"], [$this->page, $this->pages, $this->expired, $this->total]); - $stats->addEnchantment(new EnchantmentInstance(EnchantmentIdMap::getInstance()->fromId(AuctionHouse::FAKE_ENCH_ID))); + $fakeEnchant = new EnchantmentInstance(EnchantmentIdMap::getInstance()->fromId(AuctionHouse::FAKE_ENCH_ID)); + + $stats = Utils::getButtonItem($this->player, "stats", "main-stats-admin", ["{PAGE}", "{MAX}", "{EXPIRED}", "{TOTAL}"], [$this->getPage(), $this->getPageCount(), $this->expiredCount, $this->getTotalCount()]) + ->addEnchantment($fakeEnchant); + $relistALl = VanillaItems::EMERALD()->setCustomName(TextFormat::RESET . Locale::get($this->player, "relist-all")) + ->addEnchantment($fakeEnchant); + $returnAll = VanillaItems::POISONOUS_POTATO()->setCustomName(TextFormat::RESET . Locale::get($this->player, "return-all")) + ->addEnchantment($fakeEnchant); + $this->getInventory()->setItem(self::INDEX_REFRESH, $stats); + $this->getInventory()->setItem(self::INDEX_RELIST_ALL, $relistALl); + $this->getInventory()->setItem(self::INDEX_RETURN_ALL, $returnAll); } public function renderListings(): void { @@ -52,18 +62,31 @@ public function renderListings(): void { $status = Locale::get($this->player, $listing->isExpired() ? "status-expired" : "status-active"); $listedItem = Locale::get($this->player, "listed-item-admin"); $item->setLore(str_ireplace(["{PRICE}", "{SELLER}", "{STATUS}"], [$listing->getPrice(true, Settings::formatPrice()), $listing->getSeller(), $status], preg_filter('/^/', TextFormat::RESET, $listedItem))); - $this->getInventory()->setItem($index, $item); } parent::renderListings(); } public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { - if($slot <= 44 && isset($this->getListings()[$slot])) { - $listing = $this->getListings()[$slot]; - $player->removeCurrentWindow(); - self::open(new ManageListingMenu($player, $listing)); - } + Await::f2c(function() use ($player, $slot){ + if($slot <= 44 && isset($this->getListings()[$slot])) { + $listing = $this->getListings()[$slot]; + (new ManageListingMenu($player, $listing))->setReturnMenu($this)->open(); + return; + } + $database = AuctionHouse::getInstance()->getDatabase(); + switch($slot) { + case self::INDEX_RELIST_ALL: + $expireTime = Utils::getExpireTime(time()); + yield from $database->getConnector()->asyncChange(Query::RELIST_ALL, ["expires_at" => $expireTime]); + $this->init($database); + break; + case self::INDEX_RETURN_ALL: + yield from $database->getConnector()->asyncChange(Query::EXPIRE_ALL); + $this->init($database); + break; + } + }); return parent::handle($player, $itemClicked, $inventory, $slot); } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/menu/admin/ManageListingMenu.php b/src/shock95x/auctionhouse/menu/admin/ManageListingMenu.php index db8544f..bd1bce1 100644 --- a/src/shock95x/auctionhouse/menu/admin/ManageListingMenu.php +++ b/src/shock95x/auctionhouse/menu/admin/ManageListingMenu.php @@ -3,24 +3,27 @@ namespace shock95x\auctionhouse\menu\admin; +use pocketmine\block\tile\Container; +use pocketmine\data\bedrock\item\SavedItemStackData; use pocketmine\inventory\Inventory; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; -use pocketmine\item\ItemIds; +use pocketmine\block\VanillaBlocks; +use pocketmine\item\VanillaItems; use pocketmine\player\Player; +use pocketmine\Server; use pocketmine\utils\TextFormat; use shock95x\auctionhouse\AHListing; -use shock95x\auctionhouse\database\storage\DataStorage; +use shock95x\auctionhouse\AuctionHouse; use shock95x\auctionhouse\event\AuctionEndEvent; use shock95x\auctionhouse\menu\type\AHMenu; use shock95x\auctionhouse\utils\Locale; -use shock95x\auctionhouse\utils\Utils; +use SOFe\AwaitGenerator\Await; class ManageListingMenu extends AHMenu { - const INDEX_DUPLICATE = 38; - const INDEX_STATUS = 40; - const INDEX_DELETE = 42; + const INDEX_COPY = 47; + const INDEX_REMOVE = 49; + const INDEX_DELETE = 51; public function __construct(Player $player, AHListing $listing) { $this->setName(Locale::get($player, "manage-listing-name")); @@ -29,50 +32,59 @@ public function __construct(Player $player, AHListing $listing) { } public function renderButtons(): void { - parent::renderButtons(); - $listing = $this->getListings()[0]; - $duplicateItem = ItemFactory::getInstance()->get(ItemIDs::EMERALD_BLOCK)->setCustomName(TextFormat::RESET . Locale::get($this->player, "duplicate-item")); - $status = Locale::get($this->player, $listing->isExpired() ? "status-expired" : "status-active"); - $listingStatus = ItemFactory::getInstance()->get(ItemIDs::GOLD_BLOCK) - ->setCustomName(str_ireplace("{STATUS}", $status, implode("\n", preg_filter('/^/', TextFormat::RESET, Locale::get($this->player, "listing-status"))))); - $deleteItem = ItemFactory::getInstance()->get(ItemIDs::REDSTONE_BLOCK)->setCustomName(TextFormat::RESET . Locale::get($this->player, "delete-item")); - - $this->inventory->setItem(self::INDEX_DUPLICATE, $duplicateItem); - $this->inventory->setItem(self::INDEX_STATUS, $listingStatus); - $this->inventory->setItem(self::INDEX_DELETE, $deleteItem); + $this->inventory->setItem(self::INDEX_COPY, + VanillaBlocks::HOPPER()->asItem()->setCustomName(TextFormat::RESET . Locale::get($this->player, "copy-item"))); + $this->inventory->setItem(self::INDEX_REMOVE, + VanillaItems::POISONOUS_POTATO()->setCustomName(TextFormat::RESET . Locale::get($this->player, "return-item"))); + $this->inventory->setItem(self::INDEX_DELETE, + VanillaBlocks::BARRIER()->asItem()->setCustomName(TextFormat::RESET . Locale::get($this->player, "delete-item"))); } public function renderListings(): void { - $this->inventory->setItem(22, $this->getListings()[0]->getItem()); + $listingItem = $this->getListings()[0]->getItem(); + if($itemsTag = $listingItem->getNamedTag()?->getListTag(Container::TAG_ITEMS)) { // Shulker items + foreach($itemsTag->getIterator() as $itemTag) { + $this->inventory->setItem($itemTag->getByte(SavedItemStackData::TAG_SLOT), Item::nbtDeserialize($itemTag)); + } + $this->inventory->setItem(31, $listingItem); + } else { + $this->inventory->setItem(22, $listingItem); + } } public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { - $listing = $this->getListings()[0]; - switch ($slot) { - case self::INDEX_DUPLICATE: - $player->getInventory()->addItem($listing->getItem()); - break; - case self::INDEX_STATUS: - if($listing->isExpired()) { - $listing->setExpired(false); - DataStorage::getInstance()->setExpired($listing, value: false); - $listing->setEndTime(Utils::getEndTime()); - } else { - $listing->setExpired(); + Await::f2c(function() use ($player, $slot) { + $database = AuctionHouse::getInstance()->getDatabase(); + /** @var AHListing $listing */ + $listing = yield from Await::promise(fn($resolve) => $database->getListingById($this->getListings()[0]->getId(), $resolve)); + switch($slot) { + case self::INDEX_COPY: + $player->getInventory()->addItem($listing->getItem()); + break; + case self::INDEX_REMOVE: + if($listing == null || $listing->isExpired()) { + $this->returnMenu?->send($player); + break; + } + yield from $database->setExpiredAsync($listing->getId()); + (new AuctionEndEvent($listing, AuctionEndEvent::CANCELLED))->call(); + if($seller = Server::getInstance()->getPlayerByUUID($listing->getSellerUUID())) { + $item = $listing->getItem(); + $seller->sendMessage(str_ireplace(["{ITEM}", "{AMOUNT}"], [$item->getName(), $item->getCount()], Locale::get($seller, "returned-item", true))); + } + $this->returnMenu?->send($player); + break; + case self::INDEX_DELETE: + if($listing == null) { + $this->returnMenu?->send($player); + break; + } + yield from $database->removeListingAsync($listing->getId()); (new AuctionEndEvent($listing, AuctionEndEvent::ADMIN_REMOVED))->call(); - } - $this->renderButtons(); - break; - case self::INDEX_DELETE: - DataStorage::getInstance()->removeListing($listing); - (new AuctionEndEvent($listing, AuctionEndEvent::ADMIN_PURGED))->call(); - self::open(new AdminMenu($player, false)); - break; - } - return parent::handle($player, $itemClicked, $inventory, $slot); - } - - public function onClose(Player $player): void { - parent::onClose($player); + $this->returnMenu?->send($player); + break; + } + }); + return true; } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/menu/category/CategoryListMenu.php b/src/shock95x/auctionhouse/menu/category/CategoryListMenu.php index 083337e..28fab45 100644 --- a/src/shock95x/auctionhouse/menu/category/CategoryListMenu.php +++ b/src/shock95x/auctionhouse/menu/category/CategoryListMenu.php @@ -9,43 +9,40 @@ use pocketmine\utils\TextFormat; use shock95x\auctionhouse\category\Category; use shock95x\auctionhouse\category\ICategory; -use shock95x\auctionhouse\database\storage\DataStorage; +use shock95x\auctionhouse\database\Database; use shock95x\auctionhouse\menu\type\PagingMenu; use shock95x\auctionhouse\utils\Locale; use shock95x\auctionhouse\utils\Utils; class CategoryListMenu extends PagingMenu { - private int $total; - - public function __construct(Player $player, bool $returnMain = true) { + public function __construct(Player $player) { $this->setName(Locale::get($player, "category-menu-name")); - parent::__construct($player, $returnMain); + parent::__construct($player); } - protected function init(DataStorage $storage): void { - $this->total = count(Category::getAll()); - $this->pages = (int) ceil($this->total / 45); - parent::init($storage); + protected function init(Database $database): void { + $this->setTotalCount(count(Category::getAll())); + $this->renderButtons(); } public function renderButtons() : void { parent::renderButtons(); - $categories = array_slice(array_values(Category::getAll()), ($this->page - 1) * 45, 45); + $categories = array_slice(array_values(Category::getAll()), $this->getItemOffset(), 45); /** @var ICategory $category */ foreach($categories as $index => $category) { $item = $category->getMenuItem(); $item->setLore([TextFormat::RESET . TextFormat::GRAY . "Click to open category"]); $this->getInventory()->setItem($index, $item); } - $stats = Utils::getButtonItem($this->player, "stats", "category-list-stats", ["{PAGE}", "{MAX}", "{TOTAL}"], [$this->page, $this->pages, $this->total]); + $stats = Utils::getButtonItem($this->player, "stats", "category-list-stats", ["{PAGE}", "{MAX}", "{TOTAL}"], [$this->getPage(), $this->getPageCount(), $this->getTotalCount()]); $this->getInventory()->setItem(49, $stats); } public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { $categories = array_values(Category::getAll()); if($slot <= 44 && isset($categories[$slot])) { - self::open(new CategoryMenu($player, $categories[$slot]), false); + (new CategoryMenu($player, $categories[$slot]))->setReturnMenu($this)->open(); } return parent::handle($player, $itemClicked, $inventory, $slot); } diff --git a/src/shock95x/auctionhouse/menu/category/CategoryMenu.php b/src/shock95x/auctionhouse/menu/category/CategoryMenu.php index 576d1d4..b9acd3a 100644 --- a/src/shock95x/auctionhouse/menu/category/CategoryMenu.php +++ b/src/shock95x/auctionhouse/menu/category/CategoryMenu.php @@ -6,11 +6,12 @@ use DateTime; use pocketmine\inventory\Inventory; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; use pocketmine\player\Player; use pocketmine\utils\TextFormat; +use shock95x\auctionhouse\AuctionHouse; use shock95x\auctionhouse\category\ICategory; -use shock95x\auctionhouse\database\storage\DataStorage; +use shock95x\auctionhouse\database\Database; +use shock95x\auctionhouse\menu\ConfirmPurchaseMenu; use shock95x\auctionhouse\menu\type\PagingMenu; use shock95x\auctionhouse\utils\Locale; use shock95x\auctionhouse\utils\Pagination; @@ -20,52 +21,49 @@ class CategoryMenu extends PagingMenu { - private int $total; private ICategory $category; public function __construct(Player $player, ICategory $category) { $this->category = $category; $this->setName($category->getDisplayName()); - parent::__construct($player, true); + parent::__construct($player); } - protected function init(DataStorage $storage): void { - Await::f2c(function () use ($storage) { - $this->setListings(yield from Await::promise(fn($resolve) => $storage->getListings($resolve, 0, PHP_INT_MAX))); - $this->total = count($this->getListings()); - $this->pages = (int) ceil($this->total / 45); - parent::init($storage); + protected function init(Database $database): void { + Await::f2c(function () use ($database) { + $this->setListings(yield from Await::promise(fn($resolve) => $database->getActiveListings($resolve, 0, PHP_INT_MAX))); + $this->setTotalCount(count($this->getListings())); + parent::init($database); }); } public function renderButtons(): void { parent::renderButtons(); - $stats = Utils::getButtonItem($this->player, "stats", "category-stats", ["{PAGE}", "{MAX}", "{TOTAL}", "{CATEGORY}"], [$this->page, $this->pages, $this->total, $this->category->getDisplayName()]); + $stats = Utils::getButtonItem($this->player, "stats", "category-stats", ["{PAGE}", "{MAX}", "{TOTAL}", "{CATEGORY}"], [$this->getPage(), $this->getPageCount(), $this->getTotalCount(), $this->category->getDisplayName()]); $this->getInventory()->setItem(self::INDEX_REFRESH, $stats); } public function renderListings(): void { - $listings = array_slice($this->getListings(), ($this->page - 1) * 45, 45); - foreach($listings as $key => $auction) { - $item = clone $auction->getItem(); - $endTime = (new DateTime())->diff((new DateTime())->setTimestamp($auction->getEndTime())); + $listings = array_slice($this->getListings(), $this->getItemOffset(), 45); + foreach($listings as $i => $listing) { + $item = clone $listing->getItem(); + $endTime = (new DateTime())->diff((new DateTime())->setTimestamp($listing->getExpireTime())); $listedItem = Locale::get($this->player, "listed-item"); - $lore = str_ireplace(["{PRICE}", "{SELLER}", "{D}", "{H}", "{M}"], [$auction->getPrice(true, Settings::formatPrice()), $auction->getSeller(), $endTime->days, $endTime->h, $endTime->i], preg_filter('/^/', TextFormat::RESET, $listedItem)); + $lore = str_ireplace(["{PRICE}", "{SELLER}", "{D}", "{H}", "{M}"], [$listing->getPrice(true, Settings::formatPrice()), $listing->getSeller(), $endTime->days, $endTime->h, $endTime->i], preg_filter('/^/', TextFormat::RESET, $listedItem)); $lore = Settings::allowLore() ? [...$item->getLore(), ...$lore] : $lore; $item->setLore($lore); - $this->getInventory()->setItem($key, $item); + $this->getInventory()->setItem($i, $item); } parent::renderListings(); } public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { - if($slot == self::INDEX_RETURN) { - self::open(new CategoryListMenu($player, $this->returnMain), false); + if(isset($this->getListings()[$slot])) { + (new ConfirmPurchaseMenu($player, $this->getListings()[$slot]))->open(); return true; } - $this->openListing($slot); return parent::handle($player, $itemClicked, $inventory, $slot); } @@ -73,25 +71,25 @@ protected function setListings(array $listings): void { $filtered = []; $listings = array_filter($listings, [$this->category, "sort"]); array_walk($listings, function($l) use(&$filtered) { if(!is_null($l)) $filtered[] = $l; }); - $this->listings = $filtered; + parent::setListings($filtered); } protected function handlePagination(int $action): bool { + $page = $this->getPage(); + $pageCount = $this->getPageCount(); switch($action) { case Pagination::BACK: - if(($this->page - 1) <= 0) break; - $this->page--; + if($page > 1) $this->setPage($page - 1); break; case Pagination::NEXT: - if(($this->page + 1) > $this->pages) break; - $this->page++; + if($page < $pageCount) $this->setPage($page + 1); break; default: - $this->page = 1; - $this->init(DataStorage::getInstance()); + $this->setPage(1); + $this->init(AuctionHouse::getInstance()->getDatabase()); return true; } - parent::init(DataStorage::getInstance()); + parent::init(AuctionHouse::getInstance()->getDatabase()); return true; } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/menu/type/AHMenu.php b/src/shock95x/auctionhouse/menu/type/AHMenu.php index 0fad082..cd303e1 100644 --- a/src/shock95x/auctionhouse/menu/type/AHMenu.php +++ b/src/shock95x/auctionhouse/menu/type/AHMenu.php @@ -5,84 +5,44 @@ use muqsit\invmenu\InvMenu; use muqsit\invmenu\InvMenuHandler; -use muqsit\invmenu\session\InvMenuInfo; use muqsit\invmenu\transaction\DeterministicInvMenuTransaction; -use pocketmine\inventory\Inventory; -use pocketmine\item\Item; -use pocketmine\item\ItemFactory; -use pocketmine\item\VanillaItems; use pocketmine\player\Player; -use pocketmine\scheduler\ClosureTask; -use pocketmine\utils\TextFormat; use pocketmine\world\sound\ClickSound; use shock95x\auctionhouse\AHListing; use shock95x\auctionhouse\AuctionHouse; -use shock95x\auctionhouse\database\storage\DataStorage; +use shock95x\auctionhouse\database\Database; use shock95x\auctionhouse\event\MenuCloseEvent; -use shock95x\auctionhouse\menu\ConfirmPurchaseMenu; -use shock95x\auctionhouse\menu\ShopMenu; -use shock95x\auctionhouse\utils\Locale; -use shock95x\auctionhouse\utils\Utils; -use SOFe\AwaitGenerator\Await; abstract class AHMenu extends InvMenu { - protected ?Player $player; - protected Inventory $inventory; - - protected bool $returnMain = false; - /** @var AHListing[] */ protected array $listings = []; - protected static string $inventoryType = InvMenu::TYPE_DOUBLE_CHEST; + protected ?Player $player; + protected ?AHMenu $returnMenu = null; - const INDEX_RETURN = 45; + protected static string $inventoryType = InvMenu::TYPE_DOUBLE_CHEST; - public function __construct(Player $player, bool $returnMain = false) { + public function __construct(Player $player) { parent::__construct(InvMenuHandler::getTypeRegistry()->get(static::$inventoryType)); $this->player = $player; - $this->returnMain = $returnMain; - - $this->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) { - $this->player->getWorld()->addSound($this->player->getPosition(), new ClickSound(), [$this->player]); + $this->setListener(InvMenu::readonly(function(DeterministicInvMenuTransaction $transaction) use ($player) { + $player->getWorld()->addSound($player->getPosition(), new ClickSound(), [$player]); $this->handle($transaction->getPlayer(), $transaction->getItemClicked(), $transaction->getAction()->getInventory(), $transaction->getAction()->getSlot()); })); - - $this->init(DataStorage::getInstance()); } - protected function init(DataStorage $storage): void { + protected function init(Database $database): void { $this->renderButtons(); $this->renderListings(); } - public function renderButtons(): void { - if($this->returnMain) { - $this->getInventory()->setItem(self::INDEX_RETURN, Utils::getButtonItem($this->player, "back", "back-button")); - } - } - - public function renderListings(): void { - for($i = count($this->listings); $i < 45; ++$i) { - $this->getInventory()->setItem($i, VanillaItems::AIR()); - } - } + abstract function renderButtons(); + abstract function renderListings(); - public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { - if($this->returnMain && $slot == self::INDEX_RETURN) { - self::open(new ShopMenu($player), false); - } - return true; - } - - protected function openListing(int $slot): bool { - if($slot <= 44 && isset($this->getListings()[$slot])) { - $listing = $this->getListings()[$slot]; - $this->player->removeCurrentWindow(); - self::open(new ConfirmPurchaseMenu($this->player, $listing)); - } - return true; + public function setReturnMenu(?AHMenu $returnMenu): self { + $this->returnMenu = $returnMenu; + return $this; } /** @@ -99,24 +59,13 @@ public function getListings(): array { return $this->listings; } - public function getPlayer(): Player { - return $this->player; + public function open(): void { + $this->init(AuctionHouse::getInstance()->getDatabase()); + $this->send($this->player); } public function onClose(Player $player): void { (new MenuCloseEvent($player, $this))->call(); parent::onClose($player); } - - public static function open(self $menu, bool $newWindow = true): void { - $session = InvMenuHandler::getPlayerManager()->get($menu->player); - $currentMenu = $session->getCurrent()?->menu; - if($session->getCurrent() == null || ($newWindow && $currentMenu instanceof AHMenu)) { - $menu->send($menu->player); - return; - } - $currentMenu->getInventory()->clearAll(); - $currentMenu->setInventory($menu->getInventory()); - $currentMenu->setListener($menu->listener); - } -} +} \ No newline at end of file diff --git a/src/shock95x/auctionhouse/menu/type/PagingMenu.php b/src/shock95x/auctionhouse/menu/type/PagingMenu.php index 1ad0def..5b19ebf 100644 --- a/src/shock95x/auctionhouse/menu/type/PagingMenu.php +++ b/src/shock95x/auctionhouse/menu/type/PagingMenu.php @@ -5,64 +5,96 @@ use pocketmine\inventory\Inventory; use pocketmine\item\Item; +use pocketmine\item\VanillaItems; use pocketmine\player\Player; -use shock95x\auctionhouse\database\storage\DataStorage; +use shock95x\auctionhouse\AuctionHouse; use shock95x\auctionhouse\utils\Pagination; use shock95x\auctionhouse\utils\Utils; abstract class PagingMenu extends AHMenu { - protected int $page = 1; - protected int $pages = 1; - + const INDEX_RETURN = 45; const INDEX_BACK = 48; const INDEX_REFRESH = 49; const INDEX_NEXT = 50; - public function __construct(Player $player, bool $returnMain = false) { - parent::__construct($player, $returnMain); + private int $page = 1; + private int $pageCount = 1; + private int $totalCount = 0; + protected int $itemsPerPage = 45; + + public function __construct(Player $player) { + parent::__construct($player); + } + + public function setPage(int $page) : void{ + $this->page = $page; } - public function getPage() : int { + public function setTotalCount(int $itemCount): void { + $this->totalCount = $itemCount; + $this->pageCount = (int) (ceil($itemCount / $this->itemsPerPage)) ?: 1; + } + + public function getPage(): int { return $this->page; } - public function getPages(): int { - return $this->pages; + public function getPageCount(): int { + return $this->pageCount; } - public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { - switch ($slot) { - case self::INDEX_BACK: - return $this->handlePagination(Pagination::BACK); - case self::INDEX_NEXT: - return $this->handlePagination(Pagination::NEXT); - case self::INDEX_REFRESH: - return $this->handlePagination(Pagination::REFRESH); + public function getTotalCount(): int { + return $this->totalCount; + } + + public function getItemOffset(): int { + return ($this->page - 1) * $this->itemsPerPage; + } + + public function renderListings(): void { + for($i = count($this->listings); $i < $this->itemsPerPage; ++$i) { + $this->getInventory()->setItem($i, VanillaItems::AIR()); } - return parent::handle($player, $itemClicked, $inventory, $slot); } public function renderButtons(): void { - parent::renderButtons(); - $back = Utils::getButtonItem($this->player, "previous", "previous-page"); - $next = Utils::getButtonItem($this->player, "next", "next-page"); - $this->getInventory()->setItem(self::INDEX_BACK, $back); - $this->getInventory()->setItem(self::INDEX_NEXT, $next); + $showPrevious = ($this->page > 1); + $showNext = ($this->page < $this->pageCount); + $this->getInventory()->setItem(self::INDEX_BACK, ($showPrevious ? Utils::getButtonItem($this->player, "previous", "previous-page") : VanillaItems::AIR())); + $this->getInventory()->setItem(self::INDEX_NEXT, ($showNext ? Utils::getButtonItem($this->player, "next", "next-page") : VanillaItems::AIR())); + if($this->returnMenu) $this->getInventory()->setItem(self::INDEX_RETURN, Utils::getButtonItem($this->player, "back", "back-button")); } protected function handlePagination(int $action): bool { switch($action) { case Pagination::BACK: - if(($this->page - 1) <= 0) break; - $this->page--; + if($this->page > 1) { + $this->page--; + } break; case Pagination::NEXT: - if(($this->page + 1) > $this->pages) break; - $this->page++; + if($this->page < $this->pageCount) { + $this->page++; + } break; } - $this->init(DataStorage::getInstance()); + $this->init(AuctionHouse::getInstance()->getDatabase()); + return true; + } + + public function handle(Player $player, Item $itemClicked, Inventory $inventory, int $slot): bool { + switch ($slot) { + case self::INDEX_RETURN: + $this->returnMenu?->send($player); + break; + case self::INDEX_BACK: + return $this->handlePagination(Pagination::BACK); + case self::INDEX_NEXT: + return $this->handlePagination(Pagination::NEXT); + case self::INDEX_REFRESH: + return $this->handlePagination(Pagination::REFRESH); + } return true; } } \ No newline at end of file diff --git a/src/shock95x/auctionhouse/task/CheckLegacyTask.php b/src/shock95x/auctionhouse/task/CheckLegacyTask.php deleted file mode 100644 index 8e6efb4..0000000 --- a/src/shock95x/auctionhouse/task/CheckLegacyTask.php +++ /dev/null @@ -1,21 +0,0 @@ -isLegacy()) { - $this->plugin->getLogger()->notice("Old database format detected! Run '/ah convert' to update"); - } - }); - } -} \ No newline at end of file diff --git a/src/shock95x/auctionhouse/task/ListingExpireTask.php b/src/shock95x/auctionhouse/task/ListingExpireTask.php deleted file mode 100644 index b4fad34..0000000 --- a/src/shock95x/auctionhouse/task/ListingExpireTask.php +++ /dev/null @@ -1,50 +0,0 @@ -database->asyncSelectRaw("SELECT * from listings WHERE :time >= end_time AND expired = FALSE;", ["time" => time()]); - $listings = $this->createListingsFromRows($result[0]->getRows()); - foreach ($listings as $listing) { - yield from Await::promise(fn($resolve, $reject) => $dataStorage->setExpired($listing, true, $resolve, $reject)); - (new AuctionEndEvent($listing, AuctionEndEvent::EXPIRED))->call(); - } - $result = yield from $this->database->asyncSelectRaw("SELECT * from listings WHERE expired = TRUE;"); - $listings = $this->createListingsFromRows($result[0]->getRows()); - foreach ($listings as $listing) { - $time->setTimestamp($listing->getEndTime()); - if($time->diff(new DateTime())->days >= Settings::getExpiredDuration()) { - yield from Await::promise(fn($resolve, $reject) => $dataStorage->removeListing($listing, $resolve, $reject)); - (new AuctionEndEvent($listing, AuctionEndEvent::EXPIRED_PURGED))->call(); - } - } - }); - } - - /** - * @param array $rows - * @return AHListing[] - */ - private function createListingsFromRows(array $rows): array { - $listings = []; - foreach ($rows as $row) { - $listings[] = $this->database->createListingFromRows($row); - } - return $listings; - } -} \ No newline at end of file diff --git a/src/shock95x/auctionhouse/task/SQLiteExpireTask.php b/src/shock95x/auctionhouse/task/SQLiteExpireTask.php new file mode 100644 index 0000000..59e9867 --- /dev/null +++ b/src/shock95x/auctionhouse/task/SQLiteExpireTask.php @@ -0,0 +1,22 @@ +database->asyncChangeRaw("UPDATE listings SET expired = TRUE WHERE expired = FALSE AND expires_at <= unixepoch();"); + if($expiredDuration > 0) { + yield from $this->database->asyncChangeRaw("DELETE FROM listings WHERE expired = TRUE AND expires_at + (:duration * 86400) <= unixepoch();", ["duration" => $expiredDuration]); + } + }); + } +} \ No newline at end of file diff --git a/src/shock95x/auctionhouse/utils/Utils.php b/src/shock95x/auctionhouse/utils/Utils.php index 143ea4c..42ea2ea 100644 --- a/src/shock95x/auctionhouse/utils/Utils.php +++ b/src/shock95x/auctionhouse/utils/Utils.php @@ -6,6 +6,8 @@ use pocketmine\inventory\Inventory; use pocketmine\item\Item; use pocketmine\item\LegacyStringToItemParser; +use pocketmine\nbt\BigEndianNbtSerializer; +use pocketmine\nbt\TreeRoot; use pocketmine\player\Player; use pocketmine\plugin\Plugin; use pocketmine\scheduler\ClosureTask; @@ -14,8 +16,8 @@ class Utils { - public static function getEndTime(): int { - return time() + (Settings::getExpireInterval() * 3600); + public static function getExpireTime(int $time): int { + return $time + (Settings::getExpireInterval() * 3600); } public static function prefixMessage($string): string { @@ -57,6 +59,15 @@ public static function getButtonItem(Player $player, string $itemKey, string $me return $item; } + public static function serializeItem(Item $item): string { + $data = zlib_encode((new BigEndianNbtSerializer())->write(new TreeRoot($item->nbtSerialize())), ZLIB_ENCODING_GZIP); + return $data; + } + + public static function deserializeItem(string $data): Item { + return Item::nbtDeserialize((new BigEndianNbtSerializer())->read(zlib_decode($data))->mustGetCompoundTag()); + } + public static function removeItem(Player $player, Item $slot) : bool { $inventory = $player->getInventory(); for ($i = 0, $size = $inventory->getSize(); $i < $size; ++$i) {