495 lines
14 KiB
JavaScript
Executable file
495 lines
14 KiB
JavaScript
Executable file
const UserID = JSON.parse(window.localStorage.getItem('p+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();
|
|
});
|
|
|
|
let LoadAsset = document.getElementById('load-asset');
|
|
LoadAsset.addEventListener('click', async function () {
|
|
console.log('clickk');
|
|
const MeshURL = (await (await fetch('https://api.polytoria.com/v1/assets/serve-mesh/' + LoadAsset.previousElementSibling.value)).json()).url;
|
|
Avatar.items.push(MeshURL);
|
|
UpdateAvatar();
|
|
});
|
|
});
|
|
} else {
|
|
const SandboxButton = document.createElement('a');
|
|
SandboxButton.classList = 'btn btn-outline-success w-100 mt-3';
|
|
SandboxButton.href = '?sandbox=true';
|
|
SandboxButton.innerHTML = '<i class="fas fa-shirt"></i> 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 = `
|
|
<div style="max-width: 150px;">
|
|
<div class="card mb-2 avatar-item-container">
|
|
<div class="p-2">
|
|
<img src="${item.thumbnail}" class="img-fluid">
|
|
<span class="position-absolute" style="top: 5px; left: 5px; z-index: 1;">
|
|
<span class="badge bg-secondary">${item.type.charAt(0).toUpperCase() + item.type.substring(1)}</span>
|
|
</span>
|
|
<button class="avatarAction btn btn-success btn-sm position-absolute rounded-circle text-center" style="top: -10px; right: -16px; width: 32px; height: 32px; z-index: 1;"><i class="fas fa-plus"></i></button>
|
|
</div>
|
|
</div>
|
|
<a href="/store/${item.id}" class="text-reset">
|
|
<h6 class="text-truncate mb-0">${item.name}</h6>
|
|
</a>
|
|
<small class="text-muted d-block text-truncate">
|
|
by <a href="/users/${item.creator.id}" class="text-reset">${item.creator.name}</a>
|
|
</small>
|
|
</div>
|
|
`;
|
|
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 = `
|
|
<div style="max-width: 150px;">
|
|
<div class="card mb-2 avatar-item-container">
|
|
<div class="p-2">
|
|
<img src="${item.thumbnail}" class="img-fluid">
|
|
<span class="position-absolute" style="top: 5px; left: 5px; z-index: 1;">
|
|
<span class="badge bg-secondary">${item.type.charAt(0).toUpperCase() + item.type.substring(1)}</span>
|
|
</span>
|
|
<button class="avatarAction btn btn-danger btn-sm position-absolute rounded-circle text-center" style="top: -10px; right: -16px; width: 32px; height: 32px; z-index: 1;"><i class="fas fa-minus"></i></button>
|
|
</div>
|
|
</div>
|
|
<a href="/store/${item.id}" class="text-reset">
|
|
<h6 class="text-truncate mb-0">${item.name}</h6>
|
|
</a>
|
|
<small class="text-muted d-block text-truncate">
|
|
by <a href="/users/${item.creator.id}" class="text-reset">${item.creator.name}</a>
|
|
</small>
|
|
</div>
|
|
`;
|
|
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.';
|
|
}
|
|
}
|