XDUPlayer/Js/Main.js

496 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict';
const pixiApp = {
app: new PIXI.Application(baseDimensions),
loader: PIXI.loader
};
const utage = new UtageInfo();
const shaders = new Shaders();
const textFunc = new TextFunctions();
let audio = undefined; //Cant create a audio context without user input.
const player = new Player(pixiApp, utage, textFunc, audio, shaders);
const languages = ["eng", "jpn"];
const version = "YameteTomete XDUPlayer V1.2.0";
let bodyLoaded = false;
let utageLoaded = false;
let languagesLoaded = false;
let selectedLang = "eng";
let currentMission = undefined;
let currentMissionMst = 0;
let currentMissionIndex = 0;
let currentMissionList = [];
let urlParams = {};
let screenw = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
let screenh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
let screenSizeTimeout = undefined;
let isMuted = false;
let volume = 0.5;
let fullScreen = false;
let prevMission = '{Select}';
function onBodyLoaded() {
bodyLoaded = true;
document.getElementById("title-tag").innerText = version;
document.addEventListener('webkitfullscreenchange', onFullScreenChange, false);
document.addEventListener('mozfullscreenchange', onFullScreenChange, false);
document.addEventListener('fullscreenchange', onFullScreenChange, false);
document.addEventListener('MSFullscreenChange', onFullScreenChange, false);
}
(function startLoad() {
let promises = [
utage.loadUtageSettings()
];
Promise.all(promises)
.then((success) => {
utageLoaded = true;
}, (failure) => {
console.log(failure);
});
})();
(function checkIsLoaded() {
if(bodyLoaded) {
document.getElementById('loading-font').style.cssText = "display: none;";
loadLocalStorage();
}
if(utageLoaded && languagesLoaded) {
document.getElementById('loading-utage').style.cssText = "display: none;";
}
if(bodyLoaded && utageLoaded && languagesLoaded) {
document.getElementById('loading-container').style.cssText = "opacity: 0;";
onAllLoaded();
} else {
setTimeout(checkIsLoaded, 200);
}
})();
function onAllLoaded(success) {
textFunc.findTextElements();
buildMissionSelectList();
buildLanguageList();
let appContainer = document.getElementById('app-container');
appContainer.appendChild(pixiApp.app.view);
setTimeout(() => {
document.getElementById('parent-container').style.cssText = "opacity: 1;";
onWindowResize();
window.addEventListener("resize", onWindowResize);
checkQueryParameters();
}, 0);
}
function loadLocalStorage() {
try {
//audio
volume = localStorage.getItem('volume') || 0.5;
volume = Number(volume);
document.getElementById('volume-range').value = volume * 100;
isMuted = localStorage.getItem('ismuted') || false;
if(isMuted === "false") { isMuted = false; }
else if(isMuted === "true") { isMuted = true; }
if(audio) {
audio.changeVolume(volume);
audio.mute(isMuted);
}
if(isMuted) {
document.getElementById('mute-button').innerText = "🔇";
} else {
document.getElementById('mute-button').innerText = "🔊";
}
//language
let lang = localStorage.getItem('language') || "eng";
if(languages.includes(lang)) {
selectedLang = lang;
}
document.getElementById('text-container').className = selectedLang;
utage.setTranslationLanguage(selectedLang, '')
.then((success) => {
languagesLoaded = true;
}, (failure) => {
languagesLoaded = true;
console.log(failure);
});
} catch(error) {
console.log(error);
}
}
function buildMissionSelectList() {
let selectBox = document.getElementById('select-mission');
selectBox.innerHTML = '';
for(let i = -1; i < utage.missionsList.length; ++i) {
let opt = document.createElement('option');
if(i === -1) {
opt.setAttribute('value', '{Select}');
opt.innerText = 'Select Mission';
} else {
let m = utage.missionsList[i];
if(!Object.keys(utage.groupedMissions[m.MstId].Missions).some((mis) => { return utage.groupedMissions[m.MstId].Missions[mis].Enabled === true })) {
continue;
}
opt.setAttribute('value', m.MstId);
let name = m.Name;
if(utage.missionTranslations[m.MstId]) {
name = utage.missionTranslations[m.MstId].Name || name;
}
opt.innerText = name;
}
selectBox.appendChild(opt);
}
}
function buildLanguageList() {
let selectBox = document.getElementById('select-language');
selectBox.innerHTML = '';
for(let i = 0; i < languages.length; ++i) {
let opt = document.createElement('option');
opt.setAttribute('value', languages[i]);
opt.innerText = languages[i];
selectBox.appendChild(opt);
}
selectBox.value = selectedLang;
}
function checkQueryParameters() {
urlParams = commonFunctions.readQueryParameters();
if(urlParams['mstid'] && urlParams['id'] && utage.groupedMissions[urlParams['mstid']] && utage.groupedMissions[urlParams['mstid']].Missions[urlParams['id']]) {
document.getElementById('play-from-query').style.cssText = "position: fixed; z-index: 15; text-align: center; top: 50%; left: 50%; display: block;";
}
}
function playFromQuery(event) {
missionChanged(urlParams['mstid'], urlParams['id']);
document.getElementById('play-from-query').style.cssText = "display: none;";
}
function missionDropDownChanged(event) {
if(!event || !event.currentTarget || !event.currentTarget.value || event.currentTarget.value === '{Select}') { return; }
let cont = document.getElementById("modal-container");
let misId = event.currentTarget.value;
let mis = utage.groupedMissions[misId];
if(!mis) { console.log(`Mission ${misId} not found`); return; }
let name = mis.Name;
let summary = mis.SummaryText;
let credits = "";
if(utage.missionTranslations[mis.MstId]) {
name = utage.missionTranslations[mis.MstId].Name || name;
summary = utage.missionTranslations[mis.MstId].SummaryText || summary;
credits = utage.missionTranslations[mis.MstId].Credits || credits;
}
if(!credits) {
if(selectedLang === "eng") {
credits = "YameteTomete";
} else {
credits = "None";
}
}
let chapterSelect = '<div><span>Chapter Select:</span><select id="ChapterSelect">';
for(let k of Object.keys(mis.Missions)) {
var m = mis.Missions[k];
if(m.Enabled) {
chapterSelect += `<option value="${m.Id}">${m.Id}</option>`
}
}
let detailSrc = `${utage.rootDirectory}${(mis.IsCustom ? "CustomData" : "XDUData")}/Asset/Image/Quest/Snap/Detail/${mis.MstId}.png`;
let iconSrc = `${utage.rootDirectory}${(mis.IsCustom ? "CustomData" : "XDUData")}/Asset/Image/Quest/Snap/Icon/${mis.MstId}.png`;
chapterSelect += '</select></div>';
cont.innerHTML = `
<div id="mission-modal" class="modal">
<span class="mission-title">${name || 'none'}</span>
<img id="mission-detail" src="${detailSrc}"/>
<img id="mission-icon" src="${iconSrc}"/>
<div id="mission-summary">Summary: ${summary || 'none'}</div>
<div class="flex-grow"></div>
<div>Credits (${selectedLang}): ${credits}</div>
<div id="mission-ids">
${chapterSelect}
</div>
<div id="modal-buttons">
<button onclick="closeMissionModal(event, false)">Close</button>
<span>MstId: ${mis.MstId}</span>
<button onclick="missionChanged(${mis.MstId})">Play</button>
</div>
</div>`;
document.getElementById("click-catcher").style.cssText = 'display: flex;';
cont.style.cssText = 'display: flex;';
}
function closeMissionModal(event, wasStarted) {
if(!wasStarted) {
document.getElementById('select-mission').value = prevMission;
} else {
prevMission = document.getElementById('select-mission').value;
}
closeModal(event);
}
function closeModal(event) {
let cont = document.getElementById("modal-container");
document.getElementById("click-catcher").style.cssText = 'display: none;';
cont.style.cssText = 'display: none;';
cont.innerHTML = '';
}
function missionChanged(mstId, value) {
let mst = utage.groupedMissions[mstId];
let name = mst.Name;
if(utage.missionTranslations[mstId]) {
name = utage.missionTranslations[mstId].Name || name;
}
if(!value) {
value = document.getElementById("ChapterSelect").value;
}
if(!audio) {
audio = new audioController(utage);
audio.changeVolume(volume);
audio.mute(isMuted);
player.audio = audio;
}
player.resetAll()
.then((success) => {
let newMission = mst.Missions[value];
checkMissionList(mst.Missions, value);
currentMission = newMission;
currentMissionMst = mstId;
if(!currentMission.Enabled) {
//Check for the next enabled mission. If there are none just reset.
for(let i = currentMissionIndex + 1; i < currentMissionList.length; ++i) {
const mis = mst.Missions[currentMissionList[i]];
if(mis && mis.Enabled) {
missionChanged(currentMissionMst, mis.Id);
return;
}
}
//If we got through the loop there are no more enabled so just end
resetMissions();
return;
}
let promises = [];
if(newMission.IsCustom) {
promises.push(utage.parseMissionFile(`${utage.rootDirectory}CustomData/${newMission.Path.replace('Asset/', '').replace('.utage', '').replace('.tsv', '_t.tsv')}`));
} else {
promises.push(utage.parseMissionFile(`${utage.rootDirectory}XDUData/${newMission.Path.replace('Asset/', '').replace('.utage', '').replace('.tsv', '_t.tsv')}`));
}
promises.push(utage.loadMissionTranslation(`${utage.rootDirectory}Js/Translations/Missions/${currentMission.Path.replace('Asset/Utage/', '').replace('Scenario/', '').replace('.utage', '').replace('.tsv', `_translations_${selectedLang}.json`)}`))
closeMissionModal(undefined, true);
Promise.all(promises)
.then((success) => {
document.getElementById("playing-title").innerText = `${name} (${value})`;
document.getElementById("title-tag").innerText = name;
player.playFile()
.then((success) => {
if(currentMissionIndex !== currentMissionList.length - 1) {
missionChanged(currentMissionMst, mst.Missions[currentMissionList[currentMissionIndex+1]].Id);
} else {
player.resetAll();
resetMissions();
}
}, (failure) => {
player.resetAll();
resetMissions();
console.log(failure);
});
}, (failure) => {
resetMissions();
console.log(failure);
});
}, (failure) => {
console.log(failure);
});
}
function languageChanged(event) {
if(!event || !event.currentTarget || !event.currentTarget.value || event.currentTarget.value === '{Select}' || !languages.includes(event.currentTarget.value)) { return; }
selectedLang = event.currentTarget.value;
let missionPath = '';
if(currentMission) {
missionPath = `${utage.rootDirectory}Js/Translations/Missions/${currentMission.Path.replace('Asset/Utage/', '').replace('Scenario/', '').replace('.utage', '').replace('.tsv', `_translations_${selectedLang}.json`)}`;
}
utage.setTranslationLanguage(selectedLang, missionPath)
.then((success) => {
document.getElementById('text-container').className = selectedLang;
buildMissionSelectList();
localStorage.setItem('language', selectedLang);
});
}
function checkMissionList(missions, currentvalue) {
currentMissionList = [];
let i = 0;
for(var m of Object.keys(missions)) {
currentMissionList.push(m);
if(m === currentvalue) {
currentMissionIndex = i;
}
++i;
}
if(currentMissionIndex + 1 === currentMissionList.length) {
document.getElementById("skip-button").style.cssText = "display: none;";
} else {
document.getElementById("skip-button").style.cssText = "display: inline-block;";
}
}
function resetMissions() {
currentMissionIndex = 0;
currentMissionList = [];
currentMission = undefined;
currentMissionMst = 0;
document.getElementById("skip-button").style.cssText = "display: inline-block;";
document.getElementById("playing-title").innerText = 'None';
document.getElementById("title-tag").innerText = version;
document.getElementById('select-mission').value = '{Select}';
}
function onMainClick(event) {
player.onMainClick(event);
}
function hideUiClicked(event) {
player.hideUiClicked(event);
}
function skipClicked(event) {
if(player.uiHidden) {
player.hideUiClicked(event);
} else if(player.runEvent && currentMissionIndex !== currentMissionList.length - 1) {
event.preventDefault();
event.stopPropagation();
//Find the next enabled mission
for(let i = currentMissionIndex + 1; i < currentMissionList.length; ++i) {
const mis = utage.groupedMissions[currentMissionMst].Missions[currentMissionList[i]];
if(mis && mis.Enabled) {
//missionChanged(currentMissionMst, utage.groupedMissions[currentMissionMst].Missions[currentMissionList[currentMissionIndex+1]].Id);
missionChanged(currentMissionMst, mis.Id);
return;
}
}
//If we got through the loop there are no more enabled so just end
resetMissions();
}
}
function dialogScrollUp(event) {
event.preventDefault();
event.stopPropagation();
textFunc.scrollTextUp();
}
function dialogScrollDown(event) {
event.preventDefault();
event.stopPropagation();
textFunc.scrollTextDown();
}
function onBodyKey(event) {
if(event.code.toLowerCase() === "arrowdown") {
dialogScrollDown(event)
} else if(event.code.toLowerCase() === "arrowup") {
dialogScrollUp(event);
} else if(event.code.toLowerCase() === "space") {
event.preventDefault();
event.stopPropagation();
player.onMainClick(event);
}
}
function openHelpModal(event) {
let cont = document.getElementById("modal-container");
cont.innerHTML = `
<div id="mission-modal" class="modal">
<span class="mission-title">${version}</span>
<div>
<div style="margin: 5px;">Browser Support:<br/>
Chromium: 57+, May work earlier with no audio<br/>
Firefox: 52+, 57+ recommended<br/>
Edge: 17+, older may not have audio<br/>
Safari: 11+, no audio<br/>
IE: Never
</div>
<div style="margin: 5px;">Mobile:<br/>
Android: 5+, Updated Chrome/Firefox/Edge<br/>
iOS: 11+, no audio<br/>
</div>
</div>
<a style="margin-top: auto; text-align: center; "href="https://discord.gg/fpQZQ8g">YameteTomete Discord</a>
<div style="margin-top: auto; text-align: center;">All Symphogear content belongs to its respective owners</div>
<div id="modal-buttons">
<button onclick="closeModal(event)">Close</button>
<a href="https://git.poweris.moe/xduplayer.git/" target="_blank">Source</a>
</div>
</div>`;
document.getElementById("click-catcher").style.cssText = 'display: flex;';
cont.style.cssText = 'display: flex;';
}
function toggleMute(event) {
isMuted = !isMuted;
if(audio) {
audio.mute(isMuted);
}
localStorage.setItem('ismuted', isMuted);
if(isMuted) {
document.getElementById('mute-button').innerText = "🔇";
} else {
document.getElementById('mute-button').innerText = "🔊";
}
}
function onVolumeChange(event) {
volume = Number(event.currentTarget.value) / 100;
if(audio) {
audio.changeVolume(volume);
}
localStorage.setItem('volume', volume);
}
function toggleFullscreen(event) {
event.preventDefault();
event.stopPropagation();
fullScreen = !fullScreen;
let docEl = document.documentElement;
if(fullScreen) {
let requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen;
if(requestFullScreen && !document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement) {
requestFullScreen.call(docEl);
}
} else {
let cancelFullScreen = document.exitFullscreen || document.mozCancelFullScreen || document.webkitExitFullscreen || document.msExitFullscreen;
if(cancelFullScreen) {
cancelFullScreen.call(document);
}
}
}
function onFullScreenChange(event) {
if(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
fullScreen = true;
document.getElementById('other-controls-container').style.cssText = "display: none;";
document.getElementById('title-container').style.cssText = "display: none;";
document.getElementById('fullscreen-button').innerText = "✖️";
} else {
document.getElementById('other-controls-container').style.cssText = "";
document.getElementById('title-container').style.cssText = "";
document.getElementById('fullscreen-button').innerText = "";
}
onWindowResize(event, 0);
}
function onWindowResize(event, delay = 400) {
if(screenSizeTimeout) {
clearTimeout(screenSizeTimeout);
screenSizeTimeout = undefined;
}
screenw = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
screenh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
let topContainerHeight = document.getElementById('other-controls-container').offsetHeight;
topContainerHeight += document.getElementById('title-container').offsetHeight;
let res = commonFunctions.getNewResolution(baseDimensions, screenw, screenh, (topContainerHeight ? topContainerHeight + 6 : topContainerHeight));
screenSizeTimeout = setTimeout(() => {
player.updateResolution(res);
document.getElementById('app-container').style.cssText = `width: ${res.width}px; height: ${res.height}px;`;
}, delay);
}