Overview

Namespaces

  • aliuly
    • common
      • selectors
    • loader
  • xPaw

Classes

  • aliuly\common\ArmorItems
  • aliuly\common\BasicCli
  • aliuly\common\BasicHelp
  • aliuly\common\BasicPlugin
  • aliuly\common\ChatSession
  • aliuly\common\Cmd
  • aliuly\common\CmdSelector
  • aliuly\common\ExpandVars
  • aliuly\common\FastTransfer
  • aliuly\common\FileUtils
  • aliuly\common\FreezeSession
  • aliuly\common\GetMotd
  • aliuly\common\GetMotdAsyncTask
  • aliuly\common\InvisibleSession
  • aliuly\common\InvUtils
  • aliuly\common\ItemName
  • aliuly\common\mc
  • aliuly\common\mc2
  • aliuly\common\MoneyAPI
  • aliuly\common\MPMU
  • aliuly\common\Npc
  • aliuly\common\PermUtils
  • aliuly\common\PluginAsyncTask
  • aliuly\common\PluginCallbackTask
  • aliuly\common\PMScript
  • aliuly\common\QueryAsyncTask
  • aliuly\common\Rcon
  • aliuly\common\RconTask
  • aliuly\common\selectors\All
  • aliuly\common\selectors\AllEntity
  • aliuly\common\selectors\BaseSelector
  • aliuly\common\selectors\Random
  • aliuly\common\Session
  • aliuly\common\ShieldSession
  • aliuly\common\ShoppingCart
  • aliuly\common\SignUtils
  • aliuly\common\SkinUtils
  • aliuly\common\SpySession
  • aliuly\common\SubCommandMap
  • aliuly\common\TPUtils
  • aliuly\loader\Main
  • xPaw\MinecraftQuery

Exceptions

  • xPaw\MinecraftQueryException
  • Overview
  • Namespace
  • Class
  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:  * Implements ShoppingCart iterations
 31:  */
 32: class ShoppingCart extends Session {
 33:   const tag = "shopping-cart";
 34:   protected $fakeChest;
 35: 
 36:   /**
 37:    * @param PluginBase $owner - plugin that owns this session
 38:    */
 39:   public function __construct(PluginBase $owner) {
 40:     parent::__construct($owner);    // We do it here so to prevent the registration of listeners
 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:      * Handle player quit events.  Restore player's inventory before resetting
 60:      * state.
 61:    *
 62:    * @param PlayerQuitEvent $ev - Quit event
 63:      */
 64: 
 65:   public function onPlayerQuit(PlayerQuitEvent $ev) {
 66:     echo __METHOD__.",".__LINE__."\n";//##DEBUG
 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";//##DEBUG
 72:     }
 73:   /**
 74:    * Starts a Shopping Cart session.
 75:    *
 76:    * @param Player $buyer - player starting buying session
 77:    * @param array $shop - Shop items
 78:    * @param ChestTile|null $tile - Shop chest to use, otherwise null
 79:    *
 80:    * The $shop array should contain the following:
 81:    *
 82:    *      "id:meta" => [ pocketmine\item\Item, price ],
 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";//##DEBUG
 90:         $inv = [ "player" => [], "chest" => $tile ];
 91:         $inv["money"] = $this->owner->getMoney($buyer);
 92:         var_dump($inv["money"]);//##DEBUG
 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]); // Count is the price of the item...
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";//##DEBUG
112:     }
113:   /**
114:    * Handle inventory transactions
115:    *
116:    * @param InventoryTransactionEvent $ev
117:    */
118:     public function onTransaction(InventoryTransactionEvent $ev) {
119:         echo __METHOD__.",".__LINE__."\n";//##DEBUG
120:         $tg = $ev->getTransaction();
121:         $pl = null;
122:         $ti = null;
123:         foreach($tg->getInventories() as $i) {
124:             echo "INV ".get_class($i)."\n";//##DEBUG
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; // This is a normal Chest transaction...
134: 
135:         echo __METHOD__.",".__LINE__."\n";//##DEBUG
136:         echo "PLAYER ".$pl->getName()." is buying\n";//##DEBUG
137:     echo "FROM SHOP ".$xx["shop"]."\n";//##DEBUG
138: 
139:         $added = [];
140:         foreach ($tg->getTransactions() as $t) {
141:             if ($t->getInventory() instanceof PlayerInventory) {
142:                 // Handling PlayerInventory changes...
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";//##DEBUG
153: 
154:         // Test if the transaction is valid...
155:         // Make a copy of current inventory
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:         //var_dump($tsinv);//##DEBUG
163: 
164:         echo __METHOD__.",".__LINE__."\n";//##DEBUG
165:         //print_r($tsinv);//##DEBUG
166:         // Apply transactions to copy
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";//##DEBUG
184:         //      print_r($tsinv);//##DEBUG
185:         echo $pl->getName()." has ".$xx["money"]."G\n";//##DEBUG
186:         $total = 0;
187:         var_dump($xx["money"]);//##DEBUG
188:         var_dump($tsinv);//##DEBUG
189: 
190:         foreach ($tsinv as $slot=>$item) {
191:             list($idmeta,$cnt) = $item;
192:             echo "slot=$slot idmeta=$idmeta cnt=$cnt\n";//##DEBUG
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";//##DEBUG
201:             $total += round($cnt/$i->getCount())*$price;
202:         }
203:         echo "TOTAL=$total\n";//##DEBUG
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";//##DEBUG
211:         foreach ($added as $nt) {
212:             $tg->addTransaction($nt);
213:         }
214:         // Make sure inventory is properly synced
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:    * Close inventory event
226:    *
227:    * @param InventoryCloseEvent $ev
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:         // Compute shopping basket
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:         // Restore original inventory...
246:         $this->restoreInv($pl);
247:         // Check-out
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";//##DEBUG
270:         $src = clone $t->getSourceItem();
271:         $dst = clone $t->getTargetItem();
272:         // This becomes nothing... not much to do...
273:         if ($dst->getCount() == 0 || $dst->getId() == Item::AIR) return [];
274:         echo __METHOD__.",".__LINE__."\n";//##DEBUG
275:         $srccnt = $src->getId() == Item::AIR ? 0 : $src->getCount();
276:         $dstcnt = $dst->getId() == Item::AIR ? 0 : $dst->getCount();
277:         // This is a weird transaction...
278:         if ($srccnt == $dstcnt && $src->getId() == $dst->getId()) return [];
279:         echo __METHOD__.",".__LINE__."\n";//##DEBUG
280:         $idmeta = implode(":",[$dst->getId(),$dst->getDamage()]);
281:         $pl = $t->getInventory()->getHolder();
282:         echo $pl->getName()."\n";//##DEBUG
283:         $xx = $this->getState(self::tag,$pl,null);
284:         if ($xx == null) return []; // Oops...
285:         echo __METHOD__.",".__LINE__."\n";//##DEBUG
286:         list($i,$price) = $xx["shop"][$idmeta];
287:         echo "i=".$i->getCount()." at ".$price."\n";//##DEBUG
288:         echo "dstcnt=$dstcnt srccnt=$srccnt\n";//##DEBUG
289:         if ($dstcnt > $srccnt) {
290:             // Increase
291:             $newcnt = $srccnt+$i->getCount();
292:             if ($newcnt > $i->getMaxStackSize()) $newcnt -= $i->getCount();
293:         } elseif ($dstcnt < $srccnt) {
294:             // Decrease
295:             $newcnt = floor($dstcnt/$i->getCount())*$i->getCount();
296:         }
297:         if ($newcnt == $dstcnt) return [];
298:         echo __METHOD__.",".__LINE__."\n";//##DEBUG
299:         echo "NEWCNT: $newcnt\n";//##DEBUG
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:         // Moving stock to buyer
312:         echo __METHOD__.",".__LINE__."\n";//##DEBUG
313:         $src = clone $t->getSourceItem();
314:         $dst = clone $t->getTargetItem();
315:         if ($dst->getId() == Item::AIR) {
316:             // Inventory never runs out!
317:             return [ new BaseTransaction($t->getInventory(),
318:                                                   $t->getSlot(),
319:                                                   clone $t->getTargetItem(),
320:                                                   clone $src) ];
321:         }
322:         if ($src->getId() == Item::AIR) {
323:             // Do not accept new Inventory!
324:             return [ new BaseTransaction($t->getInventory(),
325:                                                   $t->getSlot(),
326:                                                   clone $dst,
327:                                                   clone $src) ];
328:         }
329:         if ($dst->getCount() > 1) {
330:             // Inventory never increases!
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:    * Restore player's inventory
341:    *
342:    * @param Player $pl
343:    */
344:     public function restoreInv($pl) {
345:         echo __METHOD__.",".__LINE__."\n";//##DEBUG
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: 
API documentation generated by ApiGen