Compare commits

...

18 Commits

  1. 2
      .pylintrc
  2. 14
      Dockerfile
  3. 23
      conftest.py
  4. 1
      docker/config/site.cfg
  5. 6
      docker/run.sh
  6. 14
      requirements-dev.txt
  7. 13
      requirements.txt
  8. 2
      setup.py
  9. 5
      vasl_templates/about.py
  10. 3
      vasl_templates/main.py
  11. 26
      vasl_templates/ui/about.ui
  12. 10
      vasl_templates/webapp/__init__.py
  13. 3
      vasl_templates/webapp/config/constants.py
  14. 2
      vasl_templates/webapp/config/site.cfg.example
  15. 3
      vasl_templates/webapp/data/default-template-pack/national-capabilities.json
  16. 6
      vasl_templates/webapp/data/ordnance/french.json
  17. 4
      vasl_templates/webapp/data/vasl-6.6.6/piece-info.json
  18. 72
      vasl_templates/webapp/data/vasl-6.6.7/expected-multiple-images.json
  19. 2
      vasl_templates/webapp/data/vasl-6.6.7/online-counter-images.json
  20. 71
      vasl_templates/webapp/data/vasl-6.6.7/piece-info.json
  21. 147
      vasl_templates/webapp/data/vasl-6.6.7/vasl-overrides.json
  22. 72
      vasl_templates/webapp/data/vasl-6.6.8/expected-multiple-images.json
  23. 2
      vasl_templates/webapp/data/vasl-6.6.8/online-counter-images.json
  24. 71
      vasl_templates/webapp/data/vasl-6.6.8/piece-info.json
  25. 147
      vasl_templates/webapp/data/vasl-6.6.8/vasl-overrides.json
  26. 6
      vasl_templates/webapp/main.py
  27. 2
      vasl_templates/webapp/scenarios.py
  28. BIN
      vasl_templates/webapp/static/help/images/asl-rulebook2.png
  29. BIN
      vasl_templates/webapp/static/help/images/asl-rulebook2.small.png
  30. 31
      vasl_templates/webapp/static/help/index.html
  31. 2
      vasl_templates/webapp/static/main.js
  32. 83
      vasl_templates/webapp/templates/index.html
  33. 2
      vasl_templates/webapp/tests/control_tests.py
  34. 2
      vasl_templates/webapp/tests/control_tests_servicer.py
  35. 0
      vasl_templates/webapp/tests/fixtures/counters/6.5.0.txt
  36. 0
      vasl_templates/webapp/tests/fixtures/counters/6.5.1.txt
  37. 5
      vasl_templates/webapp/tests/fixtures/counters/6.6.0.txt
  38. 5
      vasl_templates/webapp/tests/fixtures/counters/6.6.1.txt
  39. 5
      vasl_templates/webapp/tests/fixtures/counters/6.6.2.txt
  40. 5
      vasl_templates/webapp/tests/fixtures/counters/6.6.3.txt
  41. 5
      vasl_templates/webapp/tests/fixtures/counters/6.6.4.txt
  42. 5
      vasl_templates/webapp/tests/fixtures/counters/6.6.5.txt
  43. 5
      vasl_templates/webapp/tests/fixtures/counters/6.6.6.txt
  44. 1363
      vasl_templates/webapp/tests/fixtures/counters/6.6.7.txt
  45. 1363
      vasl_templates/webapp/tests/fixtures/counters/6.6.8.txt
  46. 1610
      vasl_templates/webapp/tests/proto/generated/control_tests_pb2.py
  47. 2
      vasl_templates/webapp/tests/proto/set_data_dir_request.py
  48. 2
      vasl_templates/webapp/tests/proto/set_default_template_pack_request.py
  49. 2
      vasl_templates/webapp/tests/proto/set_vasl_version_request.py
  50. 2
      vasl_templates/webapp/tests/proto/set_veh_ord_notes_dir_request.py
  51. 4
      vasl_templates/webapp/tests/test_counters.py
  52. 4
      vasl_templates/webapp/tests/test_national_capabilities.py
  53. 5
      vasl_templates/webapp/tests/test_scenario_search.py
  54. 2
      vasl_templates/webapp/tests/test_vasl_extensions.py
  55. 38
      vasl_templates/webapp/tests/test_vassal.py
  56. 9
      vasl_templates/webapp/tests/utils.py
  57. 6
      vasl_templates/webapp/vasl_mod.py
  58. 12
      vasl_templates/webapp/vassal.py
  59. 14
      vasl_templates/webapp/webdriver.py
  60. BIN
      vassal-shim/release/vassal-shim.jar
  61. 8
      vassal-shim/src/vassal_shim/VassalShim.java

@ -480,4 +480,4 @@ known-third-party=enchant
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception
overgeneral-exceptions=builtins.Exception

@ -1,28 +1,28 @@
# NOTE: Use the run-container.sh script to build and launch this container.
# NOTE: Multi-stage builds require Docker >= 17.05.
FROM rockylinux:8.5 AS base
FROM rockylinux:9.1 AS base
# update packages and install requirements
RUN dnf -y upgrade-minimal && \
dnf install -y python39
dnf install -y python3.11
# NOTE: We don't need the following stuff for the build step, but it's nice to not have to re-install
# it all every time we change the requirements :-/
# install Java
ARG JAVA_URL=https://download.oracle.com/java/17/archive/jdk-17.0.2_linux-x64_bin.tar.gz
RUN curl -s "$JAVA_URL" | tar -xz -C /usr/bin/
RUN dnf install -y java-17-openjdk
# install Firefox
ARG FIREFOX_URL=https://ftp.mozilla.org/pub/firefox/releases/94.0.2/linux-x86_64/en-US/firefox-94.0.2.tar.bz2
# NOTE: We could install this using dnf, but the version of geckodriver needs to match it.
ARG FIREFOX_URL=https://ftp.mozilla.org/pub/firefox/releases/117.0.1/linux-x86_64/en-US/firefox-117.0.1.tar.bz2
RUN dnf install -y bzip2 xorg-x11-server-Xvfb gtk3 dbus-glib && \
curl -s "$FIREFOX_URL" | tar -jx -C /usr/local/ && \
ln -s /usr/local/firefox/firefox /usr/bin/firefox && \
echo "exclude=firefox" >>/etc/dnf/dnf.conf
# install geckodriver
ARG GECKODRIVER_URL=https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux64.tar.gz
ARG GECKODRIVER_URL=https://github.com/mozilla/geckodriver/releases/download/v0.33.0/geckodriver-v0.33.0-linux64.tar.gz
RUN curl -sL "$GECKODRIVER_URL" | tar -xz -C /usr/bin/
# clean up
@ -33,7 +33,7 @@ RUN dnf clean all
FROM base AS build
# set up a virtualenv
RUN python3 -m venv /opt/venv
RUN python3.11 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
RUN pip install --upgrade pip

@ -1,6 +1,7 @@
""" pytest support functions. """
import os
import shutil
import threading
import json
import re
@ -10,8 +11,6 @@ import urllib.request
from urllib.error import URLError
import pytest
from flask import url_for
from vasl_templates.webapp import app
from vasl_templates.webapp.tests import utils
from vasl_templates.webapp.tests.control_tests import ControlTests
@ -19,6 +18,7 @@ from vasl_templates.webapp.tests.control_tests import ControlTests
FLASK_WEBAPP_PORT = 5011
_pytest_options = None
_orig_url_for = app.url_for
# ---------------------------------------------------------------------
@ -129,7 +129,9 @@ def _make_webapp():
# NOTE: It's not a bad idea to bypass the clipboard, even when running in a browser,
# to avoid problems if something else uses the clipboard while the tests are running.
kwargs["store_clipboard"] = 1
url = url_for( endpoint, _external=True, **kwargs )
if kwargs.get( "_external" ) is None:
kwargs["_external"] = True
url = _orig_url_for( endpoint, **kwargs )
url = url.replace( "http://localhost", app.base_url )
return url
app.url_for = make_webapp_url
@ -187,9 +189,9 @@ def _make_webapp():
# we won't have even got this far, since it needs to be there to drive the browser.
# NOTE: This will have no effect if we're talking to a remote server, but we can live with that.
if _pytest_options.webdriver == "firefox":
app.config[ "WEBDRIVER_PATH" ] = "geckodriver"
app.config[ "WEBDRIVER_PATH" ] = shutil.which( "geckodriver" )
elif _pytest_options.webdriver == "chrome":
app.config[ "WEBDRIVER_PATH" ] = "chromedriver"
app.config[ "WEBDRIVER_PATH" ] = shutil.which( "chromedriver" )
return app
@ -216,15 +218,18 @@ def webdriver( request ):
# initialize
driver = request.config.getoption( "--webdriver" )
from selenium import webdriver as wb
log_fname = os.path.join( tempfile.gettempdir(), "webdriver-pytest.log" )
if driver == "firefox":
service = wb.firefox.service.Service(
log_output = os.path.join( tempfile.gettempdir(), "webdriver-pytest.log" )
)
options = wb.FirefoxOptions()
options.headless = _pytest_options.headless
service = wb.firefox.service.Service( log_path=log_fname )
if _pytest_options.headless:
options.add_argument( "--headless" )
driver = wb.Firefox( options=options, service=service )
elif driver == "chrome":
options = wb.ChromeOptions()
options.headless = _pytest_options.headless
if _pytest_options.headless:
options.add_argument( "--headless" )
options.add_argument( "--disable-gpu" )
driver = wb.Chrome( options=options )
else:

@ -2,5 +2,4 @@
IS_CONTAINER = 1
JAVA_PATH = /usr/bin/jdk-17.0.2/bin/java
WEBDRIVER_PATH = /usr/bin/geckodriver

@ -6,6 +6,10 @@ export DISPLAY=:10.0
Xvfb :10 -ac 1>/tmp/xvfb.log 2>/tmp/xvfb.err &
# run the webapp server
python3 /app/vasl_templates/webapp/run_server.py \
# IMPORTANT! This script runs as PID 1, which is the only process that will receive signals,
# so we must replace it with the Python webserver process if it is to receive e.g. SIGTERM,
# which we must handle if "docker stop" and scaling down in Kubernetes is to work (otherwise
# things timeout and we get SIGKILL'ed).
exec python3 /app/vasl_templates/webapp/run_server.py \
--addr 0.0.0.0 \
--force-init-delay 30

@ -1,7 +1,7 @@
pytest==7.1.2
grpcio-tools==1.46.3
tabulate==0.8.9
lxml==4.9.0
pylint==2.14.1
pytest-pylint==0.18.0
pyinstaller==5.1
pytest==7.4.2
grpcio-tools==1.58.0
tabulate==0.9.0
lxml==4.9.3
pylint==2.17.5
pytest-pylint==0.19.0
pyinstaller==5.13.2

@ -1,9 +1,10 @@
# python 3.10.7
# python 3.11.4
flask==2.1.2
pyyaml==6.0
pillow==9.1.1
selenium==4.2.0
flask==2.3.3
pyyaml==6.0.1
# NOTE: Pillow 9.5.0 is the last version that provides 32-bit wheels.
pillow==9.5.0
selenium==4.12.0
waitress==2.1.2
appdirs==1.4.4
click==8.1.3
click==8.1.7

@ -28,7 +28,7 @@ def parse_requirements( fname ):
setup(
name = "vasl_templates",
version = "1.11", # nb: also update constants.py
version = "1.13", # nb: also update constants.py
description = "Create HTML snippets for use in VASL.",
license = "AGPLv3",
url = "https://code.pacman-ghost.com/public/vasl-templates",

@ -11,7 +11,7 @@ from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QDesktopServices, QIcon, QCursor
from PyQt5.QtWidgets import QDialog
from vasl_templates.webapp.config.constants import APP_NAME, APP_VERSION, APP_HOME_URL, IS_FROZEN
from vasl_templates.webapp.config.constants import APP_NAME, APP_VERSION, APP_HOME_URL, APP_ISSUES_URL, IS_FROZEN
from vasl_templates.utils import get_build_info
# ---------------------------------------------------------------------
@ -60,6 +60,9 @@ class AboutDialog( QDialog ):
self.home_url.setText( "Visit us at <a href='{}'>{}</a>.".format(
APP_HOME_URL, mo.group(1) if mo else APP_HOME_URL
) )
self.issues_url.setText( "Report a bug, request a feature, ask a question <a href='{}'>here</a>.".format(
APP_ISSUES_URL
) )
def on_app_icon_clicked( self, event ): #pylint: disable=unused-argument
"""Click handler."""

@ -243,6 +243,9 @@ def _do_main( template_pack, default_scenario, remote_debugging, debug ): #pylin
if is_windows():
QApplication.setStyle( "windowsvista" )
# disable the context help button in the title bar (Windows only)
QApplication.setAttribute( PyQt5.QtCore.Qt.AA_DisableWindowContextHelpButton )
# check if we should disable the embedded browser
disable_browser = webapp.config.get( "DISABLE_WEBENGINEVIEW" )

@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>460</width>
<height>195</height>
<height>215</height>
</rect>
</property>
<property name="windowTitle">
@ -88,7 +88,7 @@
<property name="geometry">
<rect>
<x>19</x>
<y>152</y>
<y>172</y>
<width>425</width>
<height>31</height>
</rect>
@ -147,6 +147,28 @@
<bool>true</bool>
</property>
</widget>
<widget class="QLabel" name="issues_url">
<property name="geometry">
<rect>
<x>80</x>
<y>142</y>
<width>361</width>
<height>21</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>*** ISSUES URL ***</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
<widget class="QLabel" name="license">
<property name="geometry">
<rect>

@ -129,8 +129,8 @@ def _is_flask_child_process():
# ---------------------------------------------------------------------
def _on_sigint( signum, stack ): #pylint: disable=unused-argument
"""Clean up after a SIGINT."""
def _on_sig( signum, stack ): #pylint: disable=unused-argument
"""Clean up after a SIGINT/SIGTERM."""
# FUDGE! Since we added gRPC test control, we want to shutdown properly and clean things up (e.g. temp files
# created by the gRPC service), but the Flask reloader complicates what we have to do here horribly :-(
@ -230,6 +230,7 @@ _set_config_from_env( "VASL_EXTNS_DIR" )
_set_config_from_env( "BOARDS_DIR" )
_set_config_from_env( "CHAPTER_H_NOTES_DIR" )
_set_config_from_env( "USER_FILES_DIR" )
_set_config_from_env( "ASL_RULEBOOK2_BASE_URL" )
# NOTE: The Docker container also sets DEFAULT_TEMPLATE_PACK, but we read it directly from
# the environment variable, since it is not something that is stored in app.config.
@ -257,7 +258,10 @@ import vasl_templates.webapp.downloads #pylint: disable=cyclic-import
import vasl_templates.webapp.lfa #pylint: disable=cyclic-import
# install our signal handler (must be done in the main thread)
signal.signal( signal.SIGINT, _on_sigint )
signal.signal( signal.SIGINT, _on_sig )
# NOTE: We must handle SIGTERM, so that "docker stop" and scaling down in Kubernetes
# work properly (otherwise it times out and we get SIGKILL'ed :-/).
signal.signal( signal.SIGTERM, _on_sig )
# register startup initialization
app.before_request( _on_request )

@ -4,9 +4,10 @@ import sys
import os
APP_NAME = "VASL Templates"
APP_VERSION = "v1.11" # nb: also update setup.py
APP_VERSION = "v1.13" # nb: also update setup.py
APP_DESCRIPTION = "Generate HTML for use in VASL scenarios."
APP_HOME_URL = "https://vasl-templates.org"
APP_ISSUES_URL = "https://code.pacman-ghost.com/public/vasl-templates/issues"
if getattr( sys, "frozen", False ):
IS_FROZEN = True

@ -2,7 +2,7 @@
; configure VASSAL and VASL
VASSAL_DIR = ...configure the VASSAL installation directory...
VASL_MOD = ...configure the VASL module (e.g. vasl-6.6.6.vmod)...
VASL_MOD = ...configure the VASL module (e.g. vasl-6.6.7.vmod)...
VASL_EXTNS_DIR = ...configure the VASL extensions directory...
BOARDS_DIR = ...configure the VASL boards directory...

@ -306,7 +306,8 @@
},
"kfw-rok": {
"th_color": "{! -08/1950 = Red | 09/1950-04/1951 = Red (ROK) ; Black (KMC) | 05/1951- = Black | ??? !}",
"_comment_": "Errata (ASLJ 13 p48): KMC: '9/50+ black' s.b. '8/50+ black",
"th_color": "{! -07/1950 = Red | 08/1950-04/1951 = Red (ROK) ; Black (KMC) | 05/1951- = Black | ??? !}",
"oba": [ "{! 06/1950- = 10B | ??? !}", "3R",
"{? 09/1950- | Plentiful Ammo included | Plentiful Ammo included (KMC) | Plentiful Ammo included (ROK: 9/50+) ?}",
"{! 06/1950-08/1950 = ROK: 6B/3R !}"

@ -5,7 +5,7 @@
"note_number": "1",
"notes": [ "A", "B", "C\u2020", "E" ],
"id": "fr/o:000",
"gpid": 1636
"gpid": 12830
},
{ "name": "Mortier de 60 mle 35",
"type": "MTR",
@ -13,7 +13,7 @@
"note_number": "2\u2020",
"notes": [ "A", "B", "V" ],
"id": "fr/o:001",
"gpid": 1641
"gpid": 1633
},
{ "name": "Mortier de 81 mle 27/31",
"type": "MTR",
@ -22,7 +22,7 @@
"note_number": "3\u2020",
"notes": [ "A", "B", "D", "V" ],
"id": "fr/o:002",
"gpid": 1667
"gpid": [ 1665, 1667 ]
},
{ "name": "Fusil Antichar Boys",
"type": "ATR",

@ -16,9 +16,9 @@
"11359": {"is_small": true},
"3b5:11259": {"is_small": true},
"1632": {"is_small": true},
"1636": {"is_small": true},
"1641": {"is_small": true},
"1633": {"is_small": true},
"1648": {"is_small": true},
"12830": {"is_small": true},
"1982": {"is_small": true},
"1983": {"is_small": true},
"1984": {"is_small": true},

@ -0,0 +1,72 @@
{
"1555": {
"name": "2pdr Portee",
"front_images": [ "br/vehicles/portee.gif", "br/vehicles/portee0.gif" ],
"back_images": null
},
"2212": {
"name": "76* INF FRC",
"front_images": [ "al/gun/alINF76.gif", "al/gun/alINF76u.gif" ],
"back_images": "al/gun/alINF76b.gif"
},
"2698": {
"name": "SPW 251/10",
"front_images": "ge/veh/spw25110.gif",
"back_images": [ "No_ATR.gif", "No_PSK.gif" ]
},
"6765": {
"name": "81* MTR Krh/32",
"front_images": "fi/gun/fi81mmMTR.png",
"back_images": [ "fi/gun/fi81mmMTR.png", "fi/gun/fi81mmMTRB.png" ]
},
"6782": {
"name": "81* MTR Savu M42",
"front_images": [ "fi/gun/fi81mmMTR SavuB.png", "fi/gun/fi81mmMTR Savu.png" ],
"back_images": "fi/gun/fi81mmMTR SavuB.png"
},
"6797": {
"name": "20L (4) AA (g)",
"front_images": [ "fi/gun/fi20L4.png", "fi/gun/fi20L4L.png" ]
},
"6801": {
"name": "20L (6) AA (g)",
"front_images": "fi/gun/fi20L6.png",
"back_images": [ "fi/gun/fi20L6.png", "fi/gun/fi20L6L.png" ]
},
"7409": {
"name": "76 ItK/28 B(s)",
"front_images": "fi/gun/fiAA76L.png",
"back_images": [ "fi/gun/fiAA76L.png", "fi/gun/fiAA76LB.png" ]
},
"adf:1828": {
"name": "105 ART wz.29",
"front_images": "po/gun/poARTwz29-BFP.png",
"back_images": [ "po/gun/poARTwz29-BFP.png", "po/gun/poARTwz29-BFPb.png" ]
},
"adf:1829": {
"name": "120* ART wz09.31",
"front_images": "po/gun/poARTwz0931-BFP.png",
"back_images": [ "po/gun/poARTwz0931-BFP.png", "po/gun/poARTwz0931-BFPb.png" ]
},
"adf:1830": {
"name": "155 ART wz.17",
"front_images": "po/gun/poARTwz17-BFP.png",
"back_images": [ "po/gun/poARTwz17-BFP.png", "po/gun/poARTwz17-BFPb.png" ]
},
"3b5:3676": {
"name": "M19A1 MGMC",
"front_images": [ "us/veh/usM19A1MGMC(trailer)KFW.png", "us/veh/usM19A1MGMC(KFW).png" ],
"back_images": null
}
}

@ -0,0 +1,71 @@
{
"6996": {"is_small": true},
"485": {"is_small": true},
"850": {"is_small": true},
"849": {"is_small": true},
"12689": {"is_small": true},
"856": {"is_small": true},
"857": {"is_small": true},
"11336": {"is_small": true},
"858": {"is_small": true},
"11337": {"is_small": true},
"1149": {"is_small": true},
"1153": {"is_small": true},
"12687": {"is_small": true},
"3b5:7613": {"is_small": true},
"11359": {"is_small": true},
"3b5:11259": {"is_small": true},
"1632": {"is_small": true},
"1633": {"is_small": true},
"1648": {"is_small": true},
"12830": {"is_small": true},
"1982": {"is_small": true},
"1983": {"is_small": true},
"1984": {"is_small": true},
"1985": {"is_small": true},
"1986": {"is_small": true},
"1987": {"is_small": true},
"1988": {"is_small": true},
"2172": {"is_small": true},
"2173": {"is_small": true},
"2176": {"is_small": true},
"2179": {"is_small": true},
"11391": {"is_small": true},
"11392": {"is_small": true},
"11395": {"is_small": true},
"11396": {"is_small": true},
"11440": {"is_small": true},
"3b5:8401": {"is_small": true},
"3b5:8402": {"is_small": true},
"2465": {"is_small": true},
"2474": {"is_small": true},
"3252": {"is_small": true},
"3253": {"is_small": true},
"3263": {"is_small": true},
"3422": {"is_small": true},
"3428": {"is_small": true},
"6730": {"is_small": true},
"3605": {"is_small": true},
"3608": {"is_small": true},
"6763": {"is_small": true},
"3679": {"is_small": true},
"3680": {"is_small": true},
"3681": {"is_small": true},
"3682": {"is_small": true},
"3691": {"is_small": true},
"3692": {"is_small": true},
"3959": {"is_small": true},
"11558": {"is_small": true},
"11559": {"is_small": true},
"3b5:10150": {"is_small": true},
"3b5:10151": {"is_small": true},
"11600": {"is_small": true},
"11604": {"is_small": true},
"3b5:7871": {"is_small": true},
"adf:1948": {"is_small": true},
"adf:75": {"is_small": true},
"adf:77": {"is_small": true},
"adf:76": {"is_small": true},
"adf:1407": {"is_small": true},
"08d:75": {"is_small": true}
}

@ -0,0 +1,147 @@
{
"2474": {
"expected": {
"name": "Goliath",
"front_images": [ "ge/gegol.gif", "ge/gegolb.gif" ],
"back_images": null
},
"updated": {
"front_images": "ge/gegol.gif"
}
},
"1555": {
"expected": {
"name": "2pdr Portee",
"front_images": "br/vehicles/portee.gif",
"back_images": [ "br/vehicles/portee.gif", "br/vehicles/portee0.gif" ]
},
"updated": {
"front_images": [ "br/vehicles/portee.gif", "br/vehicles/portee0.gif" ],
"back_images": null
}
},
"3463": {
"expected": {
"name": "75L AA 75/46",
"front_images": [ "it/gun/itAA7546.gif", "it/gun/itAA7546b.gif" ],
"back_images": [ "it/gun/itAA7546b.gif", "it/gun/itAA7546lb.gif" ]
},
"updated": {
"front_images": "it/gun/itAA7546.gif",
"back_images": "it/gun/itAA7546b.gif"
}
},
"3776": {
"expected": {
"name": "37* INF Skoda IG",
"front_images": [ "ax/gun/buIN37s.gif", "ax/gun/buIN37s2.gif" ],
"back_images": "ax/gun/buIN37sb.gif"
},
"updated": {
"front_images": "ax/gun/buIN37s.gif"
}
},
"3777": {
"expected": {
"name": "70* INF Skoda IG",
"front_images": [ "ax/gun/buIN37s.gif", "ax/gun/buIN37s2.gif" ],
"back_images": "ax/gun/buIN37sb.gif"
},
"updated": {
"front_images": "ax/gun/buIN37s2.gif"
}
},
"6802": {
"expected": {
"name": "20L (4) AA",
"front_images": [ "fi/gun/fi20L4 _2.png", "fi/gun/fi20L4 _2 LIM.png" ],
"back_images": null
},
"updated": {
"front_images": "fi/gun/fi20L4 _2.png"
}
},
"6803": {
"expected": {
"name": "20L VKT (12) AA",
"front_images": [ "fi/gun/fi20L12.png", "fi/gun/fi20L12L.png" ],
"back_images": null
},
"updated": {
"front_images": "fi/gun/fi20L12.png"
}
},
"6804": {
"expected": {
"name": "40L Bofors AA (s)",
"front_images": [ "fi/gun/fi40L.png", "fi/gun/fi40LL.png" ],
"back_images": null
},
"updated": {
"front_images": "fi/gun/fi40L.png"
}
},
"adf:1824": {
"expected": {
"name": "37L AT PTP obr. 30",
"front_images": "ru/gun/ruAT37L.gif",
"back_images": "ru/gun/ruAT37Lb.gif"
},
"updated": {
"front_images": "ru/gun/ru37LPTPobr30.png"
}
},
"adf:1822": {
"expected": {
"name": "37* INF PP obr. 15R",
"front_images": "ru/gun/ruINF37s.gif",
"back_images": "ru/gun/ruINF37sb.gif"
},
"updated": {
"front_images": "ru/gun/ru37PPobr15R.png"
}
},
"adf:1823": {
"expected": {
"name": "76* INF PP obr. 27",
"front_images": "ru/gun/ruINF76s.gif",
"back_images": "ru/gun/ruINF76sb.gif"
},
"updated": {
"front_images": "ru/gun/ru76PPobr27.png"
}
},
"3b5:10093": {
"expected": {
"name": "SL truck",
"front_images": [ "sh/SL3b(KFW).png", "sh/SL4b(KFW).png", "sh/SL5b(KFW).png", "sh/SL6b(KFW).png", "sh/SL1b(KFW).png", "sh/SL2b(KFW).png" ],
"back_images": [ "sh/SL3(KFW).png", "sh/SL4(KFW).png", "sh/SL5(KFW).png", "sh/SL6(KFW).png", "sh/SL1(KFW).png", "sh/SL2(KFW).png" ]
},
"updated": {
"front_images": "us/veh/usSearchlight(KFW).png",
"back_images": null
}
},
"08d:75": {
"expected": {
"name": "RCL 75*",
"front_images": "amrcl75-malf.png",
"back_images": "dm-75rcl.gif"
},
"updated": {
"front_images": "amrcl75.png"
}
}
}

@ -0,0 +1,72 @@
{
"1555": {
"name": "2pdr Portee",
"front_images": [ "br/vehicles/portee.gif", "br/vehicles/portee0.gif" ],
"back_images": null
},
"2212": {
"name": "76* INF FRC",
"front_images": [ "al/gun/alINF76.gif", "al/gun/alINF76u.gif" ],
"back_images": "al/gun/alINF76b.gif"
},
"2698": {
"name": "SPW 251/10",
"front_images": "ge/veh/spw25110.gif",
"back_images": [ "No_ATR.gif", "No_PSK.gif" ]
},
"6765": {
"name": "81* MTR Krh/32",
"front_images": "fi/gun/fi81mmMTR.png",
"back_images": [ "fi/gun/fi81mmMTR.png", "fi/gun/fi81mmMTRB.png" ]
},
"6782": {
"name": "81* MTR Savu M42",
"front_images": [ "fi/gun/fi81mmMTR SavuB.png", "fi/gun/fi81mmMTR Savu.png" ],
"back_images": "fi/gun/fi81mmMTR SavuB.png"
},
"6797": {
"name": "20L (4) AA (g)",
"front_images": [ "fi/gun/fi20L4.png", "fi/gun/fi20L4L.png" ]
},
"6801": {
"name": "20L (6) AA (g)",
"front_images": "fi/gun/fi20L6.png",
"back_images": [ "fi/gun/fi20L6.png", "fi/gun/fi20L6L.png" ]
},
"7409": {
"name": "76 ItK/28 B(s)",
"front_images": "fi/gun/fiAA76L.png",
"back_images": [ "fi/gun/fiAA76L.png", "fi/gun/fiAA76LB.png" ]
},
"adf:1828": {
"name": "105 ART wz.29",
"front_images": "po/gun/poARTwz29-BFP.png",
"back_images": [ "po/gun/poARTwz29-BFP.png", "po/gun/poARTwz29-BFPb.png" ]
},
"adf:1829": {
"name": "120* ART wz09.31",
"front_images": "po/gun/poARTwz0931-BFP.png",
"back_images": [ "po/gun/poARTwz0931-BFP.png", "po/gun/poARTwz0931-BFPb.png" ]
},
"adf:1830": {
"name": "155 ART wz.17",
"front_images": "po/gun/poARTwz17-BFP.png",
"back_images": [ "po/gun/poARTwz17-BFP.png", "po/gun/poARTwz17-BFPb.png" ]
},
"3b5:3676": {
"name": "M19A1 MGMC",
"front_images": [ "us/veh/usM19A1MGMC(trailer)KFW.png", "us/veh/usM19A1MGMC(KFW).png" ],
"back_images": null
}
}

@ -0,0 +1,71 @@
{
"6996": {"is_small": true},
"485": {"is_small": true},
"850": {"is_small": true},
"849": {"is_small": true},
"12689": {"is_small": true},
"856": {"is_small": true},
"857": {"is_small": true},
"11336": {"is_small": true},
"858": {"is_small": true},
"11337": {"is_small": true},
"1149": {"is_small": true},
"1153": {"is_small": true},
"12687": {"is_small": true},
"3b5:7613": {"is_small": true},
"11359": {"is_small": true},
"3b5:11259": {"is_small": true},
"1632": {"is_small": true},
"1633": {"is_small": true},
"1648": {"is_small": true},
"12830": {"is_small": true},
"1982": {"is_small": true},
"1983": {"is_small": true},
"1984": {"is_small": true},
"1985": {"is_small": true},
"1986": {"is_small": true},
"1987": {"is_small": true},
"1988": {"is_small": true},
"2172": {"is_small": true},
"2173": {"is_small": true},
"2176": {"is_small": true},
"2179": {"is_small": true},
"11391": {"is_small": true},
"11392": {"is_small": true},
"11395": {"is_small": true},
"11396": {"is_small": true},
"11440": {"is_small": true},
"3b5:8401": {"is_small": true},
"3b5:8402": {"is_small": true},
"2465": {"is_small": true},
"2474": {"is_small": true},
"3252": {"is_small": true},
"3253": {"is_small": true},
"3263": {"is_small": true},
"3422": {"is_small": true},
"3428": {"is_small": true},
"6730": {"is_small": true},
"3605": {"is_small": true},
"3608": {"is_small": true},
"6763": {"is_small": true},
"3679": {"is_small": true},
"3680": {"is_small": true},
"3681": {"is_small": true},
"3682": {"is_small": true},
"3691": {"is_small": true},
"3692": {"is_small": true},
"3959": {"is_small": true},
"11558": {"is_small": true},
"11559": {"is_small": true},
"3b5:10150": {"is_small": true},
"3b5:10151": {"is_small": true},
"11600": {"is_small": true},
"11604": {"is_small": true},
"3b5:7871": {"is_small": true},
"adf:1948": {"is_small": true},
"adf:75": {"is_small": true},
"adf:77": {"is_small": true},
"adf:76": {"is_small": true},
"adf:1407": {"is_small": true},
"08d:75": {"is_small": true}
}

@ -0,0 +1,147 @@
{
"2474": {
"expected": {
"name": "Goliath",
"front_images": [ "ge/gegol.gif", "ge/gegolb.gif" ],
"back_images": null
},
"updated": {
"front_images": "ge/gegol.gif"
}
},
"1555": {
"expected": {
"name": "2pdr Portee",
"front_images": "br/vehicles/portee.gif",
"back_images": [ "br/vehicles/portee.gif", "br/vehicles/portee0.gif" ]
},
"updated": {
"front_images": [ "br/vehicles/portee.gif", "br/vehicles/portee0.gif" ],
"back_images": null
}
},
"3463": {
"expected": {
"name": "75L AA 75/46",
"front_images": [ "it/gun/itAA7546.gif", "it/gun/itAA7546b.gif" ],
"back_images": [ "it/gun/itAA7546b.gif", "it/gun/itAA7546lb.gif" ]
},
"updated": {
"front_images": "it/gun/itAA7546.gif",
"back_images": "it/gun/itAA7546b.gif"
}
},
"3776": {
"expected": {
"name": "37* INF Skoda IG",
"front_images": [ "ax/gun/buIN37s.gif", "ax/gun/buIN37s2.gif" ],
"back_images": "ax/gun/buIN37sb.gif"
},
"updated": {
"front_images": "ax/gun/buIN37s.gif"
}
},
"3777": {
"expected": {
"name": "70* INF Skoda IG",
"front_images": [ "ax/gun/buIN37s.gif", "ax/gun/buIN37s2.gif" ],
"back_images": "ax/gun/buIN37sb.gif"
},
"updated": {
"front_images": "ax/gun/buIN37s2.gif"
}
},
"6802": {
"expected": {
"name": "20L (4) AA",
"front_images": [ "fi/gun/fi20L4 _2.png", "fi/gun/fi20L4 _2 LIM.png" ],
"back_images": null
},
"updated": {
"front_images": "fi/gun/fi20L4 _2.png"
}
},
"6803": {
"expected": {
"name": "20L VKT (12) AA",
"front_images": [ "fi/gun/fi20L12.png", "fi/gun/fi20L12L.png" ],
"back_images": null
},
"updated": {
"front_images": "fi/gun/fi20L12.png"
}
},
"6804": {
"expected": {
"name": "40L Bofors AA (s)",
"front_images": [ "fi/gun/fi40L.png", "fi/gun/fi40LL.png" ],
"back_images": null
},
"updated": {
"front_images": "fi/gun/fi40L.png"
}
},
"adf:1824": {
"expected": {
"name": "37L AT PTP obr. 30",
"front_images": "ru/gun/ruAT37L.gif",
"back_images": "ru/gun/ruAT37Lb.gif"
},
"updated": {
"front_images": "ru/gun/ru37LPTPobr30.png"
}
},
"adf:1822": {
"expected": {
"name": "37* INF PP obr. 15R",
"front_images": "ru/gun/ruINF37s.gif",
"back_images": "ru/gun/ruINF37sb.gif"
},
"updated": {
"front_images": "ru/gun/ru37PPobr15R.png"
}
},
"adf:1823": {
"expected": {
"name": "76* INF PP obr. 27",
"front_images": "ru/gun/ruINF76s.gif",
"back_images": "ru/gun/ruINF76sb.gif"
},
"updated": {
"front_images": "ru/gun/ru76PPobr27.png"
}
},
"3b5:10093": {
"expected": {
"name": "SL truck",
"front_images": [ "sh/SL3b(KFW).png", "sh/SL4b(KFW).png", "sh/SL5b(KFW).png", "sh/SL6b(KFW).png", "sh/SL1b(KFW).png", "sh/SL2b(KFW).png" ],
"back_images": [ "sh/SL3(KFW).png", "sh/SL4(KFW).png", "sh/SL5(KFW).png", "sh/SL6(KFW).png", "sh/SL1(KFW).png", "sh/SL2(KFW).png" ]
},
"updated": {
"front_images": "us/veh/usSearchlight(KFW).png",
"back_images": null
}
},
"08d:75": {
"expected": {
"name": "RCL 75*",
"front_images": "amrcl75-malf.png",
"back_images": "dm-75rcl.gif"
},
"updated": {
"front_images": "amrcl75.png"
}
}
}

@ -235,9 +235,13 @@ def get_program_info():
return tstamp + timedelta( minutes=tz_offset )
# set the basic details
try:
vassal_version = VassalShim.get_version()
except Exception: #pylint: disable=broad-except
vassal_version = "???"
params = {
"APP_VERSION": vasl_templates.webapp.config.constants.APP_VERSION,
"VASSAL_VERSION": VassalShim.get_version()
"VASSAL_VERSION": vassal_version
}
build_git_info = get_build_git_info()
if build_git_info:

@ -539,7 +539,7 @@ def prepare_asa_upload(): #pylint: disable=too-many-locals
max_size = parse_int( app.config.get( "ASA_MAX_SCREENSHOT_SIZE" ), 200 ) * 1024
if len(screenshot_data) > max_size:
ratio = math.sqrt( float(max_size) / len(screenshot_data) )
img = img.resize( ( int(img.width * ratio), int(img.height * ratio) ), Image.ANTIALIAS )
img = img.resize( ( int(img.width * ratio), int(img.height * ratio) ), Image.LANCZOS )
# add a border
border_size = parse_int( app.config.get( "ASA_SCREENSHOT_BORDER_SIZE" ), 5 )
img = ImageOps.expand( img, border_size, (255,255,255,255) )

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -54,8 +54,8 @@ If you have Docker installed, the webapp can be run in a container e.g.
<div class="code">
./run-container.sh \
--port 5010 \
--vassal ~/vassal-3.6.14/ \
--vasl ~/vasl/vasl-6.6.6.vmod \
--vassal ~/vassal-3.7.9/ \
--vasl ~/vasl/vasl-6.6.8.vmod \
--vasl-extensions ~/vasl/extensions/ \
--boards ~/vasl/boards/ \
--chapter-h ~/vasl/chapter-h/ \
@ -73,7 +73,7 @@ If you have Docker installed, the webapp can be run in a container e.g.
<p> You can also run the program directly from the source code. Get a copy from <a href="https://code.pacman-ghost.com/public/vasl-templates">here</a> in the usual way, by <tt>git clone</tt>'ing it, or downloading a ZIP and unpacking it somewhere.
<p> The web server was written and tested using Python 3.10.7, but it doesn't do anything particularly funky, so any recent version of Python <em>should</em> work.
<p> The web server was written and tested using Python 3.11.4, but it doesn't do anything particularly funky, so any recent version of Python <em>should</em> work.
<p> While not essential, it is <em>strongly</em> recommended that you set up a <a href="https://virtualenv.pypa.io/en/stable/">virtual environment</a> first. Then <tt>cd</tt> into the project's root directory, and install the requirements (note the trailing period):
<div class="code">
@ -101,6 +101,18 @@ pip install --editable .[gui]
<p> Then, run the <tt>vasl-templates</tt> command.
<a name="asl-rulebook2"></a>
<h2> Integrating with <tt>asl-rulebook2</tt></h2>
<p> <img src="images/asl-rulebook2.png" class="preview" style="float:right;">
If you are using <a href="https://code.pacman-ghost.com/public/asl-rulebook2"><tt>asl-rulebook2</tt></a>, you can connect it to this program, and vehicle/ordnance entries will show an icon that you can click to open their Chapter H entries.
<p> In your <tt>site.cfg</tt>, configure the base URL of the <tt>asl-rulebook2</tt> application e.g.
<div class="code">
[Site Config]
ASL_RULEBOOK2_BASE_URL = http://localhost:5020
</div>
<a name="install-webdriver"></a>
<h2>Installing a webdriver</h2>
@ -154,11 +166,11 @@ Configuring the program
<p> Choose <em>Settings</em> from the <em>File</em> menu and configure the highlighted settings. As a guide, here are some example settings:
<table class="settings">
<tr> <td class="key"> VASSAL&nbsp;installation: </td> <td class="val"> <nobr>C:\Program Files\VASSAL-3.6.14\</nobr>
<tr> <td class="key"> VASL&nbsp;module: </td> <td class="val"> <nobr>C:\bin\vasl\vasl-6.6.6.vmod</nobr>
<tr> <td class="key"> VASSAL&nbsp;installation: </td> <td class="val"> <nobr>C:\Program Files\VASSAL-3.7.9\</nobr>
<tr> <td class="key"> VASL&nbsp;module: </td> <td class="val"> <nobr>C:\bin\vasl\vasl-6.6.8.vmod</nobr>
<tr> <td class="key"> VASL&nbsp;extensions: </td> <td class="val"> <nobr>C:\bin\vasl\extensions\</nobr>
<tr> <td class="key"> VASL&nbsp;boards: </td> <td class="val"> <nobr>C:\bin\vasl\boards\</nobr>
<tr> <td class="key" valign="top"> Java: </td> <td class="val"> <nobr>C:\Program Files\VASSAL-3.6.14\jre\bin\java.exe</nobr>
<tr> <td class="key" valign="top"> Java: </td> <td class="val"> <nobr>C:\Program Files\VASSAL-3.7.9\jre\bin\java.exe</nobr>
<div class="hint" style="margin:0.5em 1em;"> Leave this field blank to use the Java that comes with VASSAL (Windows only), or on your PATH. </div>
<tr> <td class="key"> Web&nbsp;driver: </td> <td class="val"> <nobr>C:\bin\geckodriver.exe</nobr>
</table>
@ -548,6 +560,13 @@ When you're writing a new template file, it would be painful to have to ZIP up a
<a name="dev-setup"></a>
<h2 style="margin-top:0;"> Setting up </h2>
<div class="info" style="float:right;max-width:40%;margin-left:1em;">
If you want to run the GUI, you will also need to install the GUI requirements:
<div class="code">
pip install --editable .[gui]
</div>
</div>
<p> After cloning the repo, install the <em>developer</em> requirements:
<div class="code">
pip install --editable .[dev]

@ -77,8 +77,6 @@ $(document).ready( function () {
program_info: { label: "Program info", icon: imagesDir+"/info.png", action: show_program_info },
show_help: { label: "Help", icon: imagesDir+"/help.png", action: show_help },
} ;
if ( getUrlParam( "pyqt" ) )
delete menuItems.program_info ;
$menu.popmenu( menuItems ) ;
// nb: we only show the popmenu on left click (not the normal right-click)
$menu.off( "contextmenu" ) ;

@ -141,34 +141,66 @@
<script src="{{url_for('static',filename='trumbowyg/plugins/table/trumbowyg.table.min.js')}}"></script>
<script src="{{url_for('static',filename='DOMPurify/purify.min.js')}}"></script>
<script src="{{url_for('static',filename='utils.js')}}"></script>
<script>
function removeUrlTestParams( url )
{
// remove any URL parameters
// NOTE: We can't use URL.searchParams since we might be passed a relative URL.
// FUDGE! The test suite is giving us absolute, encoded URL's :-/
url = strReplaceAll( url, "&amp;", "&" ) ;
var match = url.match( new RegExp( "^http://.+?:\\d+?/" ) ) ;
if ( match )
url = url.substring( match[0].length - 1 ) ;
var pos = url.indexOf( "?" ) ;
if ( pos >= 0 ) {
params = url.substring( pos+1 ).split( "&" ) ;
url = url.substring( 0, pos ) ;
var nKeeps = 0 ;
params.forEach( function( param ) {
var keep = true ;
[ "store_msgs", "disable_close_window_check", "store_clipboard" ].forEach( function( key ) {
if ( param.substring( 0, key.length+1 ) === key + "=" )
keep = false ;
} ) ;
if ( keep ) {
url += ( nKeeps === 0 ) ? "?" : "&" ;
url += param ;
nKeeps += 1 ;
}
} ) ;
}
return url ;
}
gAppName = "{{APP_NAME}}" ;
gAppVersion = "{{APP_VERSION}}" ;
gImagesBaseUrl = "{{url_for('static',filename='images')}}" ;
gAppConfigUrl = "{{url_for('get_app_config')}}" ;
gGetStartupMsgsUrl = "{{url_for('get_startup_msgs')}}" ;
gGetTemplatePackUrl = "{{url_for('get_template_pack')}}" ;
gGetAslRulebook2VoNoteTargetsUrl = "{{url_for('get_asl_rulebook2_vo_note_targets')}}" ;
gShowAslRulebook2VoNoteUrl = "{{url_for('show_asl_rulebook2_target',target='TARGET')}}" ;
gGetDefaultScenarioUrl = "{{url_for('get_default_scenario')}}" ;
gVehicleListingsUrl = "{{url_for('get_vehicle_listings',merge_common=1)}}" ;
gOrdnanceListingsUrl = "{{url_for('get_ordnance_listings',merge_common=1)}}" ;
gVehicleNotesUrl = "{{url_for('get_vehicle_notes')}}" ;
gOrdnanceNotesUrl = "{{url_for('get_ordnance_notes')}}" ;
gGetVaslPieceInfoUrl = "{{url_for('get_vasl_piece_info')}}" ;
gGetOnlineCounterImagesUrl = "{{url_for('get_online_counter_images')}}" ;
gGetScenarioIndexUrl = "{{url_for('get_scenario_index')}}" ;
gGetScenarioUrl = "{{url_for('get_scenario',scenario_id='ID')}}" ;
gGetScenarioCardUrl = "{{url_for('get_scenario_card',scenario_id='ID')}}" ;
gGetRoarScenarioIndexUrl = "{{url_for('get_roar_scenario_index')}}" ;
gAnalyzeVsavUrl = "{{url_for('analyze_vsav')}}" ;
gAnalyzeVlogsUrl = "{{url_for('analyze_vlogs')}}" ;
gUpdateVsavUrl = "{{url_for('update_vsav')}}" ;
gPrepareAsaUploadUrl = "{{url_for('prepare_asa_upload')}}" ;
gOnSuccessfulAsaUploadUrl = "{{url_for('on_successful_asa_upload',scenario_id='ID')}}" ;
gMakeSnippetImageUrl = "{{url_for('make_snippet_image')}}" ;
gGetProgramInfoUrl = "{{url_for('get_program_info')}}" ;
gHelpUrl = "{{url_for('show_help')}}" ;
gImagesBaseUrl = removeUrlTestParams( "{{url_for('static',filename='images')}}" ) ;
gAppConfigUrl = removeUrlTestParams( "{{url_for('get_app_config')}}" ) ;
gGetStartupMsgsUrl = removeUrlTestParams( "{{url_for('get_startup_msgs')}}" ) ;
gGetTemplatePackUrl = removeUrlTestParams( "{{url_for('get_template_pack')}}" ) ;
gGetAslRulebook2VoNoteTargetsUrl = removeUrlTestParams( "{{url_for('get_asl_rulebook2_vo_note_targets')}}" ) ;
gShowAslRulebook2VoNoteUrl = removeUrlTestParams( "{{url_for('show_asl_rulebook2_target',target='TARGET')}}" ) ;
gGetDefaultScenarioUrl = removeUrlTestParams( "{{url_for('get_default_scenario')}}" ) ;
gVehicleListingsUrl = removeUrlTestParams( "{{url_for('get_vehicle_listings',merge_common=1)}}" ) ;
gOrdnanceListingsUrl = removeUrlTestParams( "{{url_for('get_ordnance_listings',merge_common=1)}}" ) ;
gVehicleNotesUrl = removeUrlTestParams( "{{url_for('get_vehicle_notes')}}" ) ;
gOrdnanceNotesUrl = removeUrlTestParams( "{{url_for('get_ordnance_notes')}}" ) ;
gGetVaslPieceInfoUrl = removeUrlTestParams( "{{url_for('get_vasl_piece_info')}}" ) ;
gGetOnlineCounterImagesUrl = removeUrlTestParams( "{{url_for('get_online_counter_images')}}" ) ;
gGetScenarioIndexUrl = removeUrlTestParams( "{{url_for('get_scenario_index')}}" ) ;
gGetScenarioUrl = removeUrlTestParams( "{{url_for('get_scenario',scenario_id='ID')}}" ) ;
gGetScenarioCardUrl = removeUrlTestParams( "{{url_for('get_scenario_card',scenario_id='ID')}}" ) ;
gGetRoarScenarioIndexUrl = removeUrlTestParams( "{{url_for('get_roar_scenario_index')}}" ) ;
gAnalyzeVsavUrl = removeUrlTestParams( "{{url_for('analyze_vsav')}}" ) ;
gAnalyzeVlogsUrl = removeUrlTestParams( "{{url_for('analyze_vlogs')}}" ) ;
gUpdateVsavUrl = removeUrlTestParams( "{{url_for('update_vsav')}}" ) ;
gPrepareAsaUploadUrl = removeUrlTestParams( "{{url_for('prepare_asa_upload')}}" ) ;
gOnSuccessfulAsaUploadUrl = removeUrlTestParams( "{{url_for('on_successful_asa_upload',scenario_id='ID')}}" ) ;
gMakeSnippetImageUrl = removeUrlTestParams( "{{url_for('make_snippet_image')}}" ) ;
gGetProgramInfoUrl = removeUrlTestParams( "{{url_for('get_program_info')}}" ) ;
gHelpUrl = removeUrlTestParams( "{{url_for('show_help')}}" ) ;
</script>
<script src="{{url_for('static',filename='main.js')}}"></script>
@ -190,7 +222,6 @@ gHelpUrl = "{{url_for('show_help')}}" ;
<script src="{{url_for('static',filename='user_settings.js')}}"></script>
<script src="{{url_for('static',filename='html-editor.js')}}"></script>
<script src="{{url_for('static',filename='jQueryHandlers.js')}}"></script>
<script src="{{url_for('static',filename='utils.js')}}"></script>
<script src="{{url_for('static',filename='timer.js')}}"></script>
{%include "testing.html"%}

@ -9,6 +9,7 @@ from google.protobuf.empty_pb2 import Empty #pylint: disable=no-name-in-module
from vasl_templates.webapp.tests.proto.generated.control_tests_pb2_grpc import ControlTestsStub
from vasl_templates.webapp.tests.proto.utils import enum_from_string
#pylint: disable=no-name-in-module
from vasl_templates.webapp.tests.proto.generated.control_tests_pb2 import \
SetVassalVersionRequest, SetVaslVersionRequest, SetVaslExtnInfoDirRequest, SetGpidRemappingsRequest, \
SetDataDirRequest, SetDefaultScenarioRequest, SetDefaultTemplatePackRequest, \
@ -17,6 +18,7 @@ from vasl_templates.webapp.tests.proto.generated.control_tests_pb2 import \
DumpVsavRequest, GetVaslPiecesRequest, \
SetAppConfigValRequest, DeleteAppConfigValRequest, \
SaveTempFileRequest
#pylint: enable=no-name-in-module
# ---------------------------------------------------------------------

@ -28,6 +28,7 @@ from vasl_templates.webapp import \
from vasl_templates.webapp.tests.proto.generated.control_tests_pb2_grpc \
import ControlTestsServicer as BaseControlTestsServicer
#pylint: disable=no-name-in-module
from vasl_templates.webapp.tests.proto.generated.control_tests_pb2 import \
SetVassalVersionRequest, SetVaslVersionRequest, SetVaslExtnInfoDirRequest, SetGpidRemappingsRequest, \
SetDataDirRequest, SetDefaultScenarioRequest, SetDefaultTemplatePackRequest, \
@ -39,6 +40,7 @@ from vasl_templates.webapp.tests.proto.generated.control_tests_pb2 import \
GetVassalVersionsResponse, GetVaslVersionsResponse, GetVaslExtnsResponse, GetVaslModWarningsResponse, \
GetLastSnippetImageResponse, GetLastAsaUploadResponse, \
DumpVsavResponse, GetVaslPiecesResponse, GetAppConfigResponse
#pylint: enable=no-name-in-module
# nb: these are defined as a convenience
_VaslExtnsTypes_NONE = SetVaslVersionRequest.VaslExtnsType.NONE #pylint: disable=no-member

@ -412,9 +412,9 @@ GPID Name Front images
1575 2-1/2 ton Truck(a) br/vehicles/ton212.gif
1577 7-1/2 ton Truck(a) br/vehicles/ton712.gif
1632 37* INF fr/frINF.gif fr/frINFb.gif
1636 50 MTR(f) fr/frMTR.gif fr/frMTRb.gif
1641 60* MTR(a) br/brMTRa.gif br/brMTRab.gif
1633 60* MTR fr/frMTR60.gif fr/frMTR60b.gif
1648 ATR fr/frATR.gif fr/frATRb.gif
1665 81* MTR mle 27/31 fr/gun/frMTR81s.gif fr/gun/frMTR81sb.gif
1667 81* MTR(f) mle 27/31 fr/gun/frMTR81sf.gif fr/gun/frMTR81sfb.gif
1669 25LL AT SA-L mle 34 fr/gun/frAT25LL.gif fr/gun/frAT25LLb.gif
1670 47L AT SA mle 37 APX <41 fr/gun/frAT47L-40.gif fr/gun/frAT47Lb.gif
@ -1281,6 +1281,7 @@ GPID Name Front images
12687 OML 2in MTR (KW) br/brMTR.gif br/brMTRb.gif
12689 60* MTR M2 (KW) am/amMTR.gif am/amMTRb.gif
12730 IP Carrier AOV br/vehicles/ipcaov.gif
12830 50 MTR ff/ffMTR50.png ff/ffMTR50b.png
3b5:10093 SL truck us/veh/usSearchlight(KFW).png
3b5:10114 57LL AT PTP obr. 43 cc/gun/ccAT57LL(KFW).png cc/gun/ccAT57LLm(KFW).png
3b5:10115 70* INF Type 92 cc/gun/ccINF70(KFW).png cc/gun/ccINF70m(KFW).png

@ -412,9 +412,9 @@ GPID Name Front images
1575 2-1/2 ton Truck(a) br/vehicles/ton212.gif
1577 7-1/2 ton Truck(a) br/vehicles/ton712.gif
1632 37* INF fr/frINF.gif fr/frINFb.gif
1636 50 MTR(f) fr/frMTR.gif fr/frMTRb.gif
1641 60* MTR(a) br/brMTRa.gif br/brMTRab.gif
1633 60* MTR fr/frMTR60.gif fr/frMTR60b.gif
1648 ATR fr/frATR.gif fr/frATRb.gif
1665 81* MTR mle 27/31 fr/gun/frMTR81s.gif fr/gun/frMTR81sb.gif
1667 81* MTR(f) mle 27/31 fr/gun/frMTR81sf.gif fr/gun/frMTR81sfb.gif
1669 25LL AT SA-L mle 34 fr/gun/frAT25LL.gif fr/gun/frAT25LLb.gif
1670 47L AT SA mle 37 APX <41 fr/gun/frAT47L-40.gif fr/gun/frAT47Lb.gif
@ -1281,6 +1281,7 @@ GPID Name Front images
12687 OML 2in MTR (KW) br/brMTR.gif br/brMTRb.gif
12689 60* MTR M2 (KW) am/amMTR.gif am/amMTRb.gif
12730 IP Carrier AOV br/vehicles/ipcaov.gif
12830 50 MTR ff/ffMTR50.png ff/ffMTR50b.png
3b5:10093 SL truck us/veh/usSearchlight(KFW).png
3b5:10114 57LL AT PTP obr. 43 cc/gun/ccAT57LL(KFW).png cc/gun/ccAT57LLm(KFW).png
3b5:10115 70* INF Type 92 cc/gun/ccINF70(KFW).png cc/gun/ccINF70m(KFW).png

@ -412,9 +412,9 @@ GPID Name Front images
1575 2-1/2 ton Truck(a) br/vehicles/ton212.gif
1577 7-1/2 ton Truck(a) br/vehicles/ton712.gif
1632 37* INF fr/frINF.gif fr/frINFb.gif
1636 50 MTR(f) fr/frMTR.gif fr/frMTRb.gif
1641 60* MTR(a) br/brMTRa.gif br/brMTRab.gif
1633 60* MTR fr/frMTR60.gif fr/frMTR60b.gif
1648 ATR fr/frATR.gif fr/frATRb.gif
1665 81* MTR mle 27/31 fr/gun/frMTR81s.gif fr/gun/frMTR81sb.gif
1667 81* MTR(f) mle 27/31 fr/gun/frMTR81sf.gif fr/gun/frMTR81sfb.gif
1669 25LL AT SA-L mle 34 fr/gun/frAT25LL.gif fr/gun/frAT25LLb.gif
1670 47L AT SA mle 37 APX <41 fr/gun/frAT47L-40.gif fr/gun/frAT47Lb.gif
@ -1281,6 +1281,7 @@ GPID Name Front images
12687 OML 2in MTR (KW) br/brMTR.gif br/brMTRb.gif
12689 60* MTR M2 (KW) am/amMTR.gif am/amMTRb.gif
12730 IP Carrier AOV br/vehicles/ipcaov.gif
12830 50 MTR ff/ffMTR50.png ff/ffMTR50b.png
3b5:10093 SL truck us/veh/usSearchlight(KFW).png
3b5:10114 57LL AT PTP obr. 43 cc/gun/ccAT57LL(KFW).png cc/gun/ccAT57LLm(KFW).png
3b5:10115 70* INF Type 92 cc/gun/ccINF70(KFW).png cc/gun/ccINF70m(KFW).png

@ -412,9 +412,9 @@ GPID Name Front images
1575 2-1/2 ton Truck(a) br/vehicles/ton212.gif
1577 7-1/2 ton Truck(a) br/vehicles/ton712.gif
1632 37* INF fr/frINF.gif fr/frINFb.gif
1636 50 MTR(f) fr/frMTR.gif fr/frMTRb.gif
1641 60* MTR(a) br/brMTRa.gif br/brMTRab.gif
1633 60* MTR fr/frMTR60.gif fr/frMTR60b.gif
1648 ATR fr/frATR.gif fr/frATRb.gif
1665 81* MTR mle 27/31 fr/gun/frMTR81s.gif fr/gun/frMTR81sb.gif
1667 81* MTR(f) mle 27/31 fr/gun/frMTR81sf.gif fr/gun/frMTR81sfb.gif
1669 25LL AT SA-L mle 34 fr/gun/frAT25LL.gif fr/gun/frAT25LLb.gif
1670 47L AT SA mle 37 APX <41 fr/gun/frAT47L-40.gif fr/gun/frAT47Lb.gif
@ -1281,6 +1281,7 @@ GPID Name Front images
12687 OML 2in MTR (KW) br/brMTR.gif br/brMTRb.gif
12689 60* MTR M2 (KW) am/amMTR.gif am/amMTRb.gif
12730 IP Carrier AOV br/vehicles/ipcaov.gif
12830 50 MTR ff/ffMTR50.png ff/ffMTR50b.png
3b5:10093 SL truck us/veh/usSearchlight(KFW).png
3b5:10114 57LL AT PTP obr. 43 cc/gun/ccAT57LL(KFW).png cc/gun/ccAT57LLm(KFW).png
3b5:10115 70* INF Type 92 cc/gun/ccINF70(KFW).png cc/gun/ccINF70m(KFW).png

@ -412,9 +412,9 @@ GPID Name Front images
1575 2-1/2 ton Truck(a) br/vehicles/ton212.gif
1577 7-1/2 ton Truck(a) br/vehicles/ton712.gif
1632 37* INF fr/frINF.gif fr/frINFb.gif
1636 50 MTR(f) fr/frMTR.gif fr/frMTRb.gif
1641 60* MTR(a) br/brMTRa.gif br/brMTRab.gif
1633 60* MTR fr/frMTR60.gif fr/frMTR60b.gif
1648 ATR fr/frATR.gif fr/frATRb.gif
1665 81* MTR mle 27/31 fr/gun/frMTR81s.gif fr/gun/frMTR81sb.gif
1667 81* MTR(f) mle 27/31 fr/gun/frMTR81sf.gif fr/gun/frMTR81sfb.gif
1669 25LL AT SA-L mle 34 fr/gun/frAT25LL.gif fr/gun/frAT25LLb.gif
1670 47L AT SA mle 37 APX <41 fr/gun/frAT47L-40.gif fr/gun/frAT47Lb.gif
@ -1281,6 +1281,7 @@ GPID Name Front images
12687 OML 2in MTR (KW) br/brMTR.gif br/brMTRb.gif
12689 60* MTR M2 (KW) am/amMTR.gif am/amMTRb.gif
12730 IP Carrier AOV br/vehicles/ipcaov.gif
12830 50 MTR ff/ffMTR50.png ff/ffMTR50b.png
13832 81* MTR sv/gun/svMTR81s.gif sv/gun/svMTR81sb.gif
13835 37L AT sv/gun/svAT37L.gif sv/gun/svAT37Lb.gif
13836 84* ART sv/gun/svART84s.gif sv/gun/svART84sb.gif

@ -412,9 +412,9 @@ GPID Name Front images
1575 2-1/2 ton Truck(a) br/vehicles/ton212.gif
1577 7-1/2 ton Truck(a) br/vehicles/ton712.gif
1632 37* INF fr/frINF.gif fr/frINFb.gif
1636 50 MTR(f) fr/frMTR.gif fr/frMTRb.gif
1641 60* MTR(a) br/brMTRa.gif br/brMTRab.gif
1633 60* MTR fr/frMTR60.gif fr/frMTR60b.gif
1648 ATR fr/frATR.gif fr/frATRb.gif
1665 81* MTR mle 27/31 fr/gun/frMTR81s.gif fr/gun/frMTR81sb.gif
1667 81* MTR(f) mle 27/31 fr/gun/frMTR81sf.gif fr/gun/frMTR81sfb.gif
1669 25LL AT SA-L mle 34 fr/gun/frAT25LL.gif fr/gun/frAT25LLb.gif
1670 47L AT SA mle 37 APX <41 fr/gun/frAT47L-40.gif fr/gun/frAT47Lb.gif
@ -1281,6 +1281,7 @@ GPID Name Front images
12687 OML 2in MTR (KW) br/brMTR.gif br/brMTRb.gif
12689 60* MTR M2 (KW) am/amMTR.gif am/amMTRb.gif
12730 IP Carrier AOV br/vehicles/ipcaov.gif
12830 50 MTR ff/ffMTR50.png ff/ffMTR50b.png
13832 81* MTR sv/gun/svMTR81s.gif sv/gun/svMTR81sb.gif
13835 37L AT sv/gun/svAT37L.gif sv/gun/svAT37Lb.gif
13836 84* ART sv/gun/svART84s.gif sv/gun/svART84sb.gif

@ -412,9 +412,9 @@ GPID Name Front images
1575 2-1/2 ton Truck(a) br/vehicles/ton212.gif
1577 7-1/2 ton Truck(a) br/vehicles/ton712.gif
1632 37* INF fr/frINF.gif fr/frINFb.gif
1636 50 MTR(f) fr/frMTR.gif fr/frMTRb.gif
1641 60* MTR(a) br/brMTRa.gif br/brMTRab.gif
1633 60* MTR fr/frMTR60.gif fr/frMTR60b.gif
1648 ATR fr/frATR.gif fr/frATRb.gif
1665 81* MTR mle 27/31 fr/gun/frMTR81s.gif fr/gun/frMTR81sb.gif
1667 81* MTR(f) mle 27/31 fr/gun/frMTR81sf.gif fr/gun/frMTR81sfb.gif
1669 25LL AT SA-L mle 34 fr/gun/frAT25LL.gif fr/gun/frAT25LLb.gif
1670 47L AT SA mle 37 APX <41 fr/gun/frAT47L-40.gif fr/gun/frAT47Lb.gif
@ -1281,6 +1281,7 @@ GPID Name Front images
12687 OML 2in MTR (KW) br/brMTR.gif br/brMTRb.gif
12689 60* MTR M2 (KW) am/amMTR.gif am/amMTRb.gif
12730 IP Carrier AOV br/vehicles/ipcaov.gif
12830 50 MTR ff/ffMTR50.png ff/ffMTR50b.png
13832 81* MTR sv/gun/svMTR81s.gif sv/gun/svMTR81sb.gif
13835 37L AT sv/gun/svAT37L.gif sv/gun/svAT37Lb.gif
13836 84* ART sv/gun/svART84s.gif sv/gun/svART84sb.gif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -1,6 +1,6 @@
""" Injected functions for SetDataDirRequest. """
from .generated.control_tests_pb2 import SetDataDirRequest
from .generated.control_tests_pb2 import SetDataDirRequest #pylint: disable=no-name-in-module
from .utils import enum_to_string
# ---------------------------------------------------------------------

@ -1,6 +1,6 @@
""" Injected functions for SetDefaultTemplatePackRequest. """
from vasl_templates.webapp.tests.proto.generated.control_tests_pb2 import SetDefaultTemplatePackRequest
from vasl_templates.webapp.tests.proto.generated.control_tests_pb2 import SetDefaultTemplatePackRequest #pylint: disable=no-name-in-module
from .utils import enum_to_string
# ---------------------------------------------------------------------

@ -1,6 +1,6 @@
""" Injected functions for SetVaslVersionRequest. """
from vasl_templates.webapp.tests.proto.generated.control_tests_pb2 import SetVaslVersionRequest
from vasl_templates.webapp.tests.proto.generated.control_tests_pb2 import SetVaslVersionRequest #pylint: disable=no-name-in-module
from .utils import enum_to_string
# ---------------------------------------------------------------------

@ -1,6 +1,6 @@
""" Injected functions for SetVehOrdNotesDirRequest. """
from vasl_templates.webapp.tests.proto.generated.control_tests_pb2 import SetVehOrdNotesDirRequest
from vasl_templates.webapp.tests.proto.generated.control_tests_pb2 import SetVehOrdNotesDirRequest #pylint: disable=no-name-in-module
from .utils import enum_to_string
# ---------------------------------------------------------------------

@ -63,7 +63,7 @@ def test_counter_images( webapp, webdriver ): #pylint: disable=too-many-locals
return (code == 200 and data) or (code == 404 and not data)
# initialize
check_dir = os.path.join( os.path.split(__file__)[0], "fixtures" )
check_dir = os.path.join( os.path.split(__file__)[0], "fixtures/counters" )
save_dir = os.environ.get( "COUNTERS_SAVEDIR" ) # nb: define this to save the generated reports
if save_dir:
if os.path.isdir( save_dir ):
@ -87,7 +87,7 @@ def test_counter_images( webapp, webdriver ): #pylint: disable=too-many-locals
init_webapp( webapp, webdriver )
# figure out what we're expecting to see
fname = os.path.join( check_dir, "vasl-pieces-{}.txt".format(
fname = os.path.join( check_dir, "{}.txt".format(
aliases.get( vasl_version, vasl_version )
) )
with open( fname, "r", encoding="utf-8" ) as fp:

@ -328,8 +328,8 @@ def test_time_based_national_capabilities( webapp, webdriver ):
comments = [ "Plentiful Ammo included (KMC)", "ROK: 6B/3R" ]
)
check_oba( "kfw-rok", "Korea", 10, 1950, "10B", "3R", plentiful=True )
check_th_color( "kfw-rok", "Korea", 8, 1950, "Red TH#" )
check_th_color( "kfw-rok", "Korea", 9, 1950, "Red TH# (ROK) ; Black (KMC)" )
check_th_color( "kfw-rok", "Korea", 7, 1950, "Red TH#" )
check_th_color( "kfw-rok", "Korea", 8, 1950, "Red TH# (ROK) ; Black (KMC)" )
check_th_color( "kfw-rok", "Korea", 5, 1951, "Black TH#" )
# test the CPVA national Capabilities

@ -15,7 +15,8 @@ from vasl_templates.webapp.tests.test_vassal import run_vassal_tests
from vasl_templates.webapp.tests.utils import init_webapp, select_tab, new_scenario, \
set_player, set_template_params, set_scenario_date, get_player_nat, get_theater, set_theater, \
get_turn_track_nturns, \
wait_for, wait_for_elem, find_child, find_children, get_css_classes, set_stored_msg, click_dialog_button
wait_for, wait_for_elem, find_child, find_children, get_css_classes, set_stored_msg, click_dialog_button, \
remove_url_params
# ---------------------------------------------------------------------
@ -833,7 +834,7 @@ def _unload_scenario_card(): #pylint: disable=too-many-branches,too-many-locals
# unload the icons
icons = set(
c.get_attribute( "src" )
remove_url_params( c.get_attribute( "src" ) )
for c in find_children( ".info .icons img", card )
)
if icons:

@ -448,7 +448,7 @@ def _check_warning_msgs( webapp, expected ):
warnings = webapp.control_tests.get_vasl_mod_warnings()
if expected:
assert len(warnings) == 1
if isinstance( expected, typing.re.Pattern ):
if isinstance( expected, typing.Pattern ):
assert expected.search( warnings[0] )
else:
assert warnings[0].startswith( expected )

@ -1,11 +1,11 @@
""" Test VASSAL integration. """
import os
import traceback
import re
import json
import base64
import random
import typing.re #pylint: disable=import-error
from vasl_templates.webapp.vassal import VassalShim
from vasl_templates.webapp.utils import TempFile, change_extn, compare_version_strings
@ -878,14 +878,32 @@ def run_vassal_tests( webapp, func, vasl_extns_type=None,
assert False, "Can't find a valid combination of VASSAL and VASL."
# run the test for each VASSAL+VASL
for vassal_version in vassal_versions:
for vasl_version in vasl_versions:
if not VassalShim.is_compatible_version( vassal_version, vasl_version ):
continue
webapp.control_tests \
.set_vassal_version( vassal_version ) \
.set_vasl_version( vasl_version, vasl_extns_type )
func()
log_fname = os.environ.get( "RUN_VASSAL_TESTS_LOG" ) # nb: define this to log activity
log_file = open( log_fname, "w", encoding="utf-8" ) if log_fname else None #pylint: disable=consider-using-with
def log( fmt, *args, **kwargs ):
if log_file:
print( fmt.format( *args, **kwargs ), file=log_file )
log_file.flush()
try:
for vassal_version in vassal_versions:
for vasl_version in vasl_versions:
if not VassalShim.is_compatible_version( vassal_version, vasl_version ):
continue
log( "Running tests for VASSAL {}, VASL {}...", vassal_version, vasl_version )
webapp.control_tests \
.set_vassal_version( vassal_version ) \
.set_vasl_version( vasl_version, vasl_extns_type )
try:
func()
log ( "- OK.\n" )
except Exception as exc: #pylint: disable=broad-except
log( "- Failed: {}\n{}", exc,
re.sub( "^", " ", traceback.format_exc(), flags=re.MULTILINE )
)
#raise
finally:
if log_file:
log_file.close()
# ---------------------------------------------------------------------
@ -963,7 +981,7 @@ def _check_vsav_dump( vsav_dump, expected, ignore=None ):
# compare what we extracted from the dump with what's expected
for snippet_id in expected:
if isinstance( expected[snippet_id], typing.re.Pattern ):
if isinstance( expected[snippet_id], re.Pattern ):
rc = expected[snippet_id].search( labels[snippet_id] ) is not None
else:
assert isinstance( expected[snippet_id], str )

@ -671,7 +671,7 @@ def wait_for_clipboard( timeout, expected, contains=None, transform=None ):
if transform:
clipboard = transform( clipboard )
if contains is None:
if isinstance( expected, typing.re.Pattern ):
if isinstance( expected, typing.Pattern ):
return expected.search( clipboard ) is not None
else:
return expected == clipboard
@ -749,6 +749,13 @@ def get_css_classes( elem ):
classes = elem.get_attribute( "class" )
return classes.split() if classes else []
def remove_url_params( url ):
"""Remove parameters from a URL."""
pos = url.find( "?" )
if pos < 0:
return url
return url[:pos]
# ---------------------------------------------------------------------
def get_all_loggers():

@ -16,8 +16,10 @@ from vasl_templates.webapp.config.constants import DATA_DIR
from vasl_templates.webapp.vo import get_vo_listings
from vasl_templates.webapp.utils import compare_version_strings
SUPPORTED_VASL_MOD_VERSIONS = [ "6.6.0", "6.6.1", "6.6.2", "6.6.3", "6.6.3.1", "6.6.4", "6.6.5", "6.6.6" ]
SUPPORTED_VASL_MOD_VERSIONS_DISPLAY = "6.6.0-.6, 6.6.3.1"
SUPPORTED_VASL_MOD_VERSIONS = [
"6.6.0", "6.6.1", "6.6.2", "6.6.3", "6.6.3.1", "6.6.4", "6.6.5", "6.6.6", "6.6.7", "6.6.8"
]
SUPPORTED_VASL_MOD_VERSIONS_DISPLAY = "6.6.0-.8, 6.6.3.1"
_zip_file_lock = threading.Lock()

@ -39,6 +39,8 @@ from vasl_templates.webapp.vasl_mod import get_reverse_remapped_gpid
# 6.6.4 | 3.6.6 17.0.2+8-LTS
# 6.6.5 | 3.6.7 18.0.1
# 6.6.6 | 3.6.14 19.0.2+7
# 6.6.7 | 3.7.5 21 (2023-09-19 LTS)
# 6.6.8 | 3.7.9 21.0.2 (2024-01-16 LTS)
# NOTE: VASSAL+VASL back-compat has gone out the window :-/ We have to tie versions of VASL
# to specific versions of VASSAL. Sigh...
SUPPORTED_VASSAL_VERSIONS = {
@ -46,9 +48,11 @@ SUPPORTED_VASSAL_VERSIONS = {
"3.4.6": [ "6.6.0", "6.6.1" ],
"3.5.5": [ "6.6.0", "6.6.1", "6.6.2" ],
"3.5.8": [ "6.6.0", "6.6.1", "6.6.2", "6.6.3", "6.6.3.1" ],
"3.6.6": [ "6.6.0", "6.6.1", "6.6.2", "6.6.3", "6.6.3.1", "6.6.4", "6.6.5", "6.6.6" ],
"3.6.7": [ "6.6.0", "6.6.1", "6.6.2", "6.6.3", "6.6.3.1", "6.6.4", "6.6.5", "6.6.6" ],
"3.6.14": [ "6.6.0", "6.6.1", "6.6.2", "6.6.3", "6.6.3.1", "6.6.4", "6.6.5", "6.6.6" ],
"3.6.6": [ "6.6.0", "6.6.1", "6.6.2", "6.6.3", "6.6.3.1", "6.6.4", "6.6.5", "6.6.6", "6.6.7" ],
"3.6.7": [ "6.6.0", "6.6.1", "6.6.2", "6.6.3", "6.6.3.1", "6.6.4", "6.6.5", "6.6.6", "6.6.7" ],
"3.6.14": [ "6.6.0", "6.6.1", "6.6.2", "6.6.3", "6.6.3.1", "6.6.4", "6.6.5", "6.6.6", "6.6.7" ],
"3.7.5": [ "6.6.2", "6.6.3", "6.6.3.1", "6.6.4", "6.6.5", "6.6.6", "6.6.7", "6.6.8" ],
"3.7.9": [ "6.6.2", "6.6.3", "6.6.3.1", "6.6.4", "6.6.5", "6.6.6", "6.6.7", "6.6.8" ],
}
SUPPORTED_VASSAL_VERSIONS_DISPLAY = "3.4.2, 3.4.6, 3.5.5, 3.5.8, 3.6.6, 3.6.7, 3.6.14"
@ -435,6 +439,8 @@ class VassalShim:
if compare_version_strings( mo.group(), "3.3.0" ) < 0:
# we're using a legacy version of VASSAL - use Java 8
java_path = java8_path
if not java_path:
raise SimpleError( "Java has not been configured." )
# prepare the command
class_path = app.config.get( "JAVA_CLASS_PATH" )

@ -61,7 +61,7 @@ class WebDriver:
log_fname = globvars.user_profile.webdriver_log_fname
if "chromedriver" in webdriver_path:
options = webdriver.ChromeOptions()
options.headless = True
options.add_argument( "--headless" )
options.add_argument( "--no-sandbox" ) # nb: need this on the rPi 4
options.add_argument( "--no-proxy-server" )
# OMG! The chromedriver looks for Chrome/Chromium in a hard-coded, fixed location (the default
@ -70,23 +70,23 @@ class WebDriver:
if chrome_path:
options.binary_location = chrome_path
service = webdriver.chrome.service.Service(
webdriver_path, log_path=log_fname
webdriver_path, log_output=log_fname
)
if is_windows():
service.creationflags = 0x8000000 # win32process.CREATE_NO_WINDOW
service.creation_flags = 0x8000000 # win32process.CREATE_NO_WINDOW
self.driver = webdriver.Chrome(
options=options, service=service
)
elif "geckodriver" in webdriver_path:
options = webdriver.FirefoxOptions()
options.headless = True
options.add_argument( "--headless" )
service = webdriver.firefox.service.Service(
webdriver_path, log_path=log_fname
webdriver_path, log_output=log_fname
)
if is_windows():
service.creationflags = 0x8000000 # win32process.CREATE_NO_WINDOW
service.creation_flags = 0x8000000 # win32process.CREATE_NO_WINDOW
self.driver = webdriver.Firefox(
options=options, proxy=None, service=service
options=options, service=service
)
else:
raise SimpleError( "Can't identify webdriver: {}".format( webdriver_path ) )

@ -61,6 +61,7 @@ import VASSAL.counters.Decorator ;
import VASSAL.counters.DynamicProperty ;
import VASSAL.counters.PieceCloner ;
import VASSAL.preferences.Prefs ;
import VASSAL.configure.StringConfigurer ;
import VASSAL.tools.DataArchive ;
import VASSAL.tools.DialogUtils ;
@ -1131,6 +1132,13 @@ public class VassalShim
private Command loadScenario( String scenarioFilename ) throws IOException
{
// FUDGE! Need this for VASL 6.6.7 (but for some reason, older VASSAL+VASL combinations that used to work
// started breaking, as well :-/).
Prefs prefs = GameModule.getGameModule().getPrefs() ;
String SHOW_MARK_MOVED = "showMarkMoved" ;
prefs.addOption( null, new StringConfigurer( SHOW_MARK_MOVED, null ) ) ;
prefs.setValue( SHOW_MARK_MOVED, false ) ;
// load the scenario
disableBoardWarnings() ;
logger.info( "Loading scenario: {}", scenarioFilename ) ;

Loading…
Cancel
Save