Working on player-settings update

This commit is contained in:
Chris Wilson 2020-12-03 18:27:32 -05:00
parent ccdc8cefe4
commit da6c44a1cf
11 changed files with 2716 additions and 1815 deletions

View File

@ -85,10 +85,15 @@ def tutorial(lang='en'):
@app.route('/player-settings')
def player_settings():
def player_settings_simple():
return render_template("playerSettings.html")
@app.route('/weighted-settings')
def player_settings():
return render_template("weightedSettings.html")
@app.route('/seed/<suuid:seed>')
def viewSeed(seed: UUID):
seed = Seed.get(id=seed)
@ -148,4 +153,4 @@ def favicon():
from WebHostLib.customserver import run_server_process
from . import tracker, upload, landing, check, generate, downloads, api # to trigger app routing picking up on it
app.register_blueprint(api.api_endpoints)
app.register_blueprint(api.api_endpoints)

View File

@ -0,0 +1,104 @@
window.addEventListener('load', () => {
fetchSettingData().then((settingData) => {
createDefaultSettings(settingData);
buildUI(settingData);
populateSettings();
});
});
const fetchSettingData = () => new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
if (ajax.status !== 200) {
reject(ajax.responseText);
return;
}
try{ resolve(JSON.parse(ajax.responseText)); }
catch(error){ reject(error); }
};
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.json` ,true);
ajax.send();
});
const createDefaultSettings = (settingData) => {
if (!localStorage.getItem('playerSettings')) {
const newSettings = {};
for (let roSetting of Object.keys(settingData.readOnly)){
newSettings[roSetting] = settingData.readOnly[roSetting];
}
for (let gameOption of Object.keys(settingData.gameOptions)){
newSettings[gameOption] = settingData.gameOptions[gameOption].defaultValue;
}
for (let romOption of Object.keys(settingData.romOptions)){
newSettings[romOption] = settingData.romOptions[romOption].defaultValue;
}
localStorage.setItem('playerSettings', JSON.stringify(newSettings));
}
};
const buildUI = (settingData) => {
// Game Options
const leftGameOpts = {};
const rightGameOpts = {};
Object.keys(settingData.gameOptions).forEach((key, index) => {
if (index % 2 === 0) { leftGameOpts[key] = settingData.gameOptions[key]; }
else { rightGameOpts[key] = settingData.gameOptions[key]; }
});
document.getElementById('game-options-left').appendChild(buildOptionsTable(leftGameOpts));
document.getElementById('game-options-right').appendChild(buildOptionsTable(rightGameOpts));
// ROM Options
const leftRomOpts = {};
const rightRomOpts = {};
Object.keys(settingData.romOptions).forEach((key, index) => {
if (index % 2 === 0) { leftRomOpts[key] = settingData.romOptions[key]; }
else { rightRomOpts[key] = settingData.romOptions[key]; }
});
document.getElementById('rom-options-left').appendChild(buildOptionsTable(leftRomOpts));
document.getElementById('rom-options-right').appendChild(buildOptionsTable(rightRomOpts));
};
const buildOptionsTable = (settings) => {
const table = document.createElement('table');
const tbody = document.createElement('tbody');
Object.keys(settings).forEach((setting) => {
const tr = document.createElement('tr');
// td Left
const tdl = document.createElement('td');
const label = document.createElement('label');
label.setAttribute('for', setting);
label.setAttribute('data-tooltip', settings[setting].description);
label.innerText = `${settings[setting].friendlyName}:`;
tdl.appendChild(label);
tr.appendChild(tdl);
// td Right
const tdr = document.createElement('td');
const select = document.createElement('select');
settings[setting].options.forEach((opt) => {
const option = document.createElement('option');
option.setAttribute('value', opt.value);
option.innerText = opt.name;
select.appendChild(option);
});
tdr.appendChild(select);
tr.appendChild(tdr);
tbody.appendChild(tr);
});
table.appendChild(tbody);
return table;
};
const populateSettings = () => {
// TODO
};
const updateSetting = (key, setting) => {
const options = JSON.parse(localStorage.getItem('playerSettings'));
options[key] = setting;
localStorage.setItem('playerSettings', JSON.stringify(options));
};

View File

@ -1,16 +1,16 @@
let spriteData = null;
window.addEventListener('load', () => {
const gameSettings = document.getElementById('player-settings');
const gameSettings = document.getElementById('weighted-settings');
Promise.all([fetchPlayerSettingsYaml(), fetchPlayerSettingsJson(), fetchSpriteData()]).then((results) => {
// Load YAML into object
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++) {
const localSettings = JSON.parse(localStorage.getItem(`playerSettings${i}`));
const localSettings = JSON.parse(localStorage.getItem(`weightedSettings${i}`));
const updatedObj = localSettings ? Object.assign(sourceData, localSettings) : sourceData;
localStorage.setItem(`playerSettings${i}`, JSON.stringify(updatedObj));
localStorage.setItem(`weightedSettings${i}`, JSON.stringify(updatedObj));
}
// Parse spriteData into useful sets
@ -47,7 +47,7 @@ const fetchPlayerSettingsYaml = () => new Promise((resolve, reject) => {
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.yaml` ,true);
ajax.open('GET', `${window.location.origin}/static/static/weightedSettings.yaml` ,true);
ajax.send();
});
@ -61,7 +61,7 @@ const fetchPlayerSettingsJson = () => new Promise((resolve, reject) => {
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/static/playerSettings.json`, true);
ajax.open('GET', `${window.location.origin}/static/static/weightedSettings.json`, true);
ajax.send();
});
@ -82,7 +82,7 @@ const fetchSpriteData = () => new Promise((resolve, reject) => {
const handleOptionChange = (event) => {
if(!event.target.matches('.setting')) { return; }
const presetNumber = document.getElementById('preset-number').value;
const settings = JSON.parse(localStorage.getItem(`playerSettings${presetNumber}`))
const settings = JSON.parse(localStorage.getItem(`weightedSettings${presetNumber}`))
const settingString = event.target.getAttribute('data-setting');
document.getElementById(settingString).innerText = event.target.value;
if(getSettingValue(settings, settingString) !== false){
@ -106,7 +106,7 @@ const handleOptionChange = (event) => {
}
// Save the updated settings object bask to localStorage
localStorage.setItem(`playerSettings${presetNumber}`, JSON.stringify(settings));
localStorage.setItem(`weightedSettings${presetNumber}`, JSON.stringify(settings));
}else{
console.warn(`Unknown setting string received: ${settingString}`)
}
@ -114,7 +114,7 @@ const handleOptionChange = (event) => {
const populateSettings = () => {
const presetNumber = document.getElementById('preset-number').value;
const settings = JSON.parse(localStorage.getItem(`playerSettings${presetNumber}`))
const settings = JSON.parse(localStorage.getItem(`weightedSettings${presetNumber}`))
const settingsInputs = Array.from(document.querySelectorAll('.setting'));
settingsInputs.forEach((input) => {
const settingString = input.getAttribute('data-setting');
@ -147,13 +147,13 @@ const getSettingValue = (settings, keyString) => {
const exportSettings = () => {
const presetNumber = document.getElementById('preset-number').value;
const settings = JSON.parse(localStorage.getItem(`playerSettings${presetNumber}`));
const settings = JSON.parse(localStorage.getItem(`weightedSettings${presetNumber}`));
const yamlText = jsyaml.safeDump(settings, { noCompatMode: true }).replaceAll(/'(\d+)':/g, (x, y) => `${y}:`);
download(`${settings.description}.yaml`, yamlText);
};
const resetToDefaults = () => {
[1, 2, 3].forEach((presetNumber) => localStorage.removeItem(`playerSettings${presetNumber}`));
[1, 2, 3].forEach((presetNumber) => localStorage.removeItem(`weightedSettings${presetNumber}`));
location.reload();
};
@ -225,7 +225,7 @@ const buildUI = (settings) => {
tbody.setAttribute('id', 'sprites-tbody');
const currentPreset = document.getElementById('preset-number').value;
const playerSettings = JSON.parse(localStorage.getItem(`playerSettings${currentPreset}`));
const playerSettings = JSON.parse(localStorage.getItem(`weightedSettings${currentPreset}`));
// Manually add a row for random sprites
addSpriteRow(tbody, playerSettings, 'random');
@ -369,7 +369,7 @@ const addSpriteRow = (tbody, playerSettings, spriteName) => {
const addSpriteOption = (event) => {
const presetNumber = document.getElementById('preset-number').value;
const playerSettings = JSON.parse(localStorage.getItem(`playerSettings${presetNumber}`));
const playerSettings = JSON.parse(localStorage.getItem(`weightedSettings${presetNumber}`));
const spriteName = event.target.getAttribute('data-sprite');
console.log(event.target);
console.log(spriteName);
@ -381,7 +381,7 @@ const addSpriteOption = (event) => {
// Add option to playerSettings object
playerSettings.rom.sprite[event.target.getAttribute('data-sprite')] = 50;
localStorage.setItem(`playerSettings${presetNumber}`, JSON.stringify(playerSettings));
localStorage.setItem(`weightedSettings${presetNumber}`, JSON.stringify(playerSettings));
// Add <tr> to #sprite-options-table
const tbody = document.getElementById('sprites-tbody');
@ -390,12 +390,12 @@ const addSpriteOption = (event) => {
const removeSpriteOption = (event) => {
const presetNumber = document.getElementById('preset-number').value;
const playerSettings = JSON.parse(localStorage.getItem(`playerSettings${presetNumber}`));
const playerSettings = JSON.parse(localStorage.getItem(`weightedSettings${presetNumber}`));
const spriteName = event.target.getAttribute('data-sprite');
// Remove option from playerSettings object
delete playerSettings.rom.sprite[spriteName];
localStorage.setItem(`playerSettings${presetNumber}`, JSON.stringify(playerSettings));
localStorage.setItem(`weightedSettings${presetNumber}`, JSON.stringify(playerSettings));
// Remove <tr> from #sprite-options-table
const tr = document.getElementById(event.target.getAttribute('data-row-id'));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,100 @@
html{
background-image: url('../static/backgrounds/grass/grass-0007-large.png');
background-repeat: repeat;
background-size: 650px 650px;
}
#player-settings{
max-width: 1000px;
margin-left: auto;
margin-right: auto;
background-color: rgba(0, 0, 0, 0.15);
border-radius: 8px;
padding: 1rem;
color: #eeffeb;
}
#player-settings code{
background-color: #d9cd8e;
border-radius: 4px;
padding-left: 0.25rem;
padding-right: 0.25rem;
color: #000000;
}
#player-settings h1{
font-size: 2.5rem;
font-weight: normal;
border-bottom: 1px solid #ffffff;
width: 100%;
margin-bottom: 0.5rem;
color: #ffffff;
text-shadow: 1px 1px 4px #000000;
}
#player-settings h2{
font-size: 2rem;
font-weight: normal;
border-bottom: 1px solid #ffffff;
width: 100%;
margin-bottom: 0.5rem;
color: #ffe993;
text-transform: lowercase;
text-shadow: 1px 1px 2px #000000;
}
#player-settings h3, #player-settings h4, #player-settings h5, #player-settings h6{
color: #ffffff;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
}
#player-settings a{
color: #ffef00;
}
#player-settings input:not([type]){
border: 1px solid #000000;
padding: 3px;
border-radius: 3px;
min-width: 150px;
}
#player-settings select{
border: 1px solid #000000;
padding: 3px;
border-radius: 3px;
min-width: 150px;
}
#player-settings #game-options, #player-settings #rom-options{
display: flex;
flex-direction: row;
}
#player-settings .left, #game-options .right{
flex-grow: 1;
}
#player-settings table select{
width: 250px;
}
#player-settings table label{
margin-right: 4px;
}
@media all and (max-width: 1000px){
#player-settings #game-options, #player-settings #rom-options{
justify-content: flex-start;
flex-wrap: wrap;
}
#player-settings .left, #player-settings .right{
flex-grow: unset;
}
#game-options table label, #rom-options table label{
display: block;
min-width: 200px;
}
}

View File

@ -4,7 +4,7 @@ html{
background-size: 650px 650px;
}
#player-settings{
#weighted-settings{
width: 60rem;
margin-left: auto;
margin-right: auto;
@ -14,7 +14,7 @@ html{
color: #eeffeb;
}
#player-settings code{
#weighted-settings code{
background-color: #d9cd8e;
border-radius: 4px;
padding-left: 0.25rem;
@ -22,7 +22,7 @@ html{
color: #000000;
}
#player-settings h1{
#weighted-settings h1{
font-size: 2.5rem;
font-weight: normal;
border-bottom: 1px solid #ffffff;
@ -32,7 +32,7 @@ html{
text-shadow: 1px 1px 4px #000000;
}
#player-settings h2{
#weighted-settings h2{
font-size: 2rem;
font-weight: normal;
border-bottom: 1px solid #ffffff;
@ -43,103 +43,103 @@ html{
text-shadow: 1px 1px 2px #000000;
}
#player-settings h3, #player-settings h4, #player-settings h5, #player-settings h6{
#weighted-settings h3, #weighted-settings h4, #weighted-settings h5, #weighted-settings h6{
color: #ffffff;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
}
#player-settings .instructions{
#weighted-settings .instructions{
text-align: left;
}
#player-settings #settings-wrapper .setting-wrapper{
#weighted-settings #settings-wrapper .setting-wrapper{
display: flex;
flex-direction: column;
justify-content: flex-start;
width: 100%;
}
#player-settings #settings-wrapper .setting-wrapper .title-span{
#weighted-settings #settings-wrapper .setting-wrapper .title-span{
font-weight: 600;
font-size: 1.25rem;
}
#player-settings #settings-wrapper{
#weighted-settings #settings-wrapper{
margin-top: 1.5rem;
}
#player-settings #settings-wrapper #sprite-picker{
#weighted-settings #settings-wrapper #sprite-picker{
margin-bottom: 2rem;
}
#player-settings #settings-wrapper #sprite-picker #sprite-picker-sprites{
#weighted-settings #settings-wrapper #sprite-picker #sprite-picker-sprites{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
}
#player-settings #settings-wrapper #sprite-picker .sprite-img-wrapper{
#weighted-settings #settings-wrapper #sprite-picker .sprite-img-wrapper{
cursor: pointer;
margin: 10px;
image-rendering: pixelated;
}
/* Center tooltip text for sprite images */
#player-settings #settings-wrapper #sprite-picker .sprite-img-wrapper::after{
#weighted-settings #settings-wrapper #sprite-picker .sprite-img-wrapper::after{
text-align: center;
}
#player-settings #settings-wrapper #sprite-picker .sprite-img-wrapper img{
#weighted-settings #settings-wrapper #sprite-picker .sprite-img-wrapper img{
width: 32px;
height: 48px;
}
#player-settings table.option-set{
#weighted-settings table.option-set{
width: 100%;
margin-bottom: 1.5rem;
}
#player-settings table.option-set td.option-name{
#weighted-settings table.option-set td.option-name{
width: 150px;
font-weight: 400;
font-size: 1rem;
line-height: 2rem;
}
#player-settings table.option-set td.option-name .delete-button{
#weighted-settings table.option-set td.option-name .delete-button{
cursor: pointer;
}
#player-settings table.option-set td.option-value{
#weighted-settings table.option-set td.option-value{
line-height: 2rem;
}
#player-settings table.option-set td.option-value input[type=range]{
#weighted-settings table.option-set td.option-value input[type=range]{
width: 90%;
min-width: 300px;
vertical-align: middle;
}
#player-settings #player-settings-button-row{
#weighted-settings #weighted-settings-button-row{
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
}
#player-settings a{
#weighted-settings a{
color: #ffef00;
}
#player-settings input:not([type]){
#weighted-settings input:not([type]){
border: 1px solid #000000;
padding: 3px;
border-radius: 3px;
min-width: 150px;
}
#player-settings select{
#weighted-settings select{
border: 1px solid #000000;
padding: 3px;
border-radius: 3px;

View File

@ -2,71 +2,34 @@
{% block head %}
<title>Player Settings</title>
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/player-settings.css") }}" />
<script type="application/ecmascript" src="{{ static_autoversion("assets/js-yaml.min.js") }}"></script>
<script type="application/ecmascript" src="{{ static_autoversion("assets/player-settings.js") }}"></script>
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/playerSettings.css") }}" />
<script type="application/ecmascript" src="{{ static_autoversion("assets/playerSettings.js") }}"></script>
{% endblock %}
{% block body %}
{% include 'header/grassHeader.html' %}
<div id="player-settings">
<h1>Player Settings</h1>
<div id="instructions">
This page is used to configure your player settings. You have three presets you can control, which
you can access using the dropdown menu below. These settings will be usable when generating a
single player game, or you can export them to a <code>.yaml</code> file and use them in a multiworld.
If you already have a settings file you would like to validate, you may do so on the
<a href="/mysterycheck">verification page</a>.
<p>Choose the options you would like to play with! You may generate a single-player game from this page,
or download a settings file you can use to participate in a MultiWorld. If you would like to make
your settings extra random, check out the <a href="/weighted-settings">weighted settings</a>
page.</p>
<p><label for="player-name">Please enter your player name. This will appear in-game as you send and receive
items, if you are playing in a MultiWorld.</label><br />
<input id="player-name" placeholder="Player Name" />
</p>
<h2>Game Options</h2>
<div id="game-options">
<div id="game-options-left" class="left"></div>
<div id="game-options-right" class="right"></div>
</div>
<div id="settings-wrapper">
<div class="setting-wrapper">
Choose a preset and optionally assign it a nickname, which will be used as the file's description if
you download it.
<table class="option-set">
<tbody>
<tr>
<td class="option-name">
<label for="preset-number">Preset Number:</label>
</td>
<td class="option-value">
<select id="preset-number">
<option value="1">Preset 1</option>
<option value="2">Preset 2</option>
<option value="3">Preset 3</option>
</select>
</td>
</tr>
<tr>
<td class="option-name">
<label for="description">Preset Name:</label>
</td>
<td class="option-value">
<input id="description" class="setting" data-setting="description" />
</td>
</tr>
</tbody>
</table>
</div>
Choose a name you want to represent you in-game. This will appear when you send items
to other people in multiworld games.
<table class="option-set">
<tbody>
<tr>
<td class="option-name">
<label for="name">Player Name:</label>
</td>
<td class="option-value">
<input id="name" maxlength="16" class="setting" data-setting="name" />
</td>
</tr>
</tbody>
</table>
</div>
<div id="player-settings-button-row">
<button id="reset-to-default">Reset to Defaults</button>
<button id="export-button">Export Settings</button>
<h2>ROM Options</h2>
<div id="rom-options">
<div id="rom-options-left" class="left"></div>
<div id="rom-options-right" class="right"></div>
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -0,0 +1,72 @@
{% extends 'pageWrapper.html' %}
{% block head %}
<title>Player Settings</title>
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("styles/weightedSettings.css") }}" />
<script type="application/ecmascript" src="{{ static_autoversion("assets/js-yaml.min.js") }}"></script>
<script type="application/ecmascript" src="{{ static_autoversion("assets/weightedSettings.js") }}"></script>
{% endblock %}
{% block body %}
{% include 'header/grassHeader.html' %}
<div id="weighted-settings">
<h1>Weighted Settings</h1>
<div id="instructions">
This page is used to configure your weighted settings. You have three presets you can control, which
you can access using the dropdown menu below. These settings will be usable when generating a
single player game, or you can export them to a <code>.yaml</code> file and use them in a multiworld.
If you already have a settings file you would like to validate, you may do so on the
<a href="/mysterycheck">verification page</a>.
</div>
<div id="settings-wrapper">
<div class="setting-wrapper">
Choose a preset and optionally assign it a nickname, which will be used as the file's description if
you download it.
<table class="option-set">
<tbody>
<tr>
<td class="option-name">
<label for="preset-number">Preset Number:</label>
</td>
<td class="option-value">
<select id="preset-number">
<option value="1">Preset 1</option>
<option value="2">Preset 2</option>
<option value="3">Preset 3</option>
</select>
</td>
</tr>
<tr>
<td class="option-name">
<label for="description">Preset Name:</label>
</td>
<td class="option-value">
<input id="description" class="setting" data-setting="description" />
</td>
</tr>
</tbody>
</table>
</div>
Choose a name you want to represent you in-game. This will appear when you send items
to other people in multiworld games.
<table class="option-set">
<tbody>
<tr>
<td class="option-name">
<label for="name">Player Name:</label>
</td>
<td class="option-value">
<input id="name" maxlength="16" class="setting" data-setting="name" />
</td>
</tr>
</tbody>
</table>
</div>
<div id="weighted-settings-button-row">
<button id="reset-to-default">Reset to Defaults</button>
<button id="export-button">Export Settings</button>
</div>
</div>
{% endblock %}

View File

@ -113,7 +113,7 @@ for data in extra_data:
installfile(Path(data))
os.makedirs(buildfolder / "Players", exist_ok=True)
shutil.copyfile("playerSettings.yaml", buildfolder / "Players" / "playerSettings.yaml")
shutil.copyfile("playerSettings.yaml", buildfolder / "Players" / "weightedSettings.yaml")
try:
from maseya import z3pr