// ==UserScript==
// @name MC-Skin
// @namespace https://viayoo.com/
// @version 3.6
// @description 在网页里添加一个MC小人
// @author undefined303
// @license MIT
// @homepageURL https://gf.qytechs.cn/zh-CN/scripts/537235
// @run-at document-end
// @match *
// @include *
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_xmlhttpRequest
// @require data:text/javascript,const%20origdef%20%3D%20window.define%3B
// @require data:text/javascript,window.define%20%3D%20undefined%3B
// @require https://fastly.jsdelivr.net/npm/[email protected]/bundles/skinview3d.bundle.min.js
// @require https://fastly.jsdelivr.net/npm/[email protected]/build/three.min.js
// @require data:text/javascript,window.define%20%3D%20origdef%3B
// ==/UserScript==
(function() {
const key = encodeURIComponent('MC skin:执行判断');
if (window[key]) {
return;
}
window[key] = true;
'use strict'
var skin = GM_getValue("skin", null);
function rafThrottle(func) {
let lock = false;
return function(...args) {
if (lock) return;
lock = true;
window.requestAnimationFrame(() => {
func.apply(this, args);
lock = false;
});
};
}
function getIframeIndex(id, max) {
var messageListener;
return new Promise((resolve, reject) => {
var timeout = setTimeout(() => {
reject();
}, 500);
messageListener = (e) => {
if (e.data.type == "McSkinIframeIndex") {
//4.读取index
if (id == e.data.id) {
var index = e.data.data;
if (index <= max) {
resolve(index);
clearTimeout(timeout);
} else {
reject();
clearTimeout(timeout);
}
}
}
}
window.addEventListener("message", messageListener, {
passive: true
})
}).then((data) => {
window.removeEventListener("message", messageListener)
return data;
}).catch(() => {
window.removeEventListener("message", messageListener)
console.error("iframe获取index信息超时");
return "error";
})
}
window.addEventListener("message", async function(e) {
if (e.data.type == "McSkinIframeGetPosition") {
//2.收到获取位置信息请求,发送询问谁需要位置信息
var iframes = [...document.getElementsByTagName("iframe")]
var i = -1;
iframes.forEach((ele) => {
i++;
ele.contentWindow.postMessage({
type: "McSkinIframeGetPositionIndex",
id: e.data.id,
index: i
}, "*")
})
var iframeIndex = await getIframeIndex(e.data.id, iframes.length - 1);
if (iframeIndex == "error") {
iframes.forEach((ele) => {
ele.contentWindow.postMessage({
type: "McSkinIframeGetPositionError",
id: e.data.id
}, "*")
})
return;
}
//使用上一帧布局信息,避免强制同步布局
requestAnimationFrame(() => {
var bcr = iframes[iframeIndex].getBoundingClientRect();
//5.发送位置信息
iframes[iframeIndex].contentWindow.postMessage({
type: "McSkinIframePositionData",
data: {
x: bcr.left,
y: bcr.top
},
id: e.data.id
}, "*")
})
}
}, {
passive: true
})
if (self != top) {
var isGettingPosition = false;
function messageReceiver(e) {
if (e.data.type == 'McSkinIframeGetPositionIndex') {
//3.收到询问信息,如果需要,回答index
if (isGettingPosition) {
window.parent.postMessage({
type: "McSkinIframeIndex",
data: e.data.index,
id: e.data.id
}, '*');
}
isGettingPosition = false;
}
}
window.addEventListener('message', messageReceiver, {
passive: true
})
var positionData;
var getIframePosition = function() {
var id = Date.now() + Math.random();
//1.发送请求获取位置信息
window.parent.postMessage({
type: "McSkinIframeGetPosition",
id: id
}, '*');
return new Promise((resolve, reject) => {
var timeout = setTimeout(() => {
window.removeEventListener("message", positionMessageReceiver);
reject();
}, 500);
isGettingPosition = true;
function positionMessageReceiver(e) {
if (e.data.type == "McSkinIframePositionData" && e.data.id == id) {
//6.接受位置信息
positionData = e.data.data;
window.removeEventListener("message", positionMessageReceiver);
if (positionData == "error") {
reject();
clearTimeout(timeout);
return;
}
resolve();
clearTimeout(timeout);
}
if (e.data.type == "McSkinIframePositionError" && e.data.id == id) {
window.removeEventListener("message", positionMessageReceiver);
reject();
clearTimeout(timeout);
return;
}
}
window.addEventListener('message', positionMessageReceiver, {
passive: true
})
}).then(() => {
return positionData;
}).catch(() => {
console.error("iframe获取位置信息超时");
return "error";
})
}
var lock = false;
function getIframePosition0() {
return new Promise((resolve, reject) => {
if (!lock) {
lock = true;
var timeout = setTimeout(() => {
reject();
}, 500)
requestAnimationFrame(async () => {
var positionData = await getIframePosition();
if (positionData) {
resolve(positionData);
clearTimeout(timeout);
}
lock = false;
})
} else {
reject();
}
}).then((data) => {
return data;
}).catch(() => {
return "error"
})
}
async function pushEventMessage(e) {
let data = {};
if (e.type == "touchstart" || e.type == "touchmove" || e.type == "mousemove") {
let lock = false;
var positionData = await getIframePosition0();
if (positionData == "error") {
return;
}
}
positionData = positionData || {};
var x = positionData.x;
var y = positionData.y;
data.type = e.type;
e.clientX ? data.clientX = e.clientX + x : null;
e.clientY ? data.clientY = e.clientY + y : null;
if (e.targetTouches) {
data.targetTouches = [{
clientX: e.targetTouches[0].clientX + x,
clientY: e.targetTouches[0].clientY + y
}]
}
e.wheelDelta ? data.wheelDelta = e.wheelDelta : null;
e.detail ? data.detail = e.detail : null;
window.parent.postMessage({
type: "McSkinIframeEventData",
data: data
}, "*");
}
window.addEventListener("mousemove", pushEventMessage, {
passive: true
});
window.addEventListener("touchstart", pushEventMessage, {
passive: true
});
window.addEventListener("touchmove", pushEventMessage);
window.addEventListener("wheel", pushEventMessage, {
passive: true
})
window.addEventListener("mousedown", pushEventMessage, {
passive: true
})
document.addEventListener('keydown', pushEventMessage, {
passive: true
});
window.addEventListener("message", async (e) => {
if (e.data.type == "McSkinIframeEventData") {
let data = {};
var positionData = await getIframePosition();
var x = positionData.x;
var y = positionData.y;
data.type = e.data.data.type;
e.data.data.clientX ? data.clientX = e.data.data.clientX + x : null;
e.data.data.clientY ? data.clientY = e.data.data.clientY + y : null;
if (e.data.data.targetTouches) {
data.targetTouches = [{
clientX: e.data.data.targetTouches[0].clientX + x,
clientY: e.data.data.targetTouches[0].clientY + y
}]
}
e.data.data.wheelDelta ? data.wheelDelta = e.data.data.wheelDelta : null;
e.data.data.detail ? data.detail = e.data.data.detail : null;
window.parent.postMessage({
type: "McSkinIframeEventData",
data: data
}, "*");
}
}, {
passive: true
})
return;
}
console.log("%cMcSkin.js", "color:orange");
var defaultRotation = GM_getValue("defaultRotation", -0.25);
const box = document.createElement("div");
document.documentElement.append(box);
const shadow = box.attachShadow({
mode: "closed"
});
const inner = document.createElement("main");
shadow.append(inner);
var dialog = inner.appendChild(document.createElement("dialog"));
dialog.setAttribute("style", `border:none !important;
border-radius:10px !important;
width:min(70vw,350px) !important;
max-width:100vw !important;
text-align:center !important;
padding:40px 0px !important;
box-shadow:0px 0px 7px 1px rgba(0,0,0,.3) !important;
backdrop-filter: blur(50px);
background-color: rgba(255, 255, 255, 0.8);
outline:none !important;
font-size:0px;
`)
var span = document.body.appendChild(document.createElement("span"));
span.setAttribute("style", "font-size:1.2em");
var fontSize = window.getComputedStyle(span).fontSize;
document.body.removeChild(span);
dialog.addEventListener("click", e => {
const dialogDimensions = dialog.getBoundingClientRect()
if (
e.clientX < dialogDimensions.left ||
e.clientX > dialogDimensions.right ||
e.clientY < dialogDimensions.top ||
e.clientY > dialogDimensions.bottom
) {
dialog.close()
}
}, {
passive: true
})
var removeAllChild = function(node) {
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
}
skin = GM_getValue("skin", skin);
var uploadSkin = function(isSave) {
dialog.close();
return new Promise((resolve, reject) => {
let input = document.createElement('input');
input.type = 'file';
input.accept = 'image/png';
input.style.display = 'none';
input.multiple = false;
input.addEventListener('change', (event) => {
let file = event.target.files[0];
if (!file) {
reject(new Error('No file selected'));
return;
}
if (file.type !== 'image/png') {
reject(new Error('Only PNG files are allowed'));
return;
}
let reader = new FileReader();
reader.onload = (e) => {
try {
const base64 = e.target.result;
skinViewer.loadSkin(base64);
skin = base64;
if (isSave) {
GM_setValue("skin", base64);
}
resolve(base64);
} catch (error) {
reject(error);
}
};
reader.onerror = (error) => reject(error);
reader.readAsDataURL(file);
});
document.body.appendChild(input);
input.click();
setTimeout(() => {
document.body.removeChild(input);
}, 200)
});
}
var createSkinPickerDialog = function(isSave, info) {
removeAllChild(dialog);
let span = dialog.appendChild(document.createElement("span"));
span.style.fontSize = fontSize;
span.innerText = info;
span.style.display = "block";
let wrap = dialog.appendChild(document.createElement("div"));
wrap.style.display = "block";
let nameInp = wrap.appendChild(document.createElement("input"));
nameInp.placeholder = "使用正版ID获取皮肤";
nameInp.setAttribute("style", `
outline:none;
border:none;
border-bottom:2px solid black;
background:transparent;
margin-right:10px;
`)
let upload;
nameInp.addEventListener("input", function() {
if (nameInp.value != "") {
uploadBtn.innerText = "获取皮肤";
upload = function() {
let span1 = dialog.appendChild(document.createElement("span"));
span1.style.fontSize = fontSize;
span1.innerText = `获取中 ...`;
span1.style.display = "block";
const username = nameInp.value.trim();
GM_xmlhttpRequest({
method: 'GET',
url: `https://api.mojang.com/users/profiles/minecraft/${username}`,
onload: function(uuidResponse) {
try {
const uuidData = JSON.parse(uuidResponse.responseText);
const uuid = uuidData.id;
GM_xmlhttpRequest({
method: 'GET',
url: `https://sessionserver.mojang.com/session/minecraft/profile/${uuid}`,
onload: function(profileResponse) {
try {
const profileData = JSON.parse(profileResponse.responseText);
const texturesProp = profileData.properties.find(p => p.name === 'textures');
if (!texturesProp) {
alert('未获取到皮肤');
dialog.close();
}
const texturesJson = atob(texturesProp.value);
const texturesData = JSON.parse(texturesJson);
const skinUrl = texturesData.textures.SKIN.url;
GM_xmlhttpRequest({
method: "GET",
url: skinUrl,
responseType: "blob",
onload: function(response) {
const reader = new FileReader();
reader.onloadend = function() {
skinViewer.loadSkin(reader.result);
skin = reader.result;
if (isSave) {
GM_setValue("skin", reader.result);
}
dialog.close();
}
reader.readAsDataURL(response.response);
},
onerror: function(e) {
alert("皮肤加载错误")
dialog.close();
}
});
} catch (e) {
alert(`${ e.message.includes('default') ? e.message : 'API请求失败,无法获取皮肤信息,请检查ID是否正确,或者检查网络连接'}`);
dialog.close();
}
},
onerror: function(e) {
alert(`API请求失败,无法获取皮肤信息,请检查ID是否正确,或者检查网络连接`);
dialog.close();
}
});
} catch (e) {
alert(`${e.responseText ? JSON.parse(e.responseText).errorMessage : 'API请求失败,无法获取皮肤信息,请检查ID是否正确,或者检查网络连接'}`);
dialog.close();
}
},
onerror: function(e) {
alert(`${e.responseText ? JSON.parse(e.responseText).errorMessage : 'API请求失败无法获取皮肤信息,请检查ID是否正确,或者检查网络连接'}`);
dialog.close();
}
});
}
uploadBtn.onclick = upload;
} else {
uploadBtn.innerText = "上传皮肤";
uploadBtn.onclick = function() {
uploadSkin(isSave);
};
}
})
let uploadBtn = wrap.appendChild(document.createElement("button"));
uploadBtn.onclick = () => {
uploadSkin(isSave)
};
uploadBtn.setAttribute("style", `
color:white;
background:#6F8DE1;
border:none;
outline:none;
padding:5px 10px;
border-radius:10px;
margin-top:20px;
`)
uploadBtn.style.fontSize = fontSize;
uploadBtn.innerText = "上传皮肤";
nameInp.addEventListener("keydown", function(e) {
if (e.keyCode == 13) {
e.preventDefault();
upload();
}
})
}
if (!skin) {
createSkinPickerDialog(true, `[MC Skin] 初次使用需要上传皮肤文件`);
dialog.showModal();
dialog.focus();
dialog.blur();
}
var opacity = GM_getValue("opacity", "0.85");
var positionLeft;
var positionTop;
var w = 130;
var h = 200;
var positionSetting = {
top: {
top: 0
},
bottom: {
top: `calc(100vh - ${h}px)`,
}
}
var position = positionSetting.bottom;
var canvas = document.createElement("canvas");
canvas.style.position = "fixed";
positionLeft = GM_getValue("positionLeft", `calc(100vw - ${w}px)`);
positionTop = GM_getValue("positionTop", position.top);
canvas.style.top = positionTop;
canvas.style.left = positionLeft;
canvas.style.zIndex = 999999999999;
canvas.style.pointerEvents = "none";
canvas.style.opacity = opacity;
document.body.appendChild(canvas);
let skinViewer = new skinview3d.SkinViewer({
canvas: canvas,
width: w,
height: h,
skin: skin
});
var addAnimation = function() {}
var idleAnimation = new skinview3d.FunctionAnimation((player, pr) => {
if (canvas.style.display != "none") {
const t = pr * 2;
// Arm swing
const basicArmRotationZ = Math.PI * 0.02;
player.skin.leftArm.rotation.z = Math.cos(t) * 0.03 + basicArmRotationZ;
player.skin.rightArm.rotation.z = Math.cos(t + Math.PI) * 0.03 - basicArmRotationZ;
// Always add an angle for cape around the x axis
const basicCapeRotationX = Math.PI * 0.06;
player.cape.rotation.x = Math.sin(t) * 0.01 + basicCapeRotationX;
player.rotation.y = defaultRotation;
addAnimation(player, pr)
}
});
skinViewer.animation = idleAnimation;
skinViewer.controls.enablePan = false;
skinViewer.controls.enableZoom = false;
skinViewer.controls.enableRotate = false;
const plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), -10);
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const pointOfIntersection = new THREE.Vector3();
const head = skinViewer.playerObject.skin.head;
var isPlayingAfkAnimation;
var timeout0;
var AfkAnimation = () => {
head.rotation.x = 0;
head.rotation.y = 0;
head.rotation.z = 0;
addAnimation = (pl, pr) => {
var kT = 13.5;
var sin0 = (x) => {
var r = Math.pow(Math.abs(Math.sin(x)), 1 / 1.5)
return Math.sin(x) > 0 ? r : -r
}
var kD = 0.25;
var t1 = Math.abs(sin0(pr / 2 * kT))
pl.skin.body.rotation.x = 0.4537860552 * (1 - kD * t1);
pl.skin.body.position.z = 1.3256181 * (1 - kD * t1) - 3.4500310377 * (1 - kD * t1);
pl.skin.body.position.y = -6 - 2.103677462 * (1 - kD * t1);
pl.skin.head.position.y = -3.618325234674 * (1 - kD * t1);
pl.skin.leftArm.position.z = 3.618325234674 * (1 - kD * t1) - 3.4500310377 * (1 - kD * t1);
pl.skin.rightArm.position.z = pl.skin.leftArm.position.z;
pl.skin.leftArm.rotation.x = 0.510367746202 * (1 - kD * t1);
pl.skin.rightArm.rotation.x = pl.skin.leftArm.rotation.x;
pl.skin.leftArm.rotation.z = 0.1 * (1 - kD * t1);
pl.skin.rightArm.rotation.z = -pl.skin.leftArm.rotation.z;
pl.skin.leftArm.position.y = -2 - 2.53943318 * (1 - kD * t1);
pl.skin.rightArm.position.y = pl.skin.leftArm.position.y;
pl.skin.rightLeg.position.z = -3.4500310377 * (1 - kD * t1);
pl.skin.leftLeg.position.z = pl.skin.rightLeg.position.z;
var mD = 1.5
var t = sin0(pr * kT) * mD
pl.skin.leftLeg.rotation.z = -Math.asin((pl.skin.leftLeg.position.x - 1.9) / 12)
pl.skin.leftLeg.position.x = t + 1.9
pl.skin.rightLeg.rotation.z = pl.skin.leftLeg.rotation.z
pl.skin.rightLeg.position.x = t - 1.9
pl.skin.body.position.x = t / 2
pl.skin.leftArm.position.x = t / 2 + 5 - 0.5 * sin0(Math.max(pr - 0.25 / kT, 0) * kT)
pl.skin.rightArm.position.x = t / 2 - 5 - 0.5 * sin0(Math.max(pr - 0.25 / kT, 0) * kT)
pl.skin.body.rotation.z = -pl.skin.rightLeg.rotation.z
pl.skin.leftArm.rotation.z = Math.asin(sin0(Math.max(pr - 0.25 / kT, 0) * kT) * mD / 12) + Math.PI / 18
pl.skin.rightArm.rotation.z = pl.skin.leftArm.rotation.z - 2 * Math.PI / 18
pl.skin.leftArm.position.y = -2.5 * Math.sin(pl.skin.leftLeg.rotation.z) - 2 - 2.53943318 * (1 - kD * Math.abs(sin0(pr / 2 * kT)));
pl.skin.rightArm.position.y = 2.5 * Math.sin(pl.skin.rightLeg.rotation.z) - 2 - 2.53943318 * (1 - kD * Math.abs(sin0(pr / 2 * kT)));
pl.skin.head.rotation.z = pl.skin.body.rotation.z * 1 / 3
}
}
isPlayingAfkAnimation = false;
timeout0 = setTimeout(() => {
AfkAnimation();
isPlayingAfkAnimation = true;
}, 300000)
var handleAfkAnimation = () => {
clearTimeout(timeout0);
if (isPlayingAfkAnimation) {
addAnimation = () => {}
var pl = skinViewer.playerObject;
pl.skin.head.rotation.set(0, 0, 0);
pl.skin.leftArm.rotation.set(0, 0, 0);
pl.skin.rightArm.rotation.set(0, 0, 0);
pl.skin.leftLeg.rotation.set(0, 0, 0);
pl.skin.rightLeg.rotation.set(0, 0, 0);
pl.skin.body.rotation.set(0, 0, 0);
pl.skin.head.position.y = 0;
pl.skin.body.position.y = -6;
pl.skin.body.position.z = 0;
pl.skin.rightArm.position.x = -5;
pl.skin.rightArm.position.y = -2;
pl.skin.rightArm.position.z = 0;
pl.skin.leftArm.position.x = 5;
pl.skin.leftArm.position.y = -2;
pl.skin.leftArm.position.z = 0;
pl.skin.rightLeg.position.x = -1.9;
pl.skin.rightLeg.position.y = -12;
pl.skin.rightLeg.position.z = -0.1;
pl.skin.leftLeg.position.x = 1.9;
pl.skin.leftLeg.position.y = -12;
pl.skin.leftLeg.position.z = -0.1;
isPlayingAfkAnimation = false;
}
timeout0 = setTimeout(() => {
AfkAnimation();
isPlayingAfkAnimation = true;
}, 300000)
}
function clamp(num, min, max) {
return num <= min ? min : num >= max ? max : num;
}
function stopAddedAnimation() {
_t0 = undefined;
_t1 = undefined;
z0 = undefined;
progress1 = undefined;
progress2 = undefined;
progress3 = undefined;
endRotationX = undefined;
progress4 = undefined;
progress5 = undefined;
endRotationXR = undefined;
endRotationXL = undefined;
isTimeoutSetted = true;
clearTimeout(waveTimeout);
addAnimation = () => {}
}
var waveTimeout;
var isTimeoutSetted = false;
var _t0;
var _t1;
var z0;
function handleWaveAnimation() {
function wave() {
addAnimation = (player, progress) => {
_t0 = !_t0 ? progress : _t0;
const t = (progress - _t0) * 2.1 * Math.PI;
if (t <= Math.PI * 4) {
player.skin.leftArm.rotation.x = -2.21;
player.skin.leftArm.rotation.z = Math.cos(t) * 0.5;
} else {
_t1 = _t1 == undefined ? progress : _t1;
z0 = z0 == undefined ? player.skin.leftArm.rotation.z : z0;
var t1 = Math.cos((progress - _t1) * 15);
if (t1 < 0) {
t1 = 0;
stopAddedAnimation();
return;
}
player.skin.leftArm.rotation.x = -2.21 * t1
player.skin.leftArm.rotation.z = z0 * t1;
}
}
}
if (!isTimeoutSetted) {
waveTimeout = setTimeout(wave, 800);
}
isTimeoutSetted = true;
}
function handleMove(x, y) {
handleAfkAnimation();
const canvasRect = canvas.getBoundingClientRect();
mouse.x = (((x - canvasRect.left) / canvasRect.width) * 2 - 1) / (window.innerWidth / canvasRect.width);
mouse.y = clamp((-((y - canvasRect.top) / canvasRect.height) * 2 + 1) / (window.innerHeight / canvasRect.height) + 0.4 - 0.52 / (window.innerHeight / canvasRect.height), -0.5, 0.9);
raycaster.setFromCamera(mouse, skinViewer.camera);
raycaster.ray.intersectPlane(plane, pointOfIntersection);
head.lookAt(pointOfIntersection);
}
function mouseMoveFunction(e) {
var x = e.clientX;
var y = e.clientY;
handleMove(x, y);
const canvasRect = canvas.getBoundingClientRect();
if (x >= canvasRect.left && x <= canvasRect.left + canvasRect.width && y >= canvasRect.top && y <= canvasRect.top + canvasRect.height) {
handleWaveAnimation();
} else {
clearTimeout(waveTimeout);
isTimeoutSetted = false;
}
}
mouseMoveFunction = rafThrottle(mouseMoveFunction)
window.addEventListener("mousemove", mouseMoveFunction, {
passive: true
});
window.addEventListener("touchstart", e => {
handleMove(e.targetTouches[0].clientX, e.targetTouches[0].clientY)
}, {
passive: true
});
var touchMoveFunction = rafThrottle((e) => {
handleMove(e.targetTouches[0].clientX, e.targetTouches[0].clientY)
})
window.addEventListener("touchmove", touchMoveFunction, {
passive: true
});
var progress1;
var progress2;
var progress3;
var endRotationX;
var ws;
function handleMouseWheelEvent(event) {
handleAfkAnimation();
try {
clearTimeout(ws)
} catch (e) {}
event = event || window.event;
let delta = event.wheelDelta || -event.detail;
var k = Math.pow(Math.abs(delta / 120), 1 / 3);
if (delta > 0) {
addAnimation = function(player, progress) {
if (!progress1) {
progress1 = progress;
isTimeoutSetted = true;
clearTimeout(waveTimeout);
}
progress2 = undefined;
player.skin.rightArm.rotation.x = -0.1 + (Math.floor((progress - progress1) / (Math.PI / (13 * k))) % 2 == 0 ? (-Math.acos(Math.cos((k * 13 * (progress - progress1 - Math.PI / (13 * k))))) * 0.5) : -0.5);
player.skin.leftArm.rotation.x = 0;
}
} else {
addAnimation = function(player, progress) {
if (!progress2) {
progress2 = progress;
isTimeoutSetted = true;
clearTimeout(waveTimeout);
}
progress1 = undefined;
player.skin.rightArm.rotation.x = -0.1 + ((Math.floor((progress - progress2) / (Math.PI / (6 * 2 * k))) % 2 == 0) ? (-Math.abs(Math.asin(Math.sin(6 * k * (progress - progress2)))) * 0.8) : 0);
player.skin.leftArm.rotation.x = 0;
}
}
ws = setTimeout(() => {
addAnimation = function(player, progress) {
if (!endRotationX) {
endRotationX = player.skin.rightArm.rotation.x;
progress3 = progress;
}
player.skin.rightArm.rotation.x = Math.min(4 * (progress - progress3) + endRotationX, 0);
if (player.skin.rightArm.rotation.x == 0) {
progress3 = undefined;
endRotationX = undefined;
stopAddedAnimation();
}
}
progress1 = undefined;
progress2 = undefined;
}, 300)
}
window.addEventListener("wheel", handleMouseWheelEvent, {
passive: true
})
var mousedownFunction = function() {
handleAfkAnimation();
var progress0
addAnimation = function(player, progress) {
if (!progress0) {
progress0 = progress;
isTimeoutSetted = true;
clearTimeout(waveTimeout);
}
player.rotation.y = defaultRotation;
const t = (progress - progress0) * 20;
player.skin.rightArm.rotation.x = -0.4537860552 * 2 + 2 * Math.sin(t + Math.PI) * 0.3;
const basicArmRotationZ = 0.01 * Math.PI + 0.06;
player.skin.rightArm.rotation.z = -Math.cos(t) * 0.403 + basicArmRotationZ;
player.skin.body.rotation.y = -Math.cos(t) * 0.06;
player.skin.leftArm.rotation.x = Math.sin(t + Math.PI) * 0.077;
player.skin.leftArm.rotation.z = -Math.cos(t) * 0.015 + 0.13 - 0.05;
player.skin.leftArm.position.z = Math.cos(t) * 0.3;
player.skin.leftArm.position.x = 5 - Math.cos(t) * 0.05;
if (t >= Math.PI * 2) {
player.skin.rightArm.rotation.x = 0;
stopAddedAnimation();
}
}
}
window.addEventListener("mousedown", mousedownFunction, {
passive: true
})
var timeout;
var progress4;
var progress5;
var time0 = -1;
var endRotationXL;
var endRotationXR;
function handleInputEvent() {
try {
clearTimeout(timeout)
} catch (e) {}
var deltaTime;
if (time0 == -1) {
time0 = Date.now();
} else {
let t = Date.now();
deltaTime = t - time0;
time0 = t;
}
let k = 5 / Math.pow(deltaTime + 1, 1 / 3.6)
k = Number.isNaN(k) ? 1 : k;
addAnimation = function(player, progress) {
if (!progress4) {
progress4 = progress;
isTimeoutSetted = true;
clearTimeout(waveTimeout);
}
var pr = progress - progress4;
player.skin.leftArm.rotation.z = -0.27;
player.skin.rightArm.rotation.z = 0.27;
player.skin.leftArm.rotation.x = -Math.abs(Math.PI / 6 * Math.sin(pr * 5 * k)) - 0.6;
player.skin.rightArm.rotation.x = -Math.abs(Math.PI / 6 * Math.cos(pr * 5 * k)) - 0.6;
}
timeout = setTimeout(() => {
addAnimation = function(player, progress) {
if (!progress5) {
progress5 = progress;
endRotationXL = player.skin.leftArm.rotation.x;
endRotationXR = player.skin.rightArm.rotation.x;
}
player.skin.leftArm.rotation.z = 0;
player.skin.rightArm.rotation.z = 0;
player.skin.rightArm.rotation.x = Math.min(4 * (progress - progress5) + endRotationXR, 0);
player.skin.leftArm.rotation.x = Math.min(4 * (progress - progress5) + endRotationXL, 0);
player.skin.rightArm.rotation.z = Math.min(4 * (progress - progress5) + 0.27, 0);
player.skin.leftArm.rotation.z = Math.max(-4 * (progress - progress5) - 0.27, 0);
if (player.skin.rightArm.rotation.x == 0 && player.skin.leftArm.rotation.x == 0 && player.skin.rightArm.rotation.z == 0 && player.skin.leftArm.rotation.z == 0) {
stopAddedAnimation();
}
}
progress4 = undefined;
}, 600)
}
document.addEventListener('keydown', () => {
handleAfkAnimation();
handleInputEvent();
}, {
passive: true
});
GM_registerMenuCommand("调整透明度", function() {
removeAllChild(dialog)
var d1 = dialog.appendChild(document.createElement("div"))
d1.setAttribute("style", `padding-bottom:15px !important;
font-size:` + fontSize)
var inp = dialog.appendChild(document.createElement("input"));
inp.min = 0;
inp.max = 1;
inp.step = 0.01;
inp.type = "range";
inp.setAttribute("style", `height:5px !important;
width:85% !important;
webkit-appearance: none !important;
accent-color:#6F8DE1 !important;
vertical-align:middle !important;
outline:none !important;
margin-left:7.5% !important;
display:block !important;
`)
inp.addEventListener("input", () => {
d1.innerHTML = (inp.value * 100).toFixed() + "%";
canvas.style.opacity = inp.value;
opacity = inp.value;
})
var d2 = dialog.appendChild(document.createElement("div"))
d2.setAttribute("style", `
margin-top:20px !important;
font-size:` + fontSize.replace(/px/, "") / 1.3 + "px")
d2.innerText = "设置仅对本次当前网页生效,保存设置请单击菜单中 保存当前设置";
dialog.showModal();
dialog.focus();
dialog.blur();
inp.value = canvas.style.opacity;
d1.innerHTML = (inp.value * 100).toFixed() + "%";
})
var moveListeners = [];
var moveMenuId;
var finishMoveMenuId;
function move() {
GM_unregisterMenuCommand(moveMenuId);
finishMoveMenuId = GM_registerMenuCommand("完成移动", finishMove);
function makeDraggable(element) {
element.style.pointerEvents = "auto";
var width = getComputedStyle(element).width.replace(/px/, "") * 1;
var height = getComputedStyle(element).height.replace(/px/, "") * 1;
let isDragging = false;
let startX, startY, initialLeft, initialTop;
const parsePosition = (type) => {
var originalPosition = (type == "left" ? (getComputedStyle(element).left.replace(/px/, "") / window.innerWidth) * 100 + "vw" : (getComputedStyle(element).top.replace(/px/, "") / window.innerHeight) * 100 + "vh")
const value = originalPosition;
const match = value.match(/(-?\d+\.?\d*)v[w|h]/);
return match ? parseFloat(match[1]) : 0;
};
const pxToVW = (px) => (px / window.innerWidth) * 100;
const pxToVH = (px) => (px / window.innerHeight) * 100;
const startDrag = (clientX, clientY) => {
isDragging = true;
initialLeft = parsePosition('left');
initialTop = parsePosition('top');
startX = clientX;
startY = clientY;
};
const handleMove = (clientX, clientY) => {
if (!isDragging) return;
const deltaX = clientX - startX;
const deltaY = clientY - startY;
var isRightSide = (initialLeft + pxToVW(deltaX)) + pxToVW(0.5 * width) >= 50;
var isBottomSide = (initialTop + pxToVH(deltaY)) + pxToVH(0.5 * height) >= 50;
if (isRightSide) {
defaultRotation = -Math.abs(defaultRotation);
element.style.left = `calc(${Math.min((initialLeft + pxToVW(deltaX) + width/window.innerWidth*100),(window.innerWidth+width/2)/window.innerWidth*100,(window.innerHeight+width/2)/window.innerHeight*100)}vw - ${width}px)`;
} else {
defaultRotation = Math.abs(defaultRotation);
element.style.left = `${Math.max((initialLeft + pxToVW(deltaX)),-width/2/window.innerWidth*100,-width/2/window.innerHeight*100)}vw`;
}
if (isBottomSide) {
element.style.top = `calc(${Math.min((initialTop + pxToVH(deltaY) + height/window.innerHeight*100),(window.innerHeight+height/2)/window.innerHeight*100,(window.innerWidth+height/2)/window.innerWidth*100)}vh - ${height}px)`;
} else {
element.style.top = `${Math.max((initialTop + pxToVH(deltaY)),-height/2/window.innerHeight*100,-height/2/window.innerWidth*100)}vh`;
}
};
var mouseMoveFunction = rafThrottle(e => handleMove(e.clientX, e.clientY));
var touchMoveFunction = rafThrottle(e => handleMove(e.touches[0].clientX, e.touches[0].clientY));
const addEvent = (target, type, handler) => {
moveListeners.push({
target: target,
type: type,
handler: handler
})
target.addEventListener(type, handler);
}
addEvent(element, 'mousedown', e => startDrag(e.clientX, e.clientY));
addEvent(element, 'touchstart', e => startDrag(e.touches[0].clientX, e.touches[0].clientY));
addEvent(document, 'mousemove', mouseMoveFunction);
addEvent(document, 'touchmove', touchMoveFunction);
['mouseup', 'touchend'].forEach(type => addEvent(document, type, () => isDragging = false));
}
makeDraggable(canvas)
canvas.style.border = "5px solid red";
}
function finishMove() {
moveListeners.forEach((item) => {
item.target.removeEventListener(item.type, item.handler);
canvas.style.border = "none";
positionLeft = canvas.style.left;
positionTop = canvas.style.top;
})
moveMenuId = GM_registerMenuCommand("移动", move);
GM_unregisterMenuCommand(finishMoveMenuId);
canvas.style.pointerEvents = "none";
}
moveMenuId = GM_registerMenuCommand("移动", move);
GM_registerMenuCommand("保存当前设置", () => {
GM_setValue("positionLeft", positionLeft);
GM_setValue("positionTop", positionTop);
GM_setValue("opacity", opacity);
GM_setValue("skin", skin);
GM_setValue("defaultRotation", defaultRotation);
alert(`[MC Skin]
保存成功,当前参数为:
${GM_getValue("positionLeft")?"位置:left "+GM_getValue("positionLeft")+" top:"+GM_getValue("positionTop")+"\n":""}${GM_getValue("opacity")?"透明度"+GM_getValue("opacity")+"\n":""}${GM_getValue("skin")?"皮肤"+GM_getValue("skin"):""}`)
})
GM_registerMenuCommand("重置当前设置", () => {
GM_deleteValue("positionLeft");
GM_deleteValue("positionTop");
GM_deleteValue("opacity");
GM_deleteValue("skin");
GM_deleteValue("defaultRotation");
})
GM_registerMenuCommand("更换皮肤", function() {
createSkinPickerDialog(false, `选择皮肤 如需保存请点击菜单中 保存当前设置`)
dialog.showModal();
dialog.focus();
dialog.blur();
})
var fullscreenAddition = GM_getValue("fullscreenAddition", false);
var fc1, fc2;
var fullscreenListener = () => {
if (document.fullscreenElement) {
document.fullscreenElement.append(canvas);
} else {
document.body.append(canvas);
}
}
var fc1Click = () => {
document.addEventListener('fullscreenchange', fullscreenListener, {
passive: true
});
GM_unregisterMenuCommand(fc1);
fc2 = GM_registerMenuCommand("点击禁用在全屏时显示皮肤", fc2Click);
GM_setValue("fullscreenAddition", true);
}
var fc2Click = () => {
document.removeEventListener('fullscreenchange', fullscreenListener);
GM_unregisterMenuCommand(fc2);
fc1 = GM_registerMenuCommand("点击启用在全屏时显示皮肤", fc1Click);
GM_setValue("fullscreenAddition", false);
}
if (!fullscreenAddition) {
fc1 = GM_registerMenuCommand("点击启用在全屏时显示皮肤", fc1Click);
} else {
document.addEventListener('fullscreenchange', fullscreenListener, {
passive: true
});
fc2 = GM_registerMenuCommand("点击禁用在全屏时显示皮肤", fc2Click);
}
function addIframeEventListener(iframe) {
function pushEventMessage(e) {
let data = {};
var rectObject = iframe.getBoundingClientRect();
var x = rectObject.left;
var y = rectObject.top;
data.type = e.type;
e.clientX ? data.clientX = e.clientX + x : null;
e.clientY ? data.clientY = e.clientY + y : null;
if (e.targetTouches) {
data.targetTouches = [{
clientX: e.targetTouches[0].clientX + x,
clientY: e.targetTouches[0].clientY + y
}]
}
e.wheelDelta ? data.wheelDelta = e.wheelDelta : null;
e.detail ? data.detail = e.detail : null;
iframe.contentWindow.parent.postMessage({
type: "McSkinIframeEventData",
data: data
}, "*");
}
iframe.contentWindow.addEventListener("mousemove", pushEventMessage, {
passive: true
});
iframe.contentWindow.addEventListener("touchstart", pushEventMessage, {
passive: true
});
iframe.contentWindow.addEventListener("touchmove", pushEventMessage);
iframe.contentWindow.addEventListener("wheel", pushEventMessage, {
passive: true
})
iframe.contentWindow.addEventListener("mousedown", pushEventMessage, {
passive: true
})
iframe.contentDocument.addEventListener('keydown', pushEventMessage, {
passive: true
});
createIframeListener(iframe.contentDocument);
iframe.contentWindow.addEventListener("message", (e) => {
if (e.data.type == "McSkinIframeEventData") {
let data = {};
var rectObject = iframe.getBoundingClientRect();
var x = rectObject.left;
var y = rectObject.top;
data.type = e.data.data.type;
e.data.data.clientX ? data.clientX = e.data.data.clientX + x : null;
e.data.data.clientY ? data.clientY = e.data.data.clientY + y : null;
if (e.data.data.targetTouches) {
data.targetTouches = [{
clientX: e.data.data.targetTouches[0].clientX + x,
clientY: e.data.data.targetTouches[0].clientY + y
}]
}
e.data.data.wheelDelta ? data.wheelDelta = e.data.data.wheelDelta : null;
e.data.data.detail ? data.detail = e.data.data.detail : null;
iframe.contentWindow.parent.postMessage({
type: "McSkinIframeEventData",
data: data
}, "*");
}
}, {
passive: true
})
}
var iframeEventHandler = (e) => {
if (e.data.type == "McSkinIframeEventData") {
let event = e.data.data;
switch (event.type) {
case "mousemove":
mouseMoveFunction(event);
break;
case "touchstart":
case "touchmove":
touchMoveFunction(event);
break;
case "wheel":
handleMouseWheelEvent(event);
break
case "mousedown":
mousedownFunction(event);
break;
case "keydown":
handleAfkAnimation();
handleInputEvent();
break;
}
}
}
window.addEventListener("message", iframeEventHandler, {
passive: true
});
function createIframeListener(document) {
[...document.getElementsByTagName("iframe")].forEach((iframe) => {
if (iframe.contentDocument && iframe.contentDocument.readyState == "complete") {
addIframeEventListener(iframe);
} else {
iframe.addEventListener("load", () => {
addIframeEventListener(iframe);
}, {
passive: true
})
}
})
var nativeDCE = document.createElement;
document.createElement = function(...arg) {
var element = nativeDCE.call(document, ...arg);
if (arg[0].toLowerCase() == "iframe") {
if (element.contentDocument && element.contentDocument.readyState == "complete") {
addIframeEventListener(element);
} else {
element.addEventListener("load", () => {
addIframeEventListener(element);
}, {
passive: true
})
}
}
return element;
}
}
createIframeListener(document);
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
canvas.style.display = "none";
skinViewer.animation.paused = true;
} else {
canvas.style.display = "block";
skinViewer.animation.paused = false;
}
}, {
passive: true
});
})();