Lines
98.83%
85 / 86
Methods
83.33%
5 / 6
Classes
0.00%
0 / 1
| Name | Lines | Methods | CRAP | ||||
|---|---|---|---|---|---|---|---|
| __construct | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| from | 100.00% | 40 / 40 | 100.00% | 1 / 1 | 11 | ||
| detail | 100.00% | 28 / 28 | 100.00% | 1 / 1 | 28 | ||
| slot | 100.00% | 10 / 10 | 100.00% | 1 / 1 | 10 | ||
| summary | 0.00% | 0 / 1 | 0.00% | 0 / 1 | 2 | ||
| [Lorekeeper\Server\Event\NamedAfterClass] name | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 1 | ||
| 28 | final readonly class PlayerInventoryLoadedEvent implements Event | |
| 29 | { | |
| 30 | use NamedAfterClass; | |
| 31 | ||
| 32 | /** @param list<InventoryItem> $items */ | |
| 33 | public function __construct( | |
| 34 | public array $items, | |
| 35 | ) {} | |
| 36 | ||
| 37 | /** @return Option\Option<static> */ | |
| 38 | #[Override] | |
| 39 | public static function from(Message $message): Option\Option | |
| 40 | { | |
| 41 | if (!$message instanceof JsonMessage || ($message->data['cmd'] ?? null) !== 'loadInventoryBig') { | |
| 42 | return Option\none(); | |
| 43 | } | |
| 44 | ||
| 45 | try { | |
| 46 | $items = Coerce\vec(Coerce\shape([ | |
| 47 | 'ItemID' => Coerce\positive_int(), | |
| 48 | 'sName' => Coerce\non_empty_string(), | |
| 49 | 'sType' => Coerce\string(), | |
| 50 | 'sES' => Coerce\string(), | |
| 51 | 'sDesc' => Coerce\optional(Coerce\string()), | |
| 52 | 'iCost' => Coerce\optional(Coerce\uint()), | |
| 53 | 'bCoins' => Coerce\optional(Coerce\bool()), | |
| 54 | 'sFile' => Coerce\optional(Coerce\nullable(Coerce\string())), | |
| 55 | 'sLink' => Coerce\optional(Coerce\string()), | |
| 56 | 'bUpg' => Coerce\optional(Coerce\bool()), | |
| 57 | ], allowUnknownFields: true)) | |
| 58 | ->coerce($message->data['items'] ?? null); | |
| 59 | } catch (CoercionException $exception) { | |
| 60 | throw new MalformedEventException(static::class, 'items are missing or invalid', $exception); | |
| 61 | } | |
| 62 | ||
| 63 | $inventory = []; | |
| 64 | foreach ($items as $item) { | |
| 65 | $description = trim($item['sDesc'] ?? ''); | |
| 66 | $cost = $item['iCost'] ?? 0; | |
| 67 | $file = $item['sFile'] ?? ''; | |
| 68 | $link = $item['sLink'] ?? ''; | |
| 69 | $hasFile = str_ends_with($file, '.swf'); | |
| 70 | ||
| 71 | $inventory[] = new InventoryItem( | |
| 72 | new ItemId($item['ItemID']), | |
| 73 | new ItemName($item['sName']), | |
| 74 | self::detail($item['sType']), | |
| 75 | $description === '' ? Option\none() : Option\some(new ItemDescription($description)), | |
| 76 | $cost === 0 | |
| 77 | ? Option\none() | |
| 78 | : Option\some( | |
| 79 | new ItemPrice($item['bCoins'] ?? false ? new AdventureCoins($cost) : new Gold($cost)), | |
| 80 | ), | |
| 81 | $hasFile ? Option\some(new Gamefile($file)) : Option\none(), | |
| 82 | $hasFile && $link !== '' ? Option\some(new Linkage($link)) : Option\none(), | |
| 83 | self::slot($item['sES']), | |
| 84 | $item['bUpg'] ?? false, | |
| 85 | ); | |
| 86 | } | |
| 87 | ||
| 88 | return Option\some(new static($inventory)); | |
| 89 | } | |
| 90 | ||
| 91 | /** @throws MalformedEventException */ | |
| 92 | private static function detail(string $type): Type\Equipment|Type\Weapon|Type\House|Type\Misc | |
| 93 | { | |
| 94 | return match ($type) { | |
| 95 | 'Armor' => Type\Equipment::Armor, | |
| 96 | 'Cape' => Type\Equipment::Cape, | |
| 97 | 'Class' => Type\Equipment::CharacterClass, | |
| 98 | 'Misc' => Type\Equipment::Ground, | |
| 99 | 'Helm' => Type\Equipment::Helm, | |
| 100 | 'Necklace' => Type\Equipment::Necklace, | |
| 101 | 'Pet' => Type\Equipment::Pet, | |
| 102 | 'Axe' => Type\Weapon::Axe, | |
| 103 | 'Bow' => Type\Weapon::Bow, | |
| 104 | 'Dagger' => Type\Weapon::Dagger, | |
| 105 | 'Gauntlet' => Type\Weapon::Gauntlet, | |
| 106 | 'Gun' => Type\Weapon::Gun, | |
| 107 | 'HandGun' => Type\Weapon::HandGun, | |
| 108 | 'Mace' => Type\Weapon::Mace, | |
| 109 | 'Polearm' => Type\Weapon::Polearm, | |
| 110 | 'Rifle' => Type\Weapon::Rifle, | |
| 111 | 'Staff' => Type\Weapon::Staff, | |
| 112 | 'Sword' => Type\Weapon::Sword, | |
| 113 | 'Wand' => Type\Weapon::Wand, | |
| 114 | 'Whip' => Type\Weapon::Whip, | |
| 115 | 'Floor Item' => Type\House::Floor, | |
| 116 | 'House' => Type\House::House, | |
| 117 | 'Wall Item' => Type\House::Wall, | |
| 118 | 'ServerUse' => Type\Misc::Boost, | |
| 119 | 'Enhancement' => Type\Misc::Enhancement, | |
| 120 | 'Item', 'Note', 'Quest Item', 'Resource' => Type\Misc::Generic, | |
| 121 | default => throw new MalformedEventException(static::class, "unknown item type '{$type}'"), | |
| 122 | }; | |
| 123 | } | |
| 124 | ||
| 125 | /** | |
| 126 | * @throws MalformedEventException | |
| 127 | * | |
| 128 | * @return Option\Option<EquipmentSlot> | |
| 129 | */ | |
| 130 | private static function slot(string $code): Option\Option | |
| 131 | { | |
| 132 | return match ($code) { | |
| 133 | 'None' => Option\none(), | |
| 134 | 'Weapon' => Option\some(EquipmentSlot::Weapon), | |
| 135 | 'ar', 'co' => Option\some(EquipmentSlot::Armor), | |
| 136 | 'he' => Option\some(EquipmentSlot::Helm), | |
| 137 | 'ba' => Option\some(EquipmentSlot::Cape), | |
| 138 | 'pe' => Option\some(EquipmentSlot::Pet), | |
| 139 | 'mi' => Option\some(EquipmentSlot::Ground), | |
| 140 | 'am' => Option\some(EquipmentSlot::Necklace), | |
| 141 | default => throw new MalformedEventException(static::class, "unknown equipment slot '{$code}'"), | |
| 142 | }; | |
| 143 | } | |
| 144 | ||
| 145 | #[Override] | |
| 146 | public function summary(): string | |
| 147 | { | |
| 148 | return 'Inventory loaded: ' . count($this->items) . ' items'; | |
| 149 | } | |
| 150 | } |
From Lorekeeper\Server\Event\NamedAfterClass
| 7 | trait NamedAfterClass | |
| 8 | { | |
| 9 | public function name(): string | |
| 10 | { | |
| 11 | $class = static::class; | |
| 12 | ||
| 13 | return (string) preg_replace( | |
| 14 | '/Event$/', | |
| 15 | replacement: '', | |
| 16 | subject: substr($class, (int) strrpos($class, needle: '\\') + 1), | |
| 17 | ); | |
| 18 | } | |
| 19 | } |