const UserID = JSON.parse(window.localStorage.getItem('account_info')).ID const BodyColors = [ "#f8f8f8", "#cdcdcd", "#111111", "#ff0000", "#a34b4b", "#ffc9c9", "#957977", "#c4281c", "#da867a", "#694028", "#cc8e69", "#a05f35", "#7c5c46", "#eab892", "#da8541", "#aa5500", "#ffcc99", "#e29b40", "#ffaf00", "#ffb000", "#d7c59a", "#f5cd30", "#fdea8d", "#e5e4df", "#c1be42", "#ffff00", "#ffffcc", "#a4bd47", "#7f8e64", "#a1c48c", "#3a7d15", "#4b974b", "#00ff00", "#ccffcc", "#27462d", "#287f47", "#789082", "#9ff3e9", "#12eed4", "#f2f3f3", "#00ffff", "#008f9c", "#04afec", "#80bbdb", "#b4d2e4", "#0d69ac", "#1b2a35", "#afddff", "#6e99ca", "#74869d", "#2154b9", "#002060", "#0000ff", "#b1a7ff", "#a3a2a5", "#6225d1", "#b480ff", "#8c5b9f", "#6b327c", "#aa00aa", "#635f62", "#ff00bf", "#ff66cc", "#e8bac8" ] let PageContainer = document.querySelector('.container.p-0.p-lg-5') let ItemGrid; let Wearing; let Tabs; let IFrame; let TabSelected = 'hat' let Search; let Page = 1 let Avatar = { "useCharacter": true, "items": [ 24122 ], "shirt": 24118, "pants": 24123, "headColor": "#e0e0e0", "torsoColor": "#e0e0e0", "leftArmColor": "#e0e0e0", "rightArmColor": "#e0e0e0", "leftLegColor": "#e0e0e0", "rightLegColor": "#e0e0e0" } if (new URLSearchParams(window.location.search).has('sandbox')) { console.log('Avatar Sandbox!') LoadFile(chrome.runtime.getURL('resources/avatar-sandbox.html'), function(html){ PageContainer.innerHTML = html ItemGrid = document.getElementById('inventory') Wearing = document.getElementById('wearing') Tabs = document.getElementById('tabs') IFrame = document.getElementById('viewFrame') Search = document.getElementById('item-search') Search.addEventListener('onchange', function(){ RefreshItems() }); UpdateAvatar() RefreshItems() LoadWearing() 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 RefreshItems() } }); }); let Clear = document.getElementById('clear') Clear.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() }); let Myself = document.getElementById('myself') Myself.addEventListener('click', function(){ LoadMyself() }); let JSONUpload = document.getElementById('jsonUpload') JSONUpload.addEventListener('change', function(){ let Reader = new FileReader() Reader.addEventListener('loadend', function(){ Avatar = JSON.parse(Reader.result) UpdateAvatar() JSONUpload.value = "" }); Reader.readAsText(JSONUpload.files[0]) }); let JSONSave = document.getElementById('jsonSave') JSONSave.addEventListener('click', function(){ let 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) }); let OpenInNewTab = document.getElementById('openNewTab') OpenInNewTab.addEventListener('click', function(){ UpdateAvatar() }); }); } 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) } function UpdateAvatar() { GenerateHash() .then(hash => { IFrame.addEventListener('load', function () { IFrame.src = 'https://polytoria.com/ptstatic/itemview/#' + hash; }); IFrame.src = 'about:blank'; }); } function LoadFile(path, callback) { var xhr = new XMLHttpRequest(); xhr.onload = function () { return callback(this.responseText); } xhr.open("GET", path, true); xhr.send(); } async function GenerateHash(data) { if (!data) { console.log('Data not provided') let FormattedAvatar = await FormatAvatar() return btoa(encodeURIComponent(JSON.stringify(FormattedAvatar))) } else { console.log('Data provided') return btoa(encodeURIComponent(JSON.stringify(data))) } } function RefreshItems() { fetch(`https://api.polytoria.com/v1/store?search=${Search.value}&types%5B%5D=${TabSelected}&sort=createdAt&order=desc&page=${Page}&limit=12`) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { Array.from(ItemGrid.children).forEach(element => {element.remove()}); data = data.assets data.forEach(item => { let NewItemCard = document.createElement('div') NewItemCard.setAttribute('data-id', item.id) NewItemCard.classList = 'col-auto' NewItemCard.innerHTML = `
${item.type.charAt(0).toUpperCase() + item.type.substring(1)}
${item.name}
by ${item.creator.name}
` NewItemCard.getElementsByClassName('p-2')[0].addEventListener('click', function(){ WearAsset(NewItemCard, item) }); ItemGrid.appendChild(NewItemCard) }); }) .catch(error => { console.error('Fetch error:', error); }); } async function FormatAvatar() { const FormattedAvatar = structuredClone(Avatar) // Hats, Tools: https://api.polytoria.com/v1/assets/serve-mesh/:id // or: https://api.polytoria.com/v1/assets/serve/:id/Asset Avatar.items.forEach(async (item, index) => { if (typeof(item) === 'number') { console.log(item) await FetchMesh(item) .then(URL => { console.log('URL: ' + URL) FormattedAvatar.items[index] = URL }) .catch(error => { throw new Error(error) }); console.log('after url') //Avatar.items[index] = URL } }); if (typeof(FormattedAvatar.tool) === 'number') {console.log(FormattedAvatar.tool); FormattedAvatar.tool = await FetchMesh(FormattedAvatar.tool)} if (FormattedAvatar.face && typeof(FormattedAvatar.face) === 'number') { FormattedAvatar.face = await FetchAsset(FormattedAvatar.face) } else { FormattedAvatar.face = "https://c0.ptacdn.com/static/3dview/DefaultFace.png" } if (typeof(FormattedAvatar.shirt) === 'number') {FormattedAvatar.shirt = await FetchAsset(FormattedAvatar.shirt)} if (typeof(FormattedAvatar.pants) === 'number') {FormattedAvatar.pants = await FetchAsset(FormattedAvatar.pants)} console.log('Real Avatar: ', Avatar, 'Formatted: ', FormattedAvatar) return FormattedAvatar } function LoadMyself() { fetch('https://api.polytoria.com/v1/users/:id/avatar'.replace(':id', UserID)) .then(response => { if (!response.ok) { throw new Error('Network not ok') } return response.json() }) .then(data => { Avatar.items = [] data.assets.forEach(item => { switch(item.type) { case 'hat': Avatar.items.push(item.id) break default: Avatar[item.type] = item.id break } }); 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) }); } function WearAsset(element, info) { if (Avatar.items.indexOf(info.id) === -1 && Avatar[info.type] !== info.id) { console.log('Equip', info) switch(info.type) { case 'hat': Avatar.items.push(info.id) break default: Avatar[info.type] = info.id break } } else { console.log('unequip', info) switch(info.type) { case 'hat': Avatar.items.splice(Avatar.items.indexOf(info.id), 1) break case 'face': Avatar.face = "https://c0.ptacdn.com/static/3dview/DefaultFace.png" break default: Avatar[info.type] = undefined break } } const ToggleButton = element.getElementsByClassName('avatarAction')[0] ToggleButton.classList.toggle('btn-success') ToggleButton.classList.toggle('btn-danger') ToggleButton.children[0].classList.toggle('fa-plus') ToggleButton.children[0].classList.toggle('fa-minus') const Duplicate = ItemGrid.querySelector(`[data-id="${info.id}"]`) if (Duplicate !== null && Duplicate !== element) { const DuplicateToggleButton = Duplicate.getElementsByClassName('avatarAction')[0] DuplicateToggleButton.classList.toggle('btn-success') DuplicateToggleButton.classList.toggle('btn-danger') DuplicateToggleButton.children[0].classList.toggle('fa-plus') DuplicateToggleButton.children[0].classList.toggle('fa-minus') } LoadWearing() UpdateAvatar() } async function FetchMesh(id) { if (id === null) {return null} console.log('https://api.polytoria.com/v1/assets/serve-mesh/:id'.replace(':id', id)) return fetch('https://api.polytoria.com/v1/assets/serve-mesh/:id'.replace(':id', id)) .then(response => { if (!response.ok) { throw new Error('Network not ok') } return response.json() }) .then(data => { console.log(data, 'finished', data.url) return data.url }) .catch(error => { console.log('Fetch error: ' + error) }); } async function FetchAsset(id) { if (id === null) {return null} return fetch('https://api.polytoria.com/v1/assets/serve/:id/Asset'.replace(':id', id)) .then(response => { if (!response.ok) { throw new Error('Network not ok') } return response.json() }) .then(data => { return data.url }) .catch(error => { console.log('Fetch error: ' + error) }); } function LoadWearing() { const WearingItems = [ ...Avatar.items, Avatar.shirt, Avatar.pants, Avatar.face ].filter(item => item !== null && item !== undefined); Array.from(Wearing.children).forEach(element => { const ItemID = element.getElementsByTagName('a')[0].href.split('/')[2] if (!WearingItems.includes(ItemID)) { element.remove(); } }); WearingItems.forEach(item => { const ExistingElement = Wearing.querySelector(`[data-itemid="${item}"]`); if (!ExistingElement) { fetch(`https://api.polytoria.com/v1/store/${item}`) .then(response => { if (!response.ok) { throw new Error('Network not ok'); } return response.json(); }) .then(item => { if (Wearing.innerHTML === 'No items to show.') { Wearing.innerHTML = '' } let NewItemCard = document.createElement('div'); NewItemCard.setAttribute('data-id', item.id) NewItemCard.classList = 'col-auto'; NewItemCard.innerHTML = `
${item.type.charAt(0).toUpperCase() + item.type.substring(1)}
${item.name}
by ${item.creator.name}
` Wearing.appendChild(NewItemCard); NewItemCard.getElementsByClassName('p-2')[0].addEventListener('click', function () { WearAsset(NewItemCard, item); }); }) .catch(error => { console.log('Fetch error: ' + error); }); } }); if (Array.from(Wearing.children).length === 0) { Wearing.innerHTML = 'No items to show.' } }