1: <?php
2: namespace aliuly\common;
3:
4: use aliuly\common\Session;
5: use aliuly\common\PluginCallbackTask;
6: use aliuly\common\mc;
7:
8: use pocketmine\plugin\PluginBase;
9: use pocketmine\item\Item;
10:
11: use pocketmine\event\player\PlayerQuitEvent;
12: use pocketmine\event\inventory\InventoryTransactionEvent;
13: use pocketmine\event\inventory\InventoryCloseEvent;
14:
15: use pocketmine\inventory\ChestInventory;
16: use pocketmine\inventory\PlayerInventory;
17: use pocketmine\inventory\InventoryType;
18: use pocketmine\inventory\BaseTransaction;
19:
20: use pocketmine\tile\Chest;
21: use pocketmine\tile\Tile;
22: use pocketmine\nbt\tag\CompoundTag;
23: use pocketmine\nbt\tag\EnumTag;
24: use pocketmine\nbt\tag\StringTag;
25: use pocketmine\nbt\tag\IntTag;
26:
27: use aliuly\common\MPMU;
28:
29: 30: 31:
32: class ShoppingCart extends Session {
33: const tag = "shopping-cart";
34: protected $fakeChest;
35:
36: 37: 38:
39: public function __construct(PluginBase $owner) {
40: parent::__construct($owner);
41: $this->fakeChest = null;
42: }
43: private function getFakeChestTile() {
44: if ($this->fakeChest === null) {
45: $this->fakeChest = new Chest($this->plugin->getServer()->getDefaultLevel()->getChunk(0,0),
46: new CompoundTag("FakeChest", [
47: new EnumTag("Items",[]),
48: new StringTag("id", Tile::CHEST),
49: new IntTag("x",0),
50: new IntTag("y",0),
51: new IntTag("z",0),
52: ]));
53: }
54: return $this->fakeChest;
55: }
56:
57:
58: 59: 60: 61: 62: 63:
64:
65: public function onPlayerQuit(PlayerQuitEvent $ev) {
66: echo __METHOD__.",".__LINE__."\n";
67: $n = MPMU::iName($ev->getPlayer());
68: $xx = $this->getState(self::tag,$ev->getPlayer(),null);
69: if ($xx !== null) $this->restoreInv($ev->getPlayer());
70: parent::onPlayerQuit($ev);
71: echo __METHOD__.",".__LINE__."\n";
72: }
73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84:
85: public function start($buyer,$shop,$tile = null) {
86: if ($tile === null) $tile = $this->getFakeChestTile();
87:
88: if ($this->getState(self::tag,$buyer,null) !== null) return;
89: echo __METHOD__.",".__LINE__."\n";
90: $inv = [ "player" => [], "chest" => $tile ];
91: $inv["money"] = $this->owner->getMoney($buyer);
92: var_dump($inv["money"]);
93: $inv["shop"] = $shop;
94:
95: foreach ($buyer->getInventory()->getContents() as $slot=>&$item) {
96: $inv["player"][$slot] = implode(":",[ $item->getId(),
97: $item->getDamage(),
98: $item->getCount() ]);
99: }
100: $inv["chest"] = new ChestInventory($tile,$buyer);
101: $contents = [];
102: foreach ($shop as $idmeta=>$it) {
103: $item = clone $it[0];
104: $item->setCount($it[1]);
105: $contents[] = $item;
106: }
107: $inv["chest"]->setContents($contents);
108: $this->setState(self::tag,$buyer,$inv);
109: $buyer->getInventory()->clearAll();
110: $buyer->addWindow($inv["chest"]);
111: echo __METHOD__.",".__LINE__."\n";
112: }
113: 114: 115: 116: 117:
118: public function onTransaction(InventoryTransactionEvent $ev) {
119: echo __METHOD__.",".__LINE__."\n";
120: $tg = $ev->getTransaction();
121: $pl = null;
122: $ti = null;
123: foreach($tg->getInventories() as $i) {
124: echo "INV ".get_class($i)."\n";
125: if ($i instanceof PlayerInventory) {
126: $pl = $i->getHolder();
127: } else {
128: $ti = $i;
129: }
130: }
131: if ($pl == null || $ti == null) return;
132: $xx = $this->getState(self::tag,$pl,null);
133: if ($xx == null) return;
134:
135: echo __METHOD__.",".__LINE__."\n";
136: echo "PLAYER ".$pl->getName()." is buying\n";
137: echo "FROM SHOP ".$xx["shop"]."\n";
138:
139: $added = [];
140: foreach ($tg->getTransactions() as $t) {
141: if ($t->getInventory() instanceof PlayerInventory) {
142:
143: foreach ($this->playerInvTransaction($t) as $nt) {
144: $added[] = $nt;
145: }
146: continue;
147: }
148: foreach ($this->chestInvTransaction($t) as $nt) {
149: $added[] = $nt;
150: }
151: }
152: echo __METHOD__.",".__LINE__."\n";
153:
154:
155:
156: $tsinv = [];
157: foreach ($pl->getInventory()->getContents() as $slot=>$item) {
158: if ($item->getId() == Item::AIR) continue;
159: $tsinv[$slot] = [implode(":",[$item->getId(),$item->getDamage()]),
160: $item->getCount()];
161: }
162:
163:
164: echo __METHOD__.",".__LINE__."\n";
165:
166:
167: foreach ([$tg->getTransactions(),$added] as &$tset) {
168: foreach ($tset as &$nt) {
169: if ($nt->getInventory() instanceof PlayerInventory) {
170: $item = clone $nt->getTargetItem();
171: $slot = $nt->getSlot();
172: if ($item->getId() == Item::AIR) {
173: if(isset($tsinv[$slot])) unset($tsinv[$slot]);
174: } else {
175: $tsinv[$slot] = [ implode(":",
176: [ $item->getId(),
177: $item->getDamage()]),
178: $item->getCount() ];
179: }
180: }
181: }
182: }
183: echo __METHOD__.",".__LINE__."\n";
184:
185: echo $pl->getName()." has ".$xx["money"]."G\n";
186: $total = 0;
187: var_dump($xx["money"]);
188: var_dump($tsinv);
189:
190: foreach ($tsinv as $slot=>$item) {
191: list($idmeta,$cnt) = $item;
192: echo "slot=$slot idmeta=$idmeta cnt=$cnt\n";
193:
194: if (!isset($xx["shop"][$idmeta])) {
195: $pl->sendMessage(mc::_("Item shop error: %1%", $idmeta));
196: $ev->setCancelled();
197: return;
198: }
199: list($i,$price) = $xx["shop"][$idmeta];
200: echo "-$idmeta - $cnt/".$i->getCount()." * $price ...".(round($cnt/$i->getCount())*$price)."\n";
201: $total += round($cnt/$i->getCount())*$price;
202: }
203: echo "TOTAL=$total\n";
204: if ($total > $xx["money"]) {
205: $pl->sendMessage(mc::_("You do not have enough money."));
206: $pl->sendMessage(mc::_("You have %1%. You need %2%", $xx["money"], $total));
207: $ev->setCancelled();
208: return;
209: }
210: echo __METHOD__.",".__LINE__."\n";
211: foreach ($added as $nt) {
212: $tg->addTransaction($nt);
213: }
214:
215: foreach($tg->getInventories() as $i) {
216: $this->owner->getServer()->getScheduler()->scheduleDelayedTask(
217: new PluginCallbackTask($this->owner,[$i,"sendContents"],[$pl]),5);
218: $this->owner->getServer()->getScheduler()->scheduleDelayedTask(
219: new PluginCallbackTask($this->owner,[$i,"sendContents"],[$pl]),10);
220: $this->owner->getServer()->getScheduler()->scheduleDelayedTask(
221: new PluginCallbackTask($this->owner,[$i,"sendContents"],[$pl]),15);
222: }
223: }
224: 225: 226: 227: 228:
229: public function onClose(InventoryCloseEvent $ev) {
230: $pl = $ev->getPlayer();
231: $xx = $this->getState(self::tag,$pl,null);
232: if ($xx == null) return;
233:
234:
235: $basket = [];
236: $total = 0;
237: foreach ($pl->getInventory()->getContents() as $slot=>$item) {
238: if ($item->getId() == Item::AIR) continue;
239: $idmeta = implode(":",[$item->getId(),$item->getDamage()]);
240: if (!isset($xx["shop"][$idmeta])) continue;
241: list($i,$price) = $xx["shop"][$idmeta];
242: $total += round($item->getCount()/$i->getCount())*$price;
243: $basket[] = [ $item->getId(),$item->getDamage(), $item->getCount() ];
244: }
245:
246: $this->restoreInv($pl);
247:
248: if (count($basket) == 0) {
249: $pl->sendMessage(mc::_("No items purchased"));
250: return;
251: }
252: if ($total < $this->owner->getMoney($pl)) {
253: $this->owner->grantMoney($pl,-$total);
254: $pl->sendMessage(mc::n(
255: mc::_("Bought one item for %1%G", $total),
256: mc::_("Bought %1% items for %2%G", count($basket), $total),
257: count($basket)
258: ));
259: foreach ($basket as $ck) {
260: list($id,$meta,$cnt) = $ck;
261: $pl->getInventory()->addItem(Item::get($id,$meta,$cnt));
262: }
263: } else {
264: $pl->sendMessage(mc::_("Not enough money."));
265: $pl->sendMessage(mc::_("You need %1%G", $total));
266: }
267: }
268: private function playerInvTransaction($t) {
269: echo __METHOD__.",".__LINE__."\n";
270: $src = clone $t->getSourceItem();
271: $dst = clone $t->getTargetItem();
272:
273: if ($dst->getCount() == 0 || $dst->getId() == Item::AIR) return [];
274: echo __METHOD__.",".__LINE__."\n";
275: $srccnt = $src->getId() == Item::AIR ? 0 : $src->getCount();
276: $dstcnt = $dst->getId() == Item::AIR ? 0 : $dst->getCount();
277:
278: if ($srccnt == $dstcnt && $src->getId() == $dst->getId()) return [];
279: echo __METHOD__.",".__LINE__."\n";
280: $idmeta = implode(":",[$dst->getId(),$dst->getDamage()]);
281: $pl = $t->getInventory()->getHolder();
282: echo $pl->getName()."\n";
283: $xx = $this->getState(self::tag,$pl,null);
284: if ($xx == null) return [];
285: echo __METHOD__.",".__LINE__."\n";
286: list($i,$price) = $xx["shop"][$idmeta];
287: echo "i=".$i->getCount()." at ".$price."\n";
288: echo "dstcnt=$dstcnt srccnt=$srccnt\n";
289: if ($dstcnt > $srccnt) {
290:
291: $newcnt = $srccnt+$i->getCount();
292: if ($newcnt > $i->getMaxStackSize()) $newcnt -= $i->getCount();
293: } elseif ($dstcnt < $srccnt) {
294:
295: $newcnt = floor($dstcnt/$i->getCount())*$i->getCount();
296: }
297: if ($newcnt == $dstcnt) return [];
298: echo __METHOD__.",".__LINE__."\n";
299: echo "NEWCNT: $newcnt\n";
300: if ($newcnt == 0) {
301: $dst = Item::get(Item::AIR,0,0);
302: } else {
303: $dst->setCount($newcnt);
304: }
305: return [ new BaseTransaction($t->getInventory(),
306: $t->getSlot(),
307: clone $t->getTargetItem(),
308: clone $dst) ];
309: }
310: private function chestInvTransaction($t) {
311:
312: echo __METHOD__.",".__LINE__."\n";
313: $src = clone $t->getSourceItem();
314: $dst = clone $t->getTargetItem();
315: if ($dst->getId() == Item::AIR) {
316:
317: return [ new BaseTransaction($t->getInventory(),
318: $t->getSlot(),
319: clone $t->getTargetItem(),
320: clone $src) ];
321: }
322: if ($src->getId() == Item::AIR) {
323:
324: return [ new BaseTransaction($t->getInventory(),
325: $t->getSlot(),
326: clone $dst,
327: clone $src) ];
328: }
329: if ($dst->getCount() > 1) {
330:
331: $dst->setCount(1);
332: return [ new BaseTransaction($t->getInventory(),
333: $t->getSlot(),
334: clone $t->getTargetItem(),
335: clone $dst) ];
336: }
337: return [];
338: }
339: 340: 341: 342: 343:
344: public function restoreInv($pl) {
345: echo __METHOD__.",".__LINE__."\n";
346: $inv = $this->getState(self::tag,$pl,null);
347: if ($inv === null) return;
348: $pl->getInventory()->clearAll();
349: foreach ($inv["player"] as $slot=>$itdat) {
350: list($id,$meta,$cnt) = explode(":",$itdat);
351: $item = Item::get($id,$meta,$cnt);
352: $pl->getInventory()->setItem($slot,$item);
353: }
354: $this->unsetState(self::tag,$pl);
355: }
356:
357: }
358: