let Utilities; const Container = document.querySelector('.container.p-0.p-lg-5') const ItemCache = { 24122: { type: "hat", accessoryType: "hat", name: "Polytoria Cap", price: 0, creator: { name: "Polytoria", id: 1 }, thumbnail: "https://c0.ptacdn.com/thumbnails/assets/RR0VPd5hX30Fx5APwRBGObotf1xD1DRT.png", asset: "https://c0.ptacdn.com/assets/InBsL5bpJdp84ZPZGQMeHuyCBlo-uOv7.glb" }, 24118: { type: "shirt", name: "Green Polytoria Flannel", price: 0, creator: { name: "Polytoria", id: 1 }, thumbnail: "https://c0.ptacdn.com/thumbnails/assets/s7l57JugjbZfWTKAQ0cqTohOBraRbX5E.png", asset: "https://c0.ptacdn.com/assets/uWrrnFGwgNN5W171vqYTWY7E639rKiXK.png" }, 24123: { type: "pants", name: "Jeans", price: 0, creator: { name: "Polytoria", id: 1 }, thumbnail: "https://c0.ptacdn.com/thumbnails/assets/anebTuFMLg8NKhRL3ab7hbzCfmcsFqGO.png", asset: "https://c0.ptacdn.com/assets/HD6TFdXD8CaflRNmd84VCNyNsmTB0SH3.png" } } let Avatar = { useCharacter: true, items: [24122], shirt: 24118, pants: 24123, headColor: '#e0e0e0', torsoColor: '#e0e0e0', leftArmColor: '#e0e0e0', rightArmColor: '#e0e0e0', leftLegColor: '#e0e0e0', rightLegColor: '#e0e0e0' }; /* Discovery */ let Page = 1 let Search = "" let TabSelected = "hat" !(async () => { Utilities = await import(chrome.runtime.getURL('resources/utils.js')); Utilities = Utilities.default; chrome.storage.sync.get(['PolyPlus_Settings'], function(result){ Settings = result.PolyPlus_Settings || Utilities.DefaultSettings; if (Settings.AvatarSandboxOn || 1 === 1) { if (new URLSearchParams(window.location.search).has('sandbox')) { document.title = 'Poly+ Avatar Sandbox' PageLoad() } else { const SandboxButton = document.createElement('a'); SandboxButton.classList = 'btn btn-outline-success w-100 mt-3'; SandboxButton.href = '?sandbox=true'; SandboxButton.innerHTML = ' Avatar Sandbox'; document.getElementById('cont-move').parentElement.appendChild(SandboxButton); } } }) })(); async function PageLoad() { const PageContents = (await ((await fetch(chrome.runtime.getURL('resources/avatar-sandbox.html'))).text())) Container.innerHTML = PageContents Utilities.InjectResource("registerTooltips") IFrame = document.getElementById('viewFrame') UpdateAvatar() LoadItems() const Tabs = document.getElementById('tabs') Array.from(Tabs.children).forEach((element) => { element.addEventListener('click', function () { let Link = element.getElementsByTagName('a')[0]; if (!Link.classList.contains('active')) { Link.classList.add('active'); Tabs.querySelector(`[data-tab="${TabSelected}"]`).classList.remove('active'); TabSelected = Link.getAttribute('data-tab'); Page = 1; LoadItems(); } }); }); const ClearButton = document.getElementById('clear'); ClearButton.addEventListener('click', function () { Avatar = { useCharacter: true, items: [24122], shirt: 24118, pants: 24123, headColor: '#e0e0e0', torsoColor: '#e0e0e0', leftArmColor: '#e0e0e0', rightArmColor: '#e0e0e0', leftLegColor: '#e0e0e0', rightLegColor: '#e0e0e0' }; UpdateAvatar(); }); const LoadMyselfButton = document.getElementById('myself'); LoadMyselfButton.addEventListener('click', function () { LoadUser(JSON.parse(window.localStorage.getItem('p+account_info')).ID); }); const JSONUploadButton = document.getElementById('jsonUpload'); JSONUploadButton.addEventListener('change', function () { const Reader = new FileReader(); Reader.addEventListener('loadend', function () { Avatar = JSON.parse(Reader.result); UpdateAvatar(); JSONUploadButton.value = ''; }); Reader.readAsText(JSONUploadButton.files[0]); }); const JSONSaveButton = document.getElementById('jsonSave'); JSONSaveButton.addEventListener('click', function () { const Download = document.createElement('a'); Download.href = URL.createObjectURL( new Blob([JSON.stringify(Avatar)], { type: 'application/json' }) ); Download.setAttribute('download', 'AvatarSandbox.json'); document.body.appendChild(Download); Download.click(); document.body.removeChild(Download); }); const OpenInNewTabButton = document.getElementById('openNewTab'); OpenInNewTabButton.addEventListener('click', function () { window.open(IFrame, "_blank") }); const LoadAsset = document.getElementById('load-asset') const LoadAssetType = document.getElementById('load-asset-type') LoadAsset.addEventListener('click', function(){ const SelectedType = LoadAssetType.options[LoadAssetType.selectedIndex].value if (SelectedType !== 'user') { if (SelectedType === 'hat') { Avatar.items.push(LoadAsset.previousElementSibling.value); } else { Avatar[SelectedType] = parseInt(LoadAsset.previousElementSibling.value) } UpdateAvatar(); } else { LoadUser(LoadAsset.previousElementSibling.value) } }) } async function UpdateAvatar() { // Hats, Tools: https://api.polytoria.com/v1/assets/serve-mesh/ID // or: https://api.polytoria.com/v1/assets/serve/ID/Asset const FormattedAvatar = structuredClone(Avatar) const AccessoryPromise = [...Avatar.items, Avatar.tool].filter((x) => x !== undefined && !x.toString().startsWith('http') && !x.toString().startsWith('data:')).map(async (x, index) => { if (ItemCache[x] === undefined) { const ItemDetails = (await (await fetch('https://api.polytoria.com/v1/store/' + x)).json()) ItemCache[x] = { type: ItemDetails.type, name: ItemDetails.name, price: ItemDetails.price, creator: { name: ItemDetails.creator.name, id: ItemDetails.creator.id }, thumbnail: ItemDetails.thumbnail, asset: undefined } if (ItemDetails.type === 'hat') { ItemCache[x].accessoryType = ItemDetails.accessoryType } } if (ItemCache[x].asset === undefined) { const MeshURL = (await (await fetch('https://api.polytoria.com/v1/assets/serve-mesh/' + x)).json()) if (MeshURL.success) { ItemCache[x].asset = MeshURL.url if (ItemCache[x].type === 'hat') { FormattedAvatar.items[index] = MeshURL.url } else { FormattedAvatar[ItemCache[x].type] = MeshURL.url } } } else { if (ItemCache[x].type === 'hat') { FormattedAvatar.items[index] = ItemCache[x].asset } else { FormattedAvatar[ItemCache[x].type] = ItemCache[x].asset } } }) const TexturePromise = [Avatar.shirt, Avatar.pants, Avatar.face].filter((x) => x !== undefined && !x.toString().startsWith('http') && !x.toString().startsWith('data:') && x !== undefined).map(async (x, index) => { if (ItemCache[x] === undefined) { const ItemDetails = (await (await fetch('https://api.polytoria.com/v1/store/' + x)).json()) ItemCache[x] = { /* type: ItemDetails.type, name: ItemDetails.name, price: ItemDetails.price, creator: { name: ItemDetails.creator.name, id: ItemDetails.creator.id }, thumbnail: ItemDetails.thumbnail, */ asset: undefined } if (ItemDetails.price === 0) { if (ItemDetails.sales === 0) { ItemCache[x].price = null } else { ItemCache[x].price = 0 } } } if (ItemCache[x].asset === undefined) { const TextureURL = (await (await fetch('https://api.polytoria.com/v1/assets/serve/' + x + '/Asset')).json()) if (TextureURL.success) { ItemCache[x].asset = TextureURL.url if (x === Avatar.shirt) { FormattedAvatar.shirt = TextureURL.url } else if (x === Avatar.pants) { FormattedAvatar.pants = TextureURL.url } else if (x === Avatar.face) { FormattedAvatar.face = TextureURL.url } } } else { if (x === Avatar.shirt) { FormattedAvatar.shirt = ItemCache[x].asset } else if (x === Avatar.pants) { FormattedAvatar.pants = ItemCache[x].asset } else if (x === Avatar.face) { FormattedAvatar.face = ItemCache[x].asset } } }) if (Avatar.face === undefined) { FormattedAvatar.face = "https://c0.ptacdn.com/static/3dview/DefaultFace.png" } await Promise.all(AccessoryPromise) await Promise.all(TexturePromise) console.log('Real Avatar: ', Avatar) console.log('Formatted: ', FormattedAvatar) IFrame.addEventListener('load', function(){ IFrame.src = 'https://polytoria.com/ptstatic/itemview/#' + btoa(encodeURIComponent(JSON.stringify(FormattedAvatar))) }) IFrame.src = 'about:blank' UpdateBodyColors() LoadWearing() } function LoadUser(id) { fetch('https://api.polytoria.com/v1/users/' + id + '/avatar') .then((response) => { if (!response.ok) { throw new Error('Network not ok'); } return response.json(); }) .then((data) => { Avatar.items = []; data.assets.forEach((item) => { ItemCache[item.id] = { type: item.type, name: item.name, price: null, creator: null, thumbnail: item.thumbnail, asset: item.path } if (item.type === 'hat' || item.type === 'tool') { ItemCache[item.id].creator = { id: 1, name: "Polytoria" } } if (item.type === 'hat') { ItemCache[item.id].accessoryType = item.accessoryType Avatar.items.push(item.id) } else { Avatar[item.type] = item.id } }); Avatar.headColor = '#' + data.colors.head || '#cdcdcd'; Avatar.torsoColor = '#' + data.colors.torso || '#cdcdcd'; Avatar.leftArmColor = '#' + data.colors.leftArm || '#cdcdcd'; Avatar.rightArmColor = '#' + data.colors.rightArm || '#cdcdcd'; Avatar.leftLegColor = '#' + data.colors.leftLeg || '#cdcdcd'; Avatar.rightLegColor = '#' + data.colors.rightLeg || '#cdcdcd'; UpdateAvatar(); }) .catch((error) => { console.log(error); }); } async function LoadItems() { document.getElementById('inventory').innerHTML = '' const Items = (await (await fetch('https://api.polytoria.com/v1/store?limit=12&order=desc&sort=createdAt&showOffsale=true&types[]='+ TabSelected +'&search=' + Search + '&page=' + Page)).json()).assets Items.forEach(item => { const ItemColumn = document.createElement('div') ItemColumn.classList = 'col-auto' ItemColumn.innerHTML = `
${ (item.type === 'hat') ? ` ${CleanAccessoryType(item.accessoryType)} ` : ''}
${item.name}
by ${ (item.type !== 'hat' && item.type !== 'tool') ? 'Polytoria' : item.creator.name }
` document.getElementById('inventory').appendChild(ItemColumn) ItemCache[item.id] = { type: item.type, name: item.name, price: item.price, creator: { name: item.creator.name, id: item.creator.id }, thumbnail: item.thumbnail, asset: undefined } if (item.price === 0) { if (item.sales === 0) { console.log("ITEM IS AWARD-ONLY!!! ", item) ItemCache[item.id].price = null } else { ItemCache[item.id].price = 0 } } if (item.type === 'hat') { ItemCache[item.id].accessoryType = item.accessoryType } ItemColumn.getElementsByClassName('p-2')[0].addEventListener('click', function(){ WearAsset(item) }) }) } function LoadWearing() { document.getElementById('wearing').innerHTML = ''; [...Avatar.items, Avatar.shirt, Avatar.pants].filter((x) => x !== undefined).forEach(id => { const Cached = Object.values(ItemCache)[Object.keys(ItemCache).indexOf(id.toString())] if (Cached !== undefined) { if (Cached.creator === null) { Cached.creator = { id: 1, name: "-" } } if (Cached.price === null) { Cached.price = "???" } const ItemColumn = document.createElement('div') ItemColumn.classList = 'col-auto' ItemColumn.innerHTML = `
${ (Cached.type === 'hat') ? ` ${CleanAccessoryType(Cached.accessoryType)} ` : ''}
${Cached.name}
by ${Cached.creator.name || "-"} Free' : (Cached.price !== "???") ? 'text-success">$ ' + Cached.price : 'text-muted">???' }
` document.getElementById('wearing').appendChild(ItemColumn) ItemColumn.getElementsByClassName('p-2')[0].addEventListener('click', function(){ WearAsset(Cached) }) } }) } function WearAsset(details) { if (Avatar[details.type] !== details.id && Avatar.items.indexOf(details.id) === -1) { // Equip if (details.type === 'hat') { Avatar.items.push(details.id) } else { Avatar[details.type] = details.id } } else { // Unequip if (details.type === 'hat') { Avatar.items.splice(Avatar.items.indexOf(details.id), 1); } else { Avatar[details.type] = undefined } } UpdateAvatar() LoadWearing() } function UpdateBodyColors() { const BodyColors = { head: Avatar.headColor, torso: Avatar.torsoColor, leftArm: Avatar.leftArmColor, rightArm: Avatar.rightArmColor, leftLeg: Avatar.leftLegColor, rightLeg: Avatar.rightLegColor } Object.keys(BodyColors).forEach((elementID, i) => { document.getElementById(elementID).style.backgroundColor = Object.values(BodyColors)[i] }) } function CleanAccessoryType(type) { const CleanAccessoryTypes = { hat: "Hat", backAccessory: "Back Accessory", faceAccessory: "Face Accessory", headAttachment: "Head Attachment", hair: "Hair", neckAccessory: "Neck Accessory", headCover: "Head Cover", headAccessory: "Head Accessory" } return Object.values(CleanAccessoryTypes)[Object.keys(CleanAccessoryTypes).indexOf(type)] || "!!!"+type }