Nuked the schema file and create my own. Works much better.

This commit is contained in:
Chris Wilson
2020-08-25 20:51:11 -04:00
parent 76f9717c99
commit ad895f045c
5 changed files with 264 additions and 2060 deletions

View File

@@ -1,20 +1,8 @@
window.addEventListener('load', () => {
const gameSettings = document.getElementById('game-settings');
new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
if (ajax.status !== 200) {
reject("Unable to fetch source yaml file.");
return;
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.yaml` ,true);
ajax.send();
}).then((results) => {
Promise.all([fetchPlayerSettingsYaml(), fetchPlayerSettingsJson()]).then((results) => {
// Load YAML into object
const sourceData = jsyaml.load(results);
const sourceData = jsyaml.safeLoad(results[0], { json: true });
// Update localStorage with three settings objects. Preserve original objects if present.
for (let i=1; i<=3; i++) {
@@ -23,19 +11,51 @@ window.addEventListener('load', () => {
localStorage.setItem(`gameSettings${i}`, JSON.stringify(updatedObj));
}
// Build the entire UI
buildUI(JSON.parse(results[1]));
// Populate the UI and add event listeners
populateSettings();
document.getElementById('preset-number').addEventListener('change', populateSettings);
gameSettings.addEventListener('change', handleOptionChange);
gameSettings.addEventListener('keyup', handleOptionChange);
}).catch((error) => {
gameSettings.innerHTML = `
<h2>Something went wrong while loading your game settings page.</h2>
<h2>${error}</h2>
<h2><a href="${window.location.origin}">Click here to return to safety!</a></h2>
`
<h2>Something went wrong while loading your game settings page.</h2>
<h2>${error}</h2>
<h2><a href="${window.location.origin}">Click here to return to safety!</a></h2>
`
});
});
const fetchPlayerSettingsYaml = () => new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
if (ajax.status !== 200) {
reject("Unable to fetch source yaml file.");
return;
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.yaml` ,true);
ajax.send();
});
const fetchPlayerSettingsJson = () => new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
if (ajax.status !== 200) {
reject('Unable to fetch JSON schema file');
return;
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.json`);
ajax.send();
});
const handleOptionChange = (event) => {
if(!event.target.matches('.setting')) { return; }
const presetNumber = document.getElementById('preset-number').value;
@@ -73,7 +93,6 @@ const populateSettings = () => {
settingsInputs.forEach((input) => {
const settingString = input.getAttribute('data-setting');
const settingValue = getSettingValue(settings, settingString);
console.info(`${settingString}: ${settingValue}`);
if(settingValue !== false){
input.value = settingValue;
document.getElementById(settingString).innerText = settingValue;
@@ -99,3 +118,98 @@ const getSettingValue = (settings, keyString) => {
});
return currentVal;
};
const buildUI = (settings) => {
const settingsWrapper = document.getElementById('settings-wrapper');
Object.values(settings).forEach((setting) => {
if (typeof(setting.inputType) === 'undefined' || !setting.inputType){
console.error(setting);
throw new Error('Setting with no inputType specified.');
}
switch(setting.inputType){
case 'text':
// Currently, all text input is handled manually because there is very little of it
return;
case 'range':
buildRangeSettings(settingsWrapper, setting);
return;
default:
console.error(setting);
throw new Error('Unhandled inputType specified.');
}
});
};
const buildRangeSettings = (parentElement, settings) => {
// Ensure we are operating on a range-specific setting
if(typeof(settings.inputType) === 'undefined' || settings.inputType !== 'range'){
throw new Error('Invalid input type provided to buildRangeSettings func.');
}
const settingWrapper = document.createElement('div');
settingWrapper.className = 'setting-wrapper';
if(typeof(settings.friendlyName) !== 'undefined' && settings.friendlyName){
const sectionTitle = document.createElement('span');
sectionTitle.className = 'title-span';
sectionTitle.innerText = settings.friendlyName;
settingWrapper.appendChild(sectionTitle);
}
if(settings.description){
const description = document.createElement('span');
description.className = 'description-span';
description.innerText = settings.description;
settingWrapper.appendChild(description);
}
// Create table
const optionSetTable = document.createElement('table');
optionSetTable.className = 'option-set';
// Create table body
const tbody = document.createElement('tbody');
Object.keys(settings.subOptions).forEach((setting) => {
// Overwrite setting key name with real object
setting = settings.subOptions[setting];
const settingId = (Math.random() * 1000000).toString();
// Create rows for each option
const optionRow = document.createElement('tr');
// Option name td
const optionName = document.createElement('td');
optionName.className = 'option-name';
const optionLabel = document.createElement('label');
optionLabel.setAttribute('for', settingId);
optionLabel.innerText = setting.friendlyName;
optionName.appendChild(optionLabel);
optionRow.appendChild(optionName);
// Option value td
const optionValue = document.createElement('td');
optionValue.className = 'option-value';
const input = document.createElement('input');
input.className = 'setting';
input.setAttribute('id', settingId);
input.setAttribute('type', 'range');
input.setAttribute('min', '0');
input.setAttribute('max', '100');
input.setAttribute('data-setting', setting.keyString);
input.value = setting.defaultValue;
optionValue.appendChild(input);
const valueDisplay = document.createElement('span');
valueDisplay.setAttribute('id', setting.keyString);
valueDisplay.innerText = setting.defaultValue;
optionValue.appendChild(valueDisplay);
optionRow.appendChild(optionValue);
tbody.appendChild(optionRow);
});
optionSetTable.appendChild(tbody);
settingWrapper.appendChild(optionSetTable);
parentElement.appendChild(settingWrapper);
};
const buildSelectSettings = (parentElement, settings) => {};

View File

@@ -0,0 +1,88 @@
{
"description": {
"keyString": "description",
"friendlyName": "Description",
"inputType": "text",
"description": "A short description of this preset. Useful if you have multiple files",
"defaultValue": "Preset Name"
},
"name": {
"keyString": "name",
"friendlyName": "Player Name",
"inputType": "text",
"description": "Displayed in-game. Spaces will be replaced with underscores.",
"defaultValue": "Your Name"
},
"glitches_required": {
"keyString": "glitches_required",
"friendlyName": "Glitches Required",
"description": "Determine the logic required to complete the seed.",
"inputType": "range",
"subOptions": {
"none": {
"keyString": "glitches_required.none",
"friendlyName": "None",
"description": "No glitches required.",
"defaultValue": 50
},
"minor_glitches": {
"keyString": "glitches_required.minor_glitches",
"friendlyName": "Minor Glitches",
"description": "Puts fake flipper, water-walk, super bunny, etc into logic",
"defaultValue": 0
},
"overworld_glitches": {
"keyString": "glitches_required.overworld_glitches",
"friendlyName": "Overworld Glitches",
"description": "Assumes the player has knowledge of both overworld major glitches (boots clips, mirror clips) and minor glitches (fake flipper, super bunny shenanigans, water walk and etc.)",
"defaultValue": 0
},
"no_logic": {
"keyString": "glitches_required.no_logic",
"friendlyName": "No Logic",
"description": "Your items are placed with no regard to any logic. Your Fire Rod could be on your Trinexx.",
"defaultValue": 0
}
}
},
"map_shuffle": {
"keyString": "map_shuffle",
"friendlyName": "Map Shuffle",
"description": "Shuffle dungeon maps into the world and other dungeons, including other players' worlds.",
"inputType": "range",
"subOptions": {
"off": {
"keyString": "map_shuffle.off",
"friendlyName": "Off",
"description": "Disable map shuffle.",
"defaultValue": 50
},
"on": {
"keyString": "map_shuffle.on",
"friendlyName": "On",
"description": "Enable map shuffle.",
"defaultValue": 0
}
}
},
"compass_shuffle": {
"keyString": "compass_shuffle",
"friendlyName": "Compass Shuffle",
"description": "Shuffle compasses into the world and other dungeons, including other players' worlds",
"inputType": "range",
"subOptions": {
"off": {
"keyString": "compass_shuffle.off",
"friendlyName": "Off",
"description": "Disable compass shuffle.",
"defaultValue": 50
},
"on": {
"keyString": "compass_shuffle.on",
"friendlyName": "On",
"description": "Enable compass shuffle.",
"defaultValue": 0
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -10,8 +10,19 @@
padding-right: 0.25rem;
}
#game-settings #instructions{
text-align: center;
#game-settings .instructions{
text-align: left;
}
#game-settings #settings-wrapper .setting-wrapper{
display: flex;
flex-direction: column;
justify-content: flex-start;
width: 100%;
}
#game-settings #settings-wrapper .setting-wrapper .title-span{
font-weight: bold;
}
#game-settings #settings-wrapper{