tiny-essentials
Version:
Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.
1 lines • 25 kB
JavaScript
(()=>{"use strict";var e={d:(t,i)=>{for(var r in i)e.o(i,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:i[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};e.d(t,{TinyInventoryTrader:()=>n});class i{static#e=new Map;static get itemRegistry(){const e={},t=Object.fromEntries(i.#e);for(const i in t)e[i]={...t[i],metadata:{...t[i].metadata}};return e}static defineItem(e){if(!e||"object"!=typeof e)throw new TypeError("Config must be a valid object.");if(!e.id||"string"!=typeof e.id)throw new TypeError("Item must have a valid string 'id'.");if(void 0!==e.weight&&("number"!=typeof e.weight||e.weight<0))throw new TypeError(`weight must be a number >= 0. Received: ${e.weight}`);if(void 0!==e.maxStack&&(!Number.isInteger(e.maxStack)||e.maxStack<=0))throw new TypeError(`maxStack must be a positive integer. Received: ${e.maxStack}`);if(void 0!==e.metadata&&"object"!=typeof e.metadata)throw new TypeError("metadata must be an object.");if(void 0!==e.onUse&&null!==e.onUse&&"function"!=typeof e.onUse)throw new TypeError("onUse must be a function or null.");if(void 0!==e.type&&null!==e.type&&"string"!=typeof e.type)throw new TypeError("type must be a string or null.");i.#e.set(e.id,{id:e.id,weight:e.weight||0,maxStack:e.maxStack||1,metadata:e.metadata||{},type:e.type??null,onUse:"function"==typeof e.onUse?e.onUse:null})}static removeItem(e){if("string"!=typeof e)throw new TypeError("itemId must be a string.");return i.#e.delete(e)}static hasItem(e){if("string"!=typeof e)throw new TypeError("itemId must be a string.");return i.#e.has(e)}static getItem(e){if("string"!=typeof e)throw new TypeError("itemId must be a string.");const t=i.#e.get(e);if(!t)throw new Error(`Item '${e}' not defined in registry.`);return t}#t=new Map;#i={add:[],remove:[],use:[],set:[]};#r=[];#n;#o;#s;#a;get maxStack(){return this.#n}set maxStack(e){if(!Number.isInteger(e)||Number.isFinite(e)&&e<=0)throw new TypeError(`maxStack must be a positive integer. Received: ${e}`);this.#n=e}get maxSize(){return this.#o}set maxSize(e){if(null!==e&&(!Number.isInteger(e)||e<=0))throw new TypeError(`maxSize must be null or a positive integer. Received: ${e}`);this.#o=e}get maxSlots(){return this.#s}set maxSlots(e){if(null!==e&&(!Number.isInteger(e)||e<=0))throw new TypeError(`maxSlots must be null or a positive integer. Received: ${e}`);this.#s=e}get maxWeight(){return this.#a}set maxWeight(e){if(null!==e&&("number"!=typeof e||e<=0))throw new TypeError(`maxWeight must be null or a positive number. Received: ${e}`);this.#a=e}get events(){return{add:[...this.#i.add],remove:[...this.#i.remove],use:[...this.#i.use],set:[...this.#i.set]}}get items(){return[...this.#r].map(e=>e?this.#l(e):null)}get specialSlots(){return new Map([...this.#t.entries()].map(([e,t])=>[e,{type:t.type,item:t.item?this.#l(t.item):null}]))}get size(){const e=this.getAllItems();let t=0;for(const i of e)t+=i.quantity;return t}get slotsSize(){return this.getAllItems().length}get weight(){return this.getAllItems().reduce((e,t)=>{const r=i.getItem(t.id);return e+(r?.weight||0)*t.quantity},0)}_cleanNulls(){let e=this.#r.length-1;for(;e>=0&&null===this.#r[e];)e--;this.#r=this.#r.slice(0,e+1)}constructor(e={}){if("object"!=typeof e||null===e)throw new TypeError("`options` must be an object.");if(void 0!==e.maxWeight&&null!==e.maxWeight&&"number"!=typeof e.maxWeight)throw new TypeError("`maxWeight` must be a number or null.");if(void 0!==e.maxSlots&&null!==e.maxSlots&&"number"!=typeof e.maxSlots)throw new TypeError("`maxSlots` must be a number or null.");if(void 0!==e.maxSize&&null!==e.maxSize&&"number"!=typeof e.maxSize)throw new TypeError("`maxSize` must be a number or null.");if(void 0!==e.maxStack&&"number"!=typeof e.maxStack)throw new TypeError("`maxStack` must be a number.");if(void 0!==e.specialSlots&&"object"!=typeof e.specialSlots)throw new TypeError("`specialSlots` must be an object if defined.");if(this.#a=e.maxWeight??null,this.#s=e.maxSlots??null,this.#o=e.maxSize??null,this.#n=e.maxStack??1/0,e.specialSlots)for(const t in e.specialSlots){const i=e.specialSlots[t];if("object"!=typeof i||null===i)throw new TypeError("Each `specialSlot` entry must be an object.");if(void 0!==i.type&&null!==i.type&&"string"!=typeof i.type)throw new TypeError("`specialSlot.type` must be a string or null.");this.#t.set(t,{type:i.type??null,item:null})}}hasSpace({weight:e=0,sizeLength:t=0,slotsLength:i=0}={}){if("number"!=typeof e)throw new TypeError("`weight` must be a number.");if("number"!=typeof t)throw new TypeError("`sizeLength` must be a number.");if("number"!=typeof i)throw new TypeError("`slotsLength` must be a number.");return!(this.areFull(t)||this.areFullSlots(i)||this.isHeavy(e))}isHeavy(e=0){if("number"!=typeof e)throw new TypeError("`extraWeight` must be a number.");return null!==this.#a&&this.weight+e>this.#a}areFull(e=0){if("number"!=typeof e)throw new TypeError("`extraLength` must be a number.");return null!==this.#o&&this.size+e>this.#o}isFull(e=0){if("number"!=typeof e)throw new TypeError("`extraLength` must be a number.");return null!==this.#o&&this.size+e>=this.#o}areFullSlots(e=0){if("number"!=typeof e)throw new TypeError("`extraLength` must be a number.");return null!==this.#s&&this.slotsSize+e>this.#s}isFullSlots(e=0){if("number"!=typeof e)throw new TypeError("`extraLength` must be a number.");return null!==this.#s&&this.slotsSize+e>=this.#s}#m(e,t){if("string"!=typeof e)throw new TypeError("`type` must be a string.");if("object"!=typeof t||null===t)throw new TypeError("`payload` must be an object.");if(this.#i[e])for(const i of this.#i[e])i(t)}off(e,t){if("string"!=typeof e)throw new TypeError("`eventType` must be a string.");if("function"!=typeof t)throw new TypeError("`callback` must be a function.");if(!this.#i[e])return;const i=this.#i[e],r=i.indexOf(t);-1!==r&&i.splice(r,1)}offAll(e){if("string"!=typeof e)throw new TypeError("`eventType` must be a string.");this.#i[e]&&(this.#i[e]=[])}cloneEventCallbacks(e){if("string"!=typeof e)throw new TypeError("`eventType` must be a string.");return this.#i[e]?[...this.#i[e]]:[]}onAddItem(e){if("function"!=typeof e)throw new TypeError("`callback` must be a function.");this.#i.add.push(e)}onSetItem(e){if("function"!=typeof e)throw new TypeError("`callback` must be a function.");this.#i.set.push(e)}onRemoveItem(e){if("function"!=typeof e)throw new TypeError("`callback` must be a function.");this.#i.remove.push(e)}onUseItem(e){if("function"!=typeof e)throw new TypeError("`callback` must be a function.");this.#i.use.push(e)}compactInventory(){this.#r=this.#r.filter((e,t)=>{const i=null!==e;return i||this.#m("remove",{index:t,item:null,isCollection:!0,specialSlot:null,remove:()=>{}}),i})}addItem({itemId:e,quantity:t=1,metadata:r={},forceSpace:n=!1}){if("string"!=typeof e)throw new TypeError("`itemId` must be a string.");if("number"!=typeof t||!Number.isFinite(t)||t<=0)throw new TypeError("`quantity` must be a positive number.");if("object"!=typeof r||null===r)throw new TypeError("`metadata` must be an object.");if("boolean"!=typeof n)throw new TypeError("`forceSpace` must be a boolean.");const o=i.getItem(e);let s=t;const a=o.maxStack<=this.#n?o.maxStack:this.#n,l=[],m=(e,t)=>JSON.stringify(e)===JSON.stringify(t);let u=!0;for(;s>0&&u;){u=!1;for(const t in this.#r){const i=this.#r[t];if(i&&i.id===e&&i.quantity<a&&m(i.metadata,r)){const e=Math.min(a-i.quantity,s);if(!n&&!this.hasSpace({weight:o.weight*e,sizeLength:e}))continue;i.quantity+=e,s-=e,u=!0;const r=Number(t),m=l.findIndex(e=>e.index===r);if(m<0?l.push({index:r,quantity:e}):l[m].quantity+=e,this.#m("add",{item:this.#l(i),index:r,isCollection:!0,specialSlot:null,remove:this.#u({locationType:"normal",slotIndex:r,forceSpace:n,item:i})}),s<=0)break}}}if(s>0)for(const t in this.#r)if(null===this.#r[t]){const i=Math.min(a,s);if(!n&&!this.hasSpace({weight:o.weight*i,sizeLength:i}))continue;const m={id:e,quantity:i,metadata:r};this.#r[t]=m,s-=i;const u=Number(t),c=l.findIndex(e=>e.index===u);if(c<0?l.push({index:u,quantity:i}):l[c].quantity+=i,this.#m("add",{item:this.#l(m),index:u,isCollection:!0,specialSlot:null,remove:this.#u({locationType:"normal",slotIndex:u,forceSpace:n,item:m})}),s<=0)break}for(;s>0;){const t=Math.min(a,s);if(!n&&!this.hasSpace({weight:o.weight*t,sizeLength:t,slotsLength:1}))break;const i={id:e,quantity:t,metadata:r};this.#r.push(i);const m=this.#r.length-1,u=l.findIndex(e=>e.index===m);u<0?l.push({index:m,quantity:t}):l[u].quantity+=t,this.#m("add",{item:this.#l(i),index:m,isCollection:!0,specialSlot:null,remove:this.#u({locationType:"normal",slotIndex:m,forceSpace:n,item:i})}),s-=t}return{remaining:s,placesAdded:l}}getItemFrom(e){if("number"!=typeof e||!Number.isInteger(e))throw new TypeError("`slotIndex` must be an integer.");if(e<0||e>=this.#r.length)throw new Error(`Slot index '${e}' out of bounds .`);return this.#r[e]?this.#l(this.#r[e]):null}setItem({slotIndex:e,item:t,forceSpace:r=!1}){if("number"!=typeof e||!Number.isInteger(e))throw new TypeError("`slotIndex` must be an integer.");if("boolean"!=typeof r)throw new TypeError("`forceSpace` must be a boolean.");const n=t&&"object"==typeof t&&"string"==typeof t.id&&"number"==typeof t.quantity&&!Number.isNaN(t.quantity)&&Number.isFinite(t.quantity)&&t.quantity>-1&&"object"==typeof t.metadata;if(null!==t&&!n)throw new Error("Invalid item type: must be null or a valid InventoryItem.");const o=t?i.#e.get(t.id):null;if(null!==t&&!o)throw new Error(`Item '${t?.id??"unknown"}' not defined in registry.`);if(o&&t){const e=o.maxStack<=this.#n?o.maxStack:this.#n;if(t.quantity>e)throw new Error(`Item '${t.id}' exceeds max stack size. Allowed: ${e}, got: ${t.quantity}.`)}if(null!==this.#s&&(e<0||e>=this.#s))throw new Error(`Slot index ${e} out of range.`);const s=this.#r[e]??null,a=s?i.#e.get(s.id)??null:null,l=(e,t)=>t?t.weight*(e?e.quantity:0):0,m=e=>e?e.quantity:0;if(!r&&!this.hasSpace({weight:l(t,o)-l(s,a),sizeLength:m(t)-m(s)}))throw new Error("Inventory is full or overweight.");for(;this.#r.length<=e;)this.#r.push(null);this.#r[e]=t,this._cleanNulls(),this.#m("set",{index:e,isCollection:!0,item:t?this.#l(t):null,specialSlot:null,remove:t?this.#u({locationType:"normal",slotIndex:e,forceSpace:r,item:t}):()=>{}})}deleteItem(e,t=!1){if("number"!=typeof e||!Number.isInteger(e))throw new TypeError("`slotIndex` must be an integer.");if("boolean"!=typeof t)throw new TypeError("`forceSpace` must be a boolean.");this.setItem({slotIndex:e,item:null,forceSpace:t})}moveItem(e,t,i=!1){if("number"!=typeof e||!Number.isInteger(e))throw new TypeError("`fromIndex` must be an integer.");if("number"!=typeof t||!Number.isInteger(t))throw new TypeError("`toIndex` must be an integer.");if("boolean"!=typeof i)throw new TypeError("`forceSpace` must be a boolean.");const r=this.#r[e];if(!r)throw new Error(`No item found in slot ${e}.`);this.setItem({slotIndex:t,item:r,forceSpace:i}),this.setItem({slotIndex:e,item:null,forceSpace:i})}removeItem({itemId:e,metadata:t=null,quantity:i=1}){if("string"!=typeof e)throw new TypeError("`itemId` must be a string.");if(null!==t&&"object"!=typeof t)throw new TypeError("`metadata` must be an object or null.");if("number"!=typeof i||!Number.isFinite(i)||i<=0)throw new TypeError("`quantity` must be a positive number.");let r=i;const n=(e,t)=>JSON.stringify(e)===JSON.stringify(t);for(let i=0;i<this.#r.length;i++){const o=this.#r[i];if(o&&o.id===e&&(null===t||n(o.metadata,t))){const e=Math.min(o.quantity,r);o.quantity-=e,r-=e;const t=Number(i);if(o.quantity<=0&&(this.#r[i]=null),r<=0)return this._cleanNulls(),this.#m("remove",{index:t,item:this.#l(o),isCollection:!0,specialSlot:null,remove:this.#u({locationType:"normal",slotIndex:t,item:o})}),!0}}return this._cleanNulls(),this.#t.forEach((i,o)=>{if(r>0&&i.item&&i.item.id===e&&(null===t||n(i.item.metadata,t))){const e=Math.min(i.item.quantity,r);i.item.quantity-=e,i.item.quantity<0&&(i.item.quantity=0),r-=e,i.item.quantity<=0&&(i.item=null),this.#t.set(o,i),this.#m("remove",{index:null,item:i.item?this.#l(i.item):null,isCollection:!1,specialSlot:o,remove:i.item?this.#u({locationType:"special",specialSlot:o,item:i.item}):()=>{}})}}),r<=0}#u({locationType:e,specialSlot:t,slotIndex:i,item:r,forceSpace:n=!1}){if("normal"!==e&&"special"!==e)throw new TypeError("`locationType` must be 'normal' or 'special'.");if("boolean"!=typeof n)throw new TypeError("`forceSpace` must be boolean.");if(!r||"object"!=typeof r)throw new TypeError("`item` must be an InventoryItem object.");if("special"===e&&t&&"string"!=typeof t)throw new TypeError("`specialSlot` must be a string when locationType is 'special'.");if("normal"===e&&"number"!=typeof i)throw new TypeError("`slotIndex` must be a number when locationType is 'normal'.");return(o=n)=>{if("special"===e&&t){const e=this.#t.get(t);if(!e?.item)throw new Error(`Special slot '${t}' is empty.`);e.item.quantity>1?(e.item.quantity-=1,this.#t.set(t,e)):this.setSpecialSlot({slotId:t,item:null,forceSpace:o})}else{if("number"!=typeof i)throw new Error("Invalid remove operation: no valid slotIndex or specialSlot provided.");r.quantity>1?this.setItem({slotIndex:i,item:{...r,quantity:r.quantity-1},forceSpace:o}):this.setItem({slotIndex:i,item:null,forceSpace:o})}}}useItem({slotIndex:e,specialSlot:t,forceSpace:r=!1},...n){if(void 0!==e&&("number"!=typeof e||!Number.isInteger(e)))throw new TypeError("`slotIndex` must be an integer if provided.");if(void 0!==t&&"string"!=typeof t)throw new TypeError("`specialSlot` must be a string if provided.");if("boolean"!=typeof r)throw new TypeError("`forceSpace` must be boolean.");let o=null,s="normal",a=null;if(t){if(!this.#t.has(t))throw new Error(`Special slot '${t}' not found.`);o=this.#t.get(t).item,s="special"}else a=this.#r,o=a[e??-1]??null,s="normal";if(!o)throw new Error("special"===s?`No item found in special slot '${t}'.`:`No item found in slot ${e} of inventory.`);const l=i.getItem(o.id);if(l.onUse){const i={inventory:this,item:this.#l(o),index:e??null,specialSlot:t??null,isCollection:!!a,itemDef:l,remove:this.#u({locationType:s,specialSlot:t,slotIndex:e,forceSpace:r,item:o}),...n},m=l.onUse(i);return this.#m("use",i),m}return null}hasSpecialSlot(e){if("string"!=typeof e)throw new TypeError("`slotId` must be a string.");return this.#t.has(e)}getSpecialItem(e){if("string"!=typeof e)throw new TypeError("`slotId` must be a string.");if(!this.#t.has(e))throw new Error(`Special slot '${e}' does not exist.`);const t=this.#t.get(e);return t?.item?this.#l(t.item):null}getSpecialSlotType(e){if("string"!=typeof e)throw new TypeError("`slotId` must be a string.");if(!this.#t.has(e))throw new Error(`Special slot '${e}' does not exist.`);const t=this.#t.get(e);return t?.type??null}setSpecialSlot({slotId:e,item:t,forceSpace:r=!1}){if("string"!=typeof e)throw new TypeError("`slotId` must be a string.");if("boolean"!=typeof r)throw new TypeError("`forceSpace` must be boolean.");if(!this.#t.has(e))throw new Error(`Special slot '${e}' not found.`);const n=t&&"object"==typeof t&&"string"==typeof t.id&&"number"==typeof t.quantity&&!Number.isNaN(t.quantity)&&Number.isFinite(t.quantity)&&t.quantity>-1&&"object"==typeof t.metadata;if(null!==t&&!n)throw new Error("Invalid item type: must be null or a valid InventoryItem.");const o=t?i.#e.get(t.id):null;if(null!==t&&!o)throw new Error(`Item '${t?.id??"unknown"}' not defined in registry.`);const s=this.#t.get(e);if(!s)throw new Error(`Special slot ${e} out of range for slot '${e}'.`);const a=s.item?i.#e.get(s.item.id):null,l=(e,t)=>t?t.weight*(e?1:0):0,m=e=>e?1:0;if(!r&&!this.hasSpace({weight:l(t,o)-l(s.item,a),sizeLength:m(t)-m(s.item)}))throw new Error("Inventory is full or overweight.");s.item=t,this.#m("set",{index:null,item:t?this.#l(t):null,isCollection:!1,specialSlot:e,remove:t?this.#u({locationType:"special",specialSlot:e,forceSpace:r,item:t}):()=>{}})}deleteSpecialItem(e,t=!1){if("string"!=typeof e)throw new TypeError("`slotId` must be a string.");if("boolean"!=typeof t)throw new TypeError("`forceSpace` must be boolean.");this.setSpecialSlot({slotId:e,item:null,forceSpace:t})}equipItem({slotId:e,slotIndex:t,quantity:r=1,forceSpace:n=!1}){if("string"!=typeof e)throw new TypeError("`slotId` must be a string.");if("number"!=typeof t||!Number.isInteger(t))throw new TypeError("`slotIndex` must be an integer.");if("number"!=typeof r||!Number.isFinite(r)||r<=0)throw new TypeError("`quantity` must be a positive number.");if("boolean"!=typeof n)throw new TypeError("`forceSpace` must be boolean.");if(r<=0||!Number.isFinite(r))throw new Error(`Invalid quantity '${r}'.`);if(!this.#t.has(e))throw new Error(`Special slot '${e}' does not exist.`);const o=this.getItemFrom(t);if(!o)throw new Error(`No item found in inventory slot ${t}.`);if(o.quantity<r)throw new Error(`Not enough quantity of item '${o.id}' in inventory slot.`);const s=i.getItem(o.id),a=this.#t.get(e);if(!a)throw new Error(`Slot '${e}' not defined in registry.`);const l=a.type??null;if(null!==l&&s.type!==l)throw new Error(`Item '${o.id}' cannot be equipped in slot '${e}'.`);const m=Math.min(s.maxStack,this.#n);if(a.item&&a.item.id===o.id){const t=Math.max(0,m-a.item.quantity);if(t<=0)return r;const i=Math.min(r,t);return this.removeItem({itemId:o.id,quantity:i,metadata:null}),a.item.quantity+=i,this.#t.set(e,a),r-i}a.item&&this.unequipItem({slotId:e,forceSpace:n});const u=Math.min(r,m);return this.removeItem({itemId:o.id,quantity:u,metadata:null}),a.item={id:o.id,quantity:u,metadata:o.metadata},this.#t.set(e,a),r-u}unequipItem({slotId:e,quantity:t=null,forceSpace:i=!1}){if("string"!=typeof e)throw new TypeError("`slotId` must be a string.");if(null!==t&&("number"!=typeof t||!Number.isFinite(t)||t<=0))throw new TypeError("`quantity` must be a positive number or null.");if("boolean"!=typeof i)throw new TypeError("`forceSpace` must be boolean.");if(!this.#t.has(e))throw new Error(`Special slot '${e}' does not exist.`);const r=this.#t.get(e);if(!r)throw new Error(`Slot '${e}' not defined in registry.`);if(!r.item)return!1;const n=r.item,o=null===t?n.quantity:t;if(o<=0)throw new Error(`Invalid unequip quantity: ${o}`);if(o>n.quantity)throw new Error(`Not enough items in slot '${e}' to unequip.`);return this.addItem({itemId:n.id,quantity:o,metadata:n.metadata,forceSpace:i}),o===n.quantity?r.item=null:(n.quantity-=o,r.item=n),this.#t.set(e,r),!0}#l(e){if(!e||"object"!=typeof e)throw new TypeError("`item` must be an InventoryItem object.");if("string"!=typeof e.id)throw new TypeError("`item.id` must be a string.");if("number"!=typeof e.quantity||!Number.isFinite(e.quantity))throw new TypeError("`item.quantity` must be a finite number.");if(!e.metadata||"object"!=typeof e.metadata)throw new TypeError("`item.metadata` must be an object.");return{id:e.id,quantity:e.quantity,metadata:{...e.metadata}}}getItemList(){return[...this.#r].map((e,t)=>[e?this.#l(e):null,t]).filter(e=>null!==e[0])}getAllItems(){const e=[...this.#r].filter(e=>null!==e).map(this.#l);return this.#t.forEach(t=>{const i=t.item;i&&e.push(i)}),e}getItemsByMetadata(e){if("function"!=typeof e)throw new TypeError("`filterFn` must be a function.");return this.getAllItems().filter(t=>{const r=i.getItem(t.id);return e(r.metadata,t)})}findItem(e){if("function"!=typeof e)throw new TypeError("`predicate` must be a function.");return this.getAllItems().find(e)}findItems(e){if("function"!=typeof e)throw new TypeError("`predicate` must be a function.");return this.getAllItems().filter(e)}getItemCount(e){if("string"!=typeof e)throw new TypeError("`itemId` must be a string.");return this.getAllItems().filter(t=>t.id===e).reduce((e,t)=>e+t.quantity,0)}hasItem(e,t=1){if("string"!=typeof e)throw new TypeError("`itemId` must be a string.");if("number"!=typeof t||!Number.isFinite(t)||t<0)throw new TypeError("`quantity` must be a non-negative number.");return this.getItemCount(e)>=t}existsItemAt(e){if("number"!=typeof e||!Number.isInteger(e))throw new TypeError("`slotIndex` must be an integer.");return!!this.#r[e]}clear(){this.clearAllItems(),this.clearAllEvents()}clearAllEvents(){this.#i={add:[],remove:[],use:[],set:[]}}clearAllItems(){this.clearItems(),this.clearSpecialItems()}clearItems(){for(let e=this.#r.length-1;e>=0;e--)this.#r[e]&&this.deleteItem(e,!0)}clearSpecialItems(){for(const e of this.#t.keys()){const t=this.#t.get(e);t?.item&&this.deleteSpecialItem(e,!0)}}clone(){const e=this.toObject();return i.fromObject(e)}toObject(){const e={};for(const[t,i]of this.#t.entries())e[t]={type:i?.type??null,item:i?.item?this.#l(i.item):null};return{__schema:"TinyInventory",version:1,maxWeight:this.#a,maxSlots:this.#s,maxSize:this.#o,maxStack:this.#n,items:this.#r.map(e=>e?this.#l(e):null),specialSlots:e}}toJSON(e=0){if("number"!=typeof e||!Number.isFinite(e)||e<0)throw new TypeError("`space` must be a non-negative number.");return JSON.stringify(this.toObject(),null,e)}static fromObject(e){if(!e||"object"!=typeof e)throw new TypeError("Invalid state: expected object.");if("TinyInventory"!==e.__schema||"number"!=typeof e.version)throw new TypeError("Invalid or missing schema header.");if(1!==e.version)throw new TypeError(`Unsupported TinyInventory state version: ${e.version}`);const t={};if(e.specialSlots&&"object"==typeof e.specialSlots)for(const i of Object.keys(e.specialSlots))t[i]={type:e.specialSlots[i]?.type??null};const r=new i({maxWeight:e.maxWeight??null,maxSlots:e.maxSlots??null,maxSize:e.maxSize??null,maxStack:e.maxStack??null,specialSlots:t});if(Array.isArray(e.items))for(const t in e.items){const i=e.items[t];if(null!==i){const e={id:String(i.id),quantity:Math.max(1,Number(i.quantity)||1),metadata:i.metadata&&"object"==typeof i.metadata?i.metadata:{}};r.setItem({slotIndex:Number(t),item:e,forceSpace:!0})}else r.setItem({slotIndex:Number(t),item:null,forceSpace:!0})}if(e.specialSlots&&"object"==typeof e.specialSlots)for(const[t,i]of Object.entries(e.specialSlots)){if(!r.hasSpecialSlot(t))continue;const e=i?.item;if(e&&e.id){const i={id:String(e.id),quantity:Math.max(1,Number(e.quantity)||1),metadata:e.metadata&&"object"==typeof e.metadata?e.metadata:{}};r.setSpecialSlot({slotId:t,item:i,forceSpace:!0})}}return r}static fromJSON(e){if("string"!=typeof e)throw new TypeError("`json` must be a string.");const t=JSON.parse(e);return i.fromObject(t)}}const r=i,n=class{#c=null;#h=null;get sender(){return this.#c}get receiver(){return this.#h}set sender(e){if(!(e instanceof r&&this.receiver instanceof r))throw new Error("Both sender and receiver must be TinyInventory instances.");this.#c=e}set receiver(e){if(!(this.sender instanceof r&&e instanceof r))throw new Error("Both sender and receiver must be TinyInventory instances.");this.#h=e}constructor(e,t){if(e||t){if(!(e instanceof r&&t instanceof r))throw new Error("Both sender and receiver must be TinyInventory instances.");this.connect(e,t)}}connect(e,t){if(!(e instanceof r&&t instanceof r))throw new Error("Both sender and receiver must be TinyInventory instances.");this.#c=e,this.#h=t}disconnect(){this.#c=null,this.#h=null}invert(){const e=this.#c,t=this.#h;this.#c=t,this.#h=e}transferItem({slotIndex:e,specialSlot:t,quantity:i=1,receiverSlotIndex:n,forceSpace:o=!1,strict:s=!1}){if(!this.#c||!this.#h)throw new Error("Sender and receiver inventories must be connected.");let a;if(t){if(a=this.#c.getSpecialItem(t),!a)throw new Error(`No item found in sender special slot '${t}'.`)}else{if("number"!=typeof e)throw new Error("Must provide either slotIndex or specialSlot.");if(a=this.#c.getItemFrom(e),!a)throw new Error(`No item found in sender slot ${e}.`)}if(a.quantity<i)throw new Error(`Sender does not have enough quantity of '${a.id}' to transfer.`);const l={id:a.id,quantity:i,metadata:a.metadata};let m;if(s)if("number"==typeof n){const e=this.#h.existsItemAt(n)?this.#h.getItemFrom(n):null;if(e){if(e.id!==l.id)throw new Error(`Receiver slot ${n} contains a different item.`);const t=r.getItem(e.id).maxStack-e.quantity;if(l.quantity>t)throw new Error(`Strict mode: not enough space in receiver slot ${n}.`)}}else if(this.#h.clone().addItem({itemId:l.id,quantity:l.quantity,metadata:l.metadata,forceSpace:o}).remaining>0)throw new Error("Strict mode: not enough space in receiver inventory.");if("number"==typeof n){const e=this.#h.existsItemAt(n)?this.#h.getItemFrom(n):null;let t=l.quantity;if(e){if(e.id!==l.id)throw new Error(`Receiver slot ${n} contains a different item.`);const i=r.getItem(e.id).maxStack-e.quantity;t=Math.min(i,l.quantity),t>0&&this.#h.setItem({slotIndex:n,item:{...e,quantity:e.quantity+t},forceSpace:o})}else this.#h.setItem({slotIndex:n,item:l,forceSpace:o});m={remaining:l.quantity-t}}else m=this.#h.addItem({itemId:l.id,quantity:l.quantity,metadata:l.metadata,forceSpace:o});const u=l.quantity-m.remaining;if(u>0)if(t)this.#c.unequipItem({slotId:t,quantity:u,forceSpace:o});else if("number"==typeof e){const t=a.quantity-u;this.#c.setItem({slotIndex:e,item:t>0?{...a,quantity:t}:null,forceSpace:o})}return m}transferMultiple(e){return e.map(e=>this.transferItem(e))}};window.TinyInventoryTrader=t.TinyInventoryTrader})();