Merge branch 'main' into player-tracker

This commit is contained in:
Chris Wilson
2022-09-24 18:35:59 -04:00
144 changed files with 4851 additions and 3263 deletions

46
WebHostLib/README.md Normal file
View File

@@ -0,0 +1,46 @@
# WebHost
## Contribution Guidelines
**Thank you for your interest in contributing to the Archipelago website!**
Much of the content on the website is generated automatically, but there are some things
that need a personal touch. For those things, we rely on contributions from both the core
team and the community. The current primary maintainer of the website is Farrak Kilhn.
He may be found on Discord as `Farrak Kilhn#0418`, or on GitHub as `LegendaryLinux`.
### Small Changes
Little changes like adding a button or a couple new select elements are perfectly fine.
Tweaks to style specific to a PR's content are also probably not a problem. For example, if
you build a new page which needs two side by side tables, and you need to write a CSS file
specific to your page, that is perfectly reasonable.
### Content Additions
Once you develop a new feature or add new content the website, make a pull request. It will
be reviewed by the community and there will probably be some discussion around it. Depending
on the size of the feature, and if new styles are required, there may be an additional step
before the PR is accepted wherein Farrak works with the designer to implement styles.
### Restrictions on Style Changes
A professional designer is paid to develop the styles and assets for the Archipelago website.
In an effort to maintain a consistent look and feel, pull requests which *exclusively*
change site styles are rejected. Please note this applies to code which changes the overall
look and feel of the site, not to small tweaks to CSS for your custom page. The intention
behind these restrictions is to maintain a curated feel for the design of the site. If
any PR affects the overall feel of the site but includes additive changes, there will
likely be a conversation about how to implement those changes without compromising the
curated site style. It is therefore worth noting there are a couple files which, if
changed in your pull request, will cause it to draw additional scrutiny.
These closely guarded files are:
- `globalStyles.css`
- `islandFooter.css`
- `landing.css`
- `markdown.css`
- `tooltip.css`
### Site Themes
There are several themes available for game pages. It is possible to request a new theme in
the `#art-and-design` channel on Discord. Because themes are created by the designer, they
are not free, and take some time to create. Farrak works closely with the designer to implement
these themes, and pays for the assets out of pocket. Therefore, only a couple themes per year
are added. If a proposed theme seems like a cool idea and the community likes it, there is a
good chance it will become a reality.

View File

@@ -1,15 +1,16 @@
from __future__ import annotations
import functools
import websockets
import asyncio
import collections
import datetime
import functools
import logging
import pickle
import random
import socket
import threading
import time
import random
import pickle
import logging
import datetime
import websockets
import Utils
from .models import db_session, Room, select, commit, Command, db
@@ -49,6 +50,8 @@ class DBCommandProcessor(ServerCommandProcessor):
class WebHostContext(Context):
room_id: int
def __init__(self, static_server_data: dict):
# static server data is used during _load_game_data to load required data,
# without needing to import worlds system, which takes quite a bit of memory
@@ -62,6 +65,8 @@ class WebHostContext(Context):
def _load_game_data(self):
for key, value in self.static_server_data.items():
setattr(self, key, value)
self.forced_auto_forfeits = collections.defaultdict(lambda: False, self.forced_auto_forfeits)
self.non_hintable_names = collections.defaultdict(frozenset, self.non_hintable_names)
def listen_to_db_commands(self):
cmdprocessor = DBCommandProcessor(self)
@@ -103,7 +108,7 @@ class WebHostContext(Context):
room.multisave = pickle.dumps(self.get_save())
# saving only occurs on activity, so we can "abuse" this information to mark this as last_activity
if not exit_save: # we don't want to count a shutdown as activity, which would restart the server again
room.last_activity = datetime.utcnow()
room.last_activity = datetime.datetime.utcnow()
return True
def get_save(self) -> dict:

View File

@@ -32,9 +32,12 @@ def download_patch(room_id, patch_id):
new_zip.writestr("archipelago.json", json.dumps(manifest))
else:
new_zip.writestr(file.filename, zf.read(file), file.compress_type, 9)
if "patch_file_ending" in manifest:
patch_file_ending = manifest["patch_file_ending"]
else:
patch_file_ending = AutoPatchRegister.patch_types[patch.game].patch_file_ending
fname = f"P{patch.player_id}_{patch.player_name}_{app.jinja_env.filters['suuid'](room_id)}" \
f"{AutoPatchRegister.patch_types[patch.game].patch_file_ending}"
f"{patch_file_ending}"
new_file.seek(0)
return send_file(new_file, as_attachment=True, download_name=fname)
else:

View File

@@ -1,6 +1,6 @@
import logging
import os
from Utils import __version__
from Utils import __version__, local_path
from jinja2 import Template
import yaml
import json
@@ -9,14 +9,13 @@ import typing
from worlds.AutoWorld import AutoWorldRegister
import Options
target_folder = os.path.join("WebHostLib", "static", "generated")
handled_in_js = {"start_inventory", "local_items", "non_local_items", "start_hints", "start_location_hints",
"exclude_locations"}
def create():
os.makedirs(os.path.join(target_folder, 'configs'), exist_ok=True)
target_folder = local_path("WebHostLib", "static", "generated")
os.makedirs(os.path.join(target_folder, "configs"), exist_ok=True)
def dictify_range(option: typing.Union[Options.Range, Options.SpecialRange]):
data = {}
@@ -49,6 +48,11 @@ def create():
return list(default_value)
return default_value
def get_html_doc(option_type: type(Options.Option)) -> str:
if not option_type.__doc__:
return "Please document me!"
return "\n".join(line.strip() for line in option_type.__doc__.split("\n")).strip()
weighted_settings = {
"baseOptions": {
"description": "Generated by https://archipelago.gg/",
@@ -61,12 +65,16 @@ def create():
for game_name, world in AutoWorldRegister.world_types.items():
all_options = {**Options.per_game_common_options, **world.option_definitions}
res = Template(open(os.path.join("WebHostLib", "templates", "options.yaml")).read()).render(
with open(local_path("WebHostLib", "templates", "options.yaml")) as f:
file_data = f.read()
res = Template(file_data).render(
options=all_options,
__version__=__version__, game=game_name, yaml_dump=yaml.dump,
dictify_range=dictify_range, default_converter=default_converter,
)
del file_data
with open(os.path.join(target_folder, 'configs', game_name + ".yaml"), "w") as f:
f.write(res)
@@ -88,7 +96,7 @@ def create():
game_options[option_name] = this_option = {
"type": "select",
"displayName": option.display_name if hasattr(option, "display_name") else option_name,
"description": option.__doc__ if option.__doc__ else "Please document me!",
"description": get_html_doc(option),
"defaultValue": None,
"options": []
}
@@ -114,7 +122,7 @@ def create():
game_options[option_name] = {
"type": "range",
"displayName": option.display_name if hasattr(option, "display_name") else option_name,
"description": option.__doc__ if option.__doc__ else "Please document me!",
"description": get_html_doc(option),
"defaultValue": option.default if hasattr(
option, "default") and option.default != "random" else option.range_start,
"min": option.range_start,
@@ -131,14 +139,14 @@ def create():
game_options[option_name] = {
"type": "items-list",
"displayName": option.display_name if hasattr(option, "display_name") else option_name,
"description": option.__doc__ if option.__doc__ else "Please document me!",
"description": get_html_doc(option),
}
elif getattr(option, "verify_location_name", False):
game_options[option_name] = {
"type": "locations-list",
"displayName": option.display_name if hasattr(option, "display_name") else option_name,
"description": option.__doc__ if option.__doc__ else "Please document me!",
"description": get_html_doc(option),
}
elif issubclass(option, Options.OptionList) or issubclass(option, Options.OptionSet):
@@ -146,7 +154,7 @@ def create():
game_options[option_name] = {
"type": "custom-list",
"displayName": option.display_name if hasattr(option, "display_name") else option_name,
"description": option.__doc__ if option.__doc__ else "Please document me!",
"description": get_html_doc(option),
"options": list(option.valid_keys),
}

View File

@@ -1,7 +1,7 @@
flask>=2.1.3
flask>=2.2.2
pony>=0.7.16
waitress>=2.1.1
waitress>=2.1.2
Flask-Caching>=2.0.1
Flask-Compress>=1.12
Flask-Limiter>=2.5.0
Flask-Limiter>=2.6.2
bokeh>=2.4.3

View File

@@ -102,9 +102,15 @@ const buildOptionsTable = (settings, romOpts = false) => {
// td Left
const tdl = document.createElement('td');
const label = document.createElement('label');
label.textContent = `${settings[setting].displayName}: `;
label.setAttribute('for', setting);
label.setAttribute('data-tooltip', settings[setting].description);
label.innerText = `${settings[setting].displayName}:`;
const questionSpan = document.createElement('span');
questionSpan.classList.add('interactive');
questionSpan.setAttribute('data-tooltip', settings[setting].description);
questionSpan.innerText = '(?)';
label.appendChild(questionSpan);
tdl.appendChild(label);
tr.appendChild(tdl);

View File

@@ -56,7 +56,3 @@
#file-input{
display: none;
}
.interactive{
color: #ffef00;
}

View File

@@ -105,3 +105,7 @@ h5, h6{
margin-bottom: 20px;
background-color: #ffff00;
}
.interactive{
color: #ffef00;
}

View File

@@ -14,7 +14,6 @@ give it one of the following classes: tooltip-left, tooltip-right, tooltip-top,
/* Base styles for the element that has a tooltip */
[data-tooltip], .tooltip {
position: relative;
cursor: pointer;
}
/* Base styles for the entire tooltip */
@@ -55,14 +54,15 @@ give it one of the following classes: tooltip-left, tooltip-right, tooltip-top,
/** Content styles */
.tooltip:after, [data-tooltip]:after {
width: 260px;
z-index: 10000;
padding: 8px;
width: 160px;
border-radius: 4px;
background-color: #000;
background-color: hsla(0, 0%, 20%, 0.9);
color: #fff;
content: attr(data-tooltip);
white-space: pre-wrap;
font-size: 14px;
line-height: 1.2;
}

View File

@@ -41,12 +41,11 @@
<tbody>
<tr>
<td>
<label for="forfeit_mode">Forfeit Permission:</label>
<span
class="interactive"
data-tooltip="A forfeit releases all remaining items from the locations
in your world.">(?)
</span>
<label for="forfeit_mode">Forfeit Permission:
<span class="interactive" data-tooltip="A forfeit releases all remaining items from the locations in your world.">
(?)
</span>
</label>
</td>
<td>
<select name="forfeit_mode" id="forfeit_mode">
@@ -63,12 +62,11 @@
<tr>
<td>
<label for="collect_mode">Collect Permission:</label>
<span
class="interactive"
data-tooltip="A collect releases all of your remaining items to you
from across the multiworld.">(?)
</span>
<label for="collect_mode">Collect Permission:
<span class="interactive" data-tooltip="A collect releases all of your remaining items to you from across the multiworld.">
(?)
</span>
</label>
</td>
<td>
<select name="collect_mode" id="collect_mode">
@@ -85,12 +83,11 @@
<tr>
<td>
<label for="remaining_mode">Remaining Permission:</label>
<span
class="interactive"
data-tooltip="Remaining lists all items still in your world by name only."
>(?)
</span>
<label for="remaining_mode">Remaining Permission:
<span class="interactive" data-tooltip="Remaining lists all items still in your world by name only.">
(?)
</span>
</label>
</td>
<td>
<select name="remaining_mode" id="remaining_mode">
@@ -106,11 +103,11 @@
</tr>
<tr>
<td>
<label for="item_cheat">Item Cheat:</label>
<span
class="interactive"
data-tooltip="Allows players to use the !getitem command.">(?)
</span>
<label for="item_cheat">Item Cheat:
<span class="interactive" data-tooltip="Allows players to use the !getitem command.">
(?)
</span>
</label>
</td>
<td>
<select name="item_cheat" id="item_cheat">
@@ -131,12 +128,11 @@
<tbody>
<tr>
<td>
<label for="hint_cost"> Hint Cost:</label>
<span
class="interactive"
data-tooltip="After gathering this many checks, players can !hint <itemname>
to get the location of that hint item.">(?)
</span>
<label for="hint_cost"> Hint Cost:
<span class="interactive" data-tooltip="After gathering this many checks, players can !hint <itemname> to get the location of that hint item.">
(?)
</span>
</label>
</td>
<td>
<select name="hint_cost" id="hint_cost">
@@ -150,11 +146,11 @@
</tr>
<tr>
<td>
<label for="server_password">Server Password:</label>
<span
class="interactive"
data-tooltip="Allows for issuing of server console commands from any text client or in-game client using the !admin command.">(?)
</span>
<label for="server_password">Server Password:
<span class="interactive" data-tooltip="Allows for issuing of server console commands from any text client or in-game client using the !admin command.">
(?)
</span>
</label>
</td>
<td>
<input id="server_password" name="server_password">
@@ -162,23 +158,22 @@
</tr>
<tr>
<td>
<label for="plando_options">Plando Options:</label>
<span
class="interactive"
data-tooltip="Allows players to plan some of the randomization. See the 'Archipelago Plando Guide' in 'Setup Guides' for more information.">(?)
Plando Options:
<span class="interactive" data-tooltip="Allows players to plan some of the randomization. See the 'Archipelago Plando Guide' in 'Setup Guides' for more information.">
(?)
</span>
</td>
<td>
<input type="checkbox" name="plando_bosses" value="bosses" checked>
<input type="checkbox" id="plando_bosses" name="plando_bosses" value="bosses" checked>
<label for="plando_bosses">Bosses</label><br>
<input type="checkbox" name="plando_items" value="items" checked>
<input type="checkbox" id="plando_items" name="plando_items" value="items" checked>
<label for="plando_items">Items</label><br>
<input type="checkbox" name="plando_connections" value="connections" checked>
<input type="checkbox" id="plando_connections" name="plando_connections" value="connections" checked>
<label for="plando_connections">Connections</label><br>
<input type="checkbox" name="plando_texts" value="texts" checked>
<input type="checkbox" id="plando_texts" name="plando_texts" value="texts" checked>
<label for="plando_texts">Text</label>
</td>
</tr>

View File

@@ -6,8 +6,6 @@
-
<a href="https://github.com/ArchipelagoMW/Archipelago">Source Code</a>
-
<a href="https://github.com/ArchipelagoMW/Archipelago/wiki">Wiki</a>
-
<a href="https://github.com/ArchipelagoMW/Archipelago/graphs/contributors">Contributors</a>
-
<a href="https://github.com/ArchipelagoMW/Archipelago/issues">Bug Report</a>

View File

@@ -1,7 +1,7 @@
{% extends 'pageWrapper.html' %}
{% block head %}
<title>Player Settings</title>
<title>Supported Games</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/markdown.css") }}" />
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/supportedGames.css") }}" />
{% endblock %}