diff --git a/.github/workflows/FissionUnitTest.yml b/.github/workflows/FissionUnitTest.yml index 1a0389244b..b3dc4e6be2 100644 --- a/.github/workflows/FissionUnitTest.yml +++ b/.github/workflows/FissionUnitTest.yml @@ -44,7 +44,7 @@ jobs: with: path: | ~/.cache/ms-playwright/ - key: ${{ runner.os }}-assets-playwright-${{ env.PLAYWRIGHT_VERSION }} + key: ${{ runner.os }}-assets-playwright-${{ env.PLAYWRIGHT_VERSION }}-v2 - name: Install Dependencies run: | diff --git a/.gitmodules b/.gitmodules index 44da10b0bf..8f7b277463 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "mirabuf"] path = mirabuf url = https://github.com/HiceS/mirabuf.git +[submodule "jolt"] + path = jolt + url = https://github.com/HunterBarclay/JoltPhysics.js.git diff --git a/README.md b/README.md index 3a6135d588..cd19a6d963 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,10 @@ All code is under a configured formatting utility. See each component for more d Mirabuf is a file format we use to store physical data from Fusion to load into the Synthesis simulator (Fission). This is a separate project that is a submodule of Synthesis. [See Mirabuf](https://github.com/HiceS/mirabuf/) +### Jolt Physics + +Jolt is the core physics engine for our web biased simulator. [See JoltPhysics.js](https://github.com/HunterBarclay/JoltPhysics.js) for more information. + ### Tutorials Our source code for the tutorials featured on our [Tutorials Page](https://synthesis.autodesk.com/tutorials.html). diff --git a/exporter/SynthesisFusionAddin/Synthesis.py b/exporter/SynthesisFusionAddin/Synthesis.py index 20f3fb35d6..deba3c9551 100644 --- a/exporter/SynthesisFusionAddin/Synthesis.py +++ b/exporter/SynthesisFusionAddin/Synthesis.py @@ -3,35 +3,45 @@ import adsk.core -# Currently required for `resolveDependencies()`, will be required for absolute imports. +# Required for absolute imports. sys.path.append(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "proto", "proto_out"))) -from .src.Dependencies import resolveDependencies # isort:skip +from src.Dependencies import resolveDependencies +from src.Logging import logFailure, setupLogger -# Transition: AARD-1741 -# Import order should be removed in AARD-1737 and `setupLogger()` moved to `__init__.py` -from .src.Logging import getLogger, logFailure, setupLogger # isort:skip - -setupLogger() +logger = setupLogger() try: - from .src.general_imports import APP_NAME, DESCRIPTION, INTERNAL_ID, gm - from .src.UI import ( - HUI, - Camera, - ConfigCommand, - MarkingMenu, - ShowAPSAuthCommand, - ShowWebsiteCommand, + # Attempt to import required pip dependencies to verify their installation. + import requests + from proto.proto_out import ( + assembly_pb2, + joint_pb2, + material_pb2, + motor_pb2, + signal_pb2, + types_pb2, ) - from .src.UI.Toolbar import Toolbar -except (ImportError, ModuleNotFoundError) as error: - getLogger().warn(f"Running resolve dependencies with error of:\n{error}") +except (ImportError, ModuleNotFoundError, BaseException) as error: # BaseException required to catch proto.VersionError + logger.warn(f"Running resolve dependencies with error of:\n{error}") result = resolveDependencies() if result: adsk.core.Application.get().userInterface.messageBox("Installed required dependencies.\nPlease restart Fusion.") +from src import APP_NAME, DESCRIPTION, INTERNAL_ID, gm +from src.UI import ( + HUI, + Camera, + ConfigCommand, + MarkingMenu, + ShowAPSAuthCommand, + ShowWebsiteCommand, +) +from src.UI.Toolbar import Toolbar + + @logFailure def run(_): """## Entry point to application from Fusion. @@ -68,28 +78,8 @@ def stop(_): # nm.deleteMe() - logger = getLogger(INTERNAL_ID) logger.cleanupHandlers() - - for file in gm.files: - try: - os.remove(file) - except OSError: - pass - - # removes path so that proto files don't get confused - - import sys - - path = os.path.abspath(os.path.dirname(__file__)) - - path_proto_files = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "proto", "proto_out")) - - if path in sys.path: - sys.path.remove(path) - - if path_proto_files in sys.path: - sys.path.remove(path_proto_files) + gm.clear() @logFailure diff --git a/exporter/SynthesisFusionAddin/src/APS/APS.py b/exporter/SynthesisFusionAddin/src/APS/APS.py index a65728ec23..a6f4f34a5b 100644 --- a/exporter/SynthesisFusionAddin/src/APS/APS.py +++ b/exporter/SynthesisFusionAddin/src/APS/APS.py @@ -10,13 +10,13 @@ import requests -from ..general_imports import INTERNAL_ID, gm, my_addin_path -from ..Logging import getLogger +from src import ADDIN_PATH, gm +from src.Logging import getLogger logger = getLogger() CLIENT_ID = "GCxaewcLjsYlK8ud7Ka9AKf9dPwMR3e4GlybyfhAK2zvl3tU" -auth_path = os.path.abspath(os.path.join(my_addin_path, "..", ".aps_auth")) +auth_path = os.path.abspath(os.path.join(ADDIN_PATH, "..", ".aps_auth")) APS_AUTH = None APS_USER_INFO = None diff --git a/exporter/SynthesisFusionAddin/src/Dependencies.py b/exporter/SynthesisFusionAddin/src/Dependencies.py index b9ad31f7be..c6c1b26b4c 100644 --- a/exporter/SynthesisFusionAddin/src/Dependencies.py +++ b/exporter/SynthesisFusionAddin/src/Dependencies.py @@ -1,7 +1,6 @@ import importlib.machinery import importlib.util import os -import platform import subprocess import sys from pathlib import Path @@ -9,10 +8,10 @@ import adsk.core import adsk.fusion -from .Logging import getLogger, logFailure +from src import SYSTEM +from src.Logging import getLogger, logFailure logger = getLogger() -system = platform.system() # Since the Fusion python runtime is separate from the system python runtime we need to do some funky things # in order to download and install python packages separate from the standard library. @@ -29,13 +28,11 @@ def getInternalFusionPythonInstillationFolder() -> str: pythonStandardLibraryModulePath = importlib.machinery.PathFinder.find_spec("os", sys.path).origin # Depending on platform, adjust to folder to where the python executable binaries are stored. - if system == "Windows": + if SYSTEM == "Windows": folder = f"{Path(pythonStandardLibraryModulePath).parents[1]}" - elif system == "Darwin": - folder = f"{Path(pythonStandardLibraryModulePath).parents[2]}/bin" else: - # TODO: System string should be moved to __init__ after GH-1013 - raise RuntimeError("Unsupported platform.") + assert SYSTEM == "Darwin" + folder = f"{Path(pythonStandardLibraryModulePath).parents[2]}/bin" return folder @@ -100,7 +97,7 @@ def resolveDependencies() -> bool | None: adsk.doEvents() pythonFolder = getInternalFusionPythonInstillationFolder() - pythonExecutableFile = "python.exe" if system == "Windows" else "python" # Confirming 110% everything is fine. + pythonExecutableFile = "python.exe" if SYSTEM == "Windows" else "python" # Confirming 110% everything is fine. pythonExecutablePath = os.path.join(pythonFolder, pythonExecutableFile) progressBar = ui.createProgressDialog() @@ -109,7 +106,7 @@ def resolveDependencies() -> bool | None: progressBar.show("Synthesis", f"Installing dependencies...", 0, len(PIP_DEPENDENCY_VERSION_MAP) * 2 + 2, 0) # Install pip manually on macos as it is not included by default? Really? - if system == "Darwin" and not os.path.exists(os.path.join(pythonFolder, "pip")): + if SYSTEM == "Darwin" and not os.path.exists(os.path.join(pythonFolder, "pip")): pipInstallScriptPath = os.path.join(pythonFolder, "get-pip.py") if not os.path.exists(pipInstallScriptPath): executeCommand("curl", "https://bootstrap.pypa.io/get-pip.py", "-o", pipInstallScriptPath) diff --git a/exporter/SynthesisFusionAddin/src/GlobalManager.py b/exporter/SynthesisFusionAddin/src/GlobalManager.py index a31688d119..6841a58750 100644 --- a/exporter/SynthesisFusionAddin/src/GlobalManager.py +++ b/exporter/SynthesisFusionAddin/src/GlobalManager.py @@ -1,13 +1,8 @@ """ Initializes the global variables that are set in the run method to reduce hanging commands. """ -import logging - import adsk.core import adsk.fusion -from .general_imports import * -from .strings import * - class GlobalManager(object): """Global Manager instance""" @@ -47,6 +42,11 @@ def __init__(self): def __str__(self): return "GlobalManager" + def clear(self): + for attr, value in self.__dict__.items(): + if isinstance(value, list): + setattr(self, attr, []) + instance = None def __new__(cls): diff --git a/exporter/SynthesisFusionAddin/src/Logging.py b/exporter/SynthesisFusionAddin/src/Logging.py index 2bf9ce191b..e5f352f480 100644 --- a/exporter/SynthesisFusionAddin/src/Logging.py +++ b/exporter/SynthesisFusionAddin/src/Logging.py @@ -11,8 +11,8 @@ import adsk.core -from .strings import INTERNAL_ID -from .UI.OsHelper import getOSPath +from src import INTERNAL_ID +from src.UI.OsHelper import getOSPath MAX_LOG_FILES_TO_KEEP = 10 TIMING_LEVEL = 25 @@ -27,7 +27,7 @@ def cleanupHandlers(self) -> None: handler.close() -def setupLogger() -> None: +def setupLogger() -> SynthesisLogger: now = datetime.now().strftime("%H-%M-%S") today = date.today() logFileFolder = getOSPath(f"{pathlib.Path(__file__).parent.parent}", "logs") @@ -46,6 +46,7 @@ def setupLogger() -> None: logger = getLogger(INTERNAL_ID) logger.setLevel(10) # Debug logger.addHandler(logHandler) + return cast(SynthesisLogger, logger) def getLogger(name: str | None = None) -> SynthesisLogger: diff --git a/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py b/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py index 9151a7115d..69e9bbef5d 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py +++ b/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py @@ -11,9 +11,9 @@ import adsk.core from adsk.fusion import CalculationAccuracy, TriangleMeshQualityOptions -from ..Logging import logFailure, timed -from ..strings import INTERNAL_ID -from ..Types import ( +from src import INTERNAL_ID +from src.Logging import logFailure, timed +from src.Types import ( KG, ExportLocation, ExportMode, diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py index aa77cac500..aea709f04a 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py @@ -1,20 +1,18 @@ # Contains all of the logic for mapping the Components / Occurrences -import logging -import traceback -import uuid -from typing import * - import adsk.core import adsk.fusion - from proto.proto_out import assembly_pb2, joint_pb2, material_pb2, types_pb2 -from ...Logging import logFailure, timed -from ...Types import ExportMode -from ..ExporterOptions import ExporterOptions -from . import PhysicalProperties -from .PDMessage import PDMessage -from .Utilities import * +from src.Logging import logFailure +from src.Parser.ExporterOptions import ExporterOptions +from src.Parser.SynthesisParser import PhysicalProperties +from src.Parser.SynthesisParser.PDMessage import PDMessage +from src.Parser.SynthesisParser.Utilities import ( + fill_info, + guid_component, + guid_occurrence, +) +from src.Types import ExportMode # TODO: Impelement Material overrides diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py index 53dd3d10fa..cf8c5e04b0 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py @@ -1,18 +1,15 @@ import enum -import logging -import traceback -from typing import * +from typing import Union import adsk.core import adsk.fusion - from proto.proto_out import joint_pb2, types_pb2 -from ...general_imports import * -from ...Logging import getLogger, logFailure -from ..ExporterOptions import ExporterOptions -from .PDMessage import PDMessage -from .Utilities import guid_component, guid_occurrence +from src import gm +from src.Logging import getLogger, logFailure +from src.Parser.ExporterOptions import ExporterOptions +from src.Parser.SynthesisParser.PDMessage import PDMessage +from src.Parser.SynthesisParser.Utilities import guid_component, guid_occurrence logger = getLogger() diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py index c79a0240d0..6b1650b3f9 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py @@ -28,15 +28,17 @@ import adsk.core import adsk.fusion - -from proto.proto_out import assembly_pb2, joint_pb2, motor_pb2, signal_pb2, types_pb2 - -from ...general_imports import * -from ...Logging import getLogger -from ...Types import JointParentType, SignalType -from ..ExporterOptions import ExporterOptions -from .PDMessage import PDMessage -from .Utilities import construct_info, fill_info, guid_occurrence +from proto.proto_out import assembly_pb2, joint_pb2, signal_pb2, types_pb2 + +from src.Logging import getLogger +from src.Parser.ExporterOptions import ExporterOptions +from src.Parser.SynthesisParser.PDMessage import PDMessage +from src.Parser.SynthesisParser.Utilities import ( + construct_info, + fill_info, + guid_occurrence, +) +from src.Types import JointParentType, SignalType logger = getLogger() diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py index 97d8d47f57..a077c764b7 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py @@ -1,18 +1,10 @@ -# Should contain Physical and Apperance materials ? -import json -import logging -import math -import traceback - import adsk - from proto.proto_out import material_pb2 -from ...general_imports import * -from ...Logging import logFailure, timed -from ..ExporterOptions import ExporterOptions -from .PDMessage import PDMessage -from .Utilities import * +from src.Logging import logFailure +from src.Parser.ExporterOptions import ExporterOptions +from src.Parser.SynthesisParser.PDMessage import PDMessage +from src.Parser.SynthesisParser.Utilities import construct_info, fill_info OPACITY_RAMPING_CONSTANT = 14.0 diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py index fe034d20b4..338f5a300a 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py @@ -4,17 +4,22 @@ import adsk.core import adsk.fusion from google.protobuf.json_format import MessageToJson - from proto.proto_out import assembly_pb2, types_pb2 -from ...APS.APS import getAuth, upload_mirabuf -from ...general_imports import * -from ...Logging import getLogger, logFailure, timed -from ...Types import ExportLocation, ExportMode -from ...UI.Camera import captureThumbnail, clearIconCache -from ..ExporterOptions import ExporterOptions -from . import Components, JointHierarchy, Joints, Materials, PDMessage -from .Utilities import * +from src import gm +from src.APS.APS import getAuth, upload_mirabuf +from src.Logging import getLogger, logFailure, timed +from src.Parser.ExporterOptions import ExporterOptions +from src.Parser.SynthesisParser import ( + Components, + JointHierarchy, + Joints, + Materials, + PDMessage, +) +from src.Parser.SynthesisParser.Utilities import fill_info +from src.Types import ExportLocation, ExportMode +from src.UI.Camera import captureThumbnail, clearIconCache logger = getLogger() diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py index db488c115a..b178bcb3bb 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py @@ -16,16 +16,12 @@ """ -import logging -import traceback from typing import Union import adsk - from proto.proto_out import types_pb2 -from ...general_imports import INTERNAL_ID -from ...Logging import logFailure +from src.Logging import logFailure @logFailure diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/RigidGroup.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/RigidGroup.py index 362a2a6e72..8516cefae6 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/RigidGroup.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/RigidGroup.py @@ -12,14 +12,13 @@ - Success """ -from typing import * +from typing import Union import adsk.core import adsk.fusion - from proto.proto_out import assembly_pb2 -from ...Logging import logFailure +from src.Logging import logFailure @logFailure diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py index f508f32117..0a5d277766 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py @@ -1,11 +1,9 @@ import math import uuid -from adsk.core import Base, Vector3D +from adsk.core import Vector3D from adsk.fusion import Component, Occurrence -# from proto.proto_out import types_pb2 - def guid_component(comp: Component) -> str: return f"{comp.entityToken}_{comp.id}" diff --git a/exporter/SynthesisFusionAddin/src/UI/Camera.py b/exporter/SynthesisFusionAddin/src/UI/Camera.py index 538968034d..02de04083a 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Camera.py +++ b/exporter/SynthesisFusionAddin/src/UI/Camera.py @@ -1,11 +1,9 @@ import os -from adsk.core import SaveImageFileOptions +import adsk.core -from ..general_imports import * -from ..Logging import logFailure, timed -from ..Types import OString -from . import Helper +from src.Logging import logFailure +from src.Types import OString @logFailure @@ -25,7 +23,7 @@ def captureThumbnail(size=250): path = OString.ThumbnailPath(name) - saveOptions = SaveImageFileOptions.create(str(path.getPath())) + saveOptions = adsk.core.SaveImageFileOptions.create(str(path.getPath())) saveOptions.height = size saveOptions.width = size saveOptions.isAntiAliased = True diff --git a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py index d7fd6ec6bb..c50c7feed2 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py @@ -9,22 +9,17 @@ import adsk.core import adsk.fusion -from ..APS.APS import getAuth, getUserInfo, refreshAuthToken -from ..general_imports import * -from ..Logging import getLogger, logFailure -from ..Parser.ExporterOptions import ExporterOptions -from ..Parser.SynthesisParser.Parser import Parser -from ..Parser.SynthesisParser.Utilities import guid_occurrence -from ..Types import ExportLocation, ExportMode -from . import CustomGraphics, FileDialogConfig, Helper, IconPaths -from .Configuration.SerialCommand import SerialCommand -from .GamepieceConfigTab import GamepieceConfigTab -from .GeneralConfigTab import GeneralConfigTab - -# Transition: AARD-1685 -# In the future all components should be handled in this way. -# This import broke everything when attempting to use absolute imports??? Investigate? -from .JointConfigTab import JointConfigTab +from src import gm +from src.APS.APS import getAuth, getUserInfo +from src.Logging import getLogger, logFailure +from src.Parser.ExporterOptions import ExporterOptions +from src.Parser.SynthesisParser.Parser import Parser +from src.Types import ExportLocation, ExportMode +from src.UI import FileDialogConfig +from src.UI.Configuration.SerialCommand import SerialCommand +from src.UI.GamepieceConfigTab import GamepieceConfigTab +from src.UI.GeneralConfigTab import GeneralConfigTab +from src.UI.JointConfigTab import JointConfigTab # ====================================== CONFIG COMMAND ====================================== diff --git a/exporter/SynthesisFusionAddin/src/UI/Configuration/SerialCommand.py b/exporter/SynthesisFusionAddin/src/UI/Configuration/SerialCommand.py index 16084148c5..663afe9337 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Configuration/SerialCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/Configuration/SerialCommand.py @@ -7,7 +7,7 @@ import json -from ...Types import OString +from src.Types import OString def generateFilePath() -> str: diff --git a/exporter/SynthesisFusionAddin/src/UI/CreateCommandInputsHelper.py b/exporter/SynthesisFusionAddin/src/UI/CreateCommandInputsHelper.py index 536b93b57d..1f78b469bd 100644 --- a/exporter/SynthesisFusionAddin/src/UI/CreateCommandInputsHelper.py +++ b/exporter/SynthesisFusionAddin/src/UI/CreateCommandInputsHelper.py @@ -1,6 +1,6 @@ import adsk.core -from ..Logging import logFailure +from src.Logging import logFailure @logFailure diff --git a/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py b/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py index 52a49fa5d4..3b6bd8e2c2 100644 --- a/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py +++ b/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py @@ -1,11 +1,8 @@ -import logging -import traceback - import adsk.core import adsk.fusion -from ..general_imports import * -from ..Logging import logFailure +from src import gm +from src.Logging import logFailure @logFailure diff --git a/exporter/SynthesisFusionAddin/src/UI/Events.py b/exporter/SynthesisFusionAddin/src/UI/Events.py index 281ebf3f0e..64d0f1ea29 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Events.py +++ b/exporter/SynthesisFusionAddin/src/UI/Events.py @@ -1,7 +1,10 @@ -from typing import Sequence, Tuple +import json +from typing import Sequence -from ..general_imports import * -from ..Logging import getLogger +import adsk.core + +from src import gm +from src.Logging import getLogger """ # This file is Special It links all function names to command requests that palletes can make automatically diff --git a/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py b/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py index 6f6f764cd9..d2465ae29b 100644 --- a/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py +++ b/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py @@ -1,12 +1,8 @@ -from typing import Union - import adsk.core import adsk.fusion -from ..general_imports import * - -# from ..proto_out import Configuration_pb2 -from ..Types import OString +from src import gm +from src.Types import OString def saveFileDialog(defaultPath: str | None = None, defaultName: str | None = None) -> str | bool: diff --git a/exporter/SynthesisFusionAddin/src/UI/GamepieceConfigTab.py b/exporter/SynthesisFusionAddin/src/UI/GamepieceConfigTab.py index f0d2f7d4bd..8eb4f80044 100644 --- a/exporter/SynthesisFusionAddin/src/UI/GamepieceConfigTab.py +++ b/exporter/SynthesisFusionAddin/src/UI/GamepieceConfigTab.py @@ -1,11 +1,11 @@ import adsk.core import adsk.fusion -from ..Logging import logFailure -from ..Parser.ExporterOptions import ExporterOptions -from ..Types import Gamepiece, PreferredUnits, toKg, toLbs -from . import IconPaths -from .CreateCommandInputsHelper import ( +from src.Logging import logFailure +from src.Parser.ExporterOptions import ExporterOptions +from src.Types import Gamepiece, PreferredUnits, toKg, toLbs +from src.UI import IconPaths +from src.UI.CreateCommandInputsHelper import ( createBooleanInput, createTableInput, createTextBoxInput, diff --git a/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py b/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py index 116b8ca7d7..40a602a406 100644 --- a/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py +++ b/exporter/SynthesisFusionAddin/src/UI/GeneralConfigTab.py @@ -1,18 +1,18 @@ import adsk.core import adsk.fusion -from ..Logging import logFailure -from ..Parser.ExporterOptions import ( +from src.Logging import logFailure +from src.Parser.ExporterOptions import ( ExporterOptions, ExportLocation, ExportMode, PreferredUnits, ) -from ..Types import KG, toKg, toLbs -from . import IconPaths -from .CreateCommandInputsHelper import createBooleanInput, createTableInput -from .GamepieceConfigTab import GamepieceConfigTab -from .JointConfigTab import JointConfigTab +from src.Types import KG, toKg, toLbs +from src.UI import IconPaths +from src.UI.CreateCommandInputsHelper import createBooleanInput, createTableInput +from src.UI.GamepieceConfigTab import GamepieceConfigTab +from src.UI.JointConfigTab import JointConfigTab class GeneralConfigTab: diff --git a/exporter/SynthesisFusionAddin/src/UI/HUI.py b/exporter/SynthesisFusionAddin/src/UI/HUI.py index 3b52de9999..d1a968d642 100644 --- a/exporter/SynthesisFusionAddin/src/UI/HUI.py +++ b/exporter/SynthesisFusionAddin/src/UI/HUI.py @@ -1,6 +1,8 @@ -from ..general_imports import * -from ..Logging import logFailure -from . import Handlers, OsHelper +import adsk.core + +from src import INTERNAL_ID, gm +from src.Logging import logFailure +from src.UI import Handlers, OsHelper # no longer used diff --git a/exporter/SynthesisFusionAddin/src/UI/Handlers.py b/exporter/SynthesisFusionAddin/src/UI/Handlers.py index 710f61e8c8..4529b861db 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Handlers.py +++ b/exporter/SynthesisFusionAddin/src/UI/Handlers.py @@ -1,4 +1,4 @@ -from ..general_imports import * +import adsk.core class HButtonCommandCreatedEvent(adsk.core.CommandCreatedEventHandler): diff --git a/exporter/SynthesisFusionAddin/src/UI/Helper.py b/exporter/SynthesisFusionAddin/src/UI/Helper.py index 7c8e3a5930..ba8bf9b0e9 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Helper.py +++ b/exporter/SynthesisFusionAddin/src/UI/Helper.py @@ -1,8 +1,9 @@ from inspect import getmembers, isfunction -from typing import Union -from ..general_imports import * -from . import HUI, Events +import adsk.core + +from src import APP_NAME, APP_TITLE, INTERNAL_ID, gm +from src.UI import HUI, Events def getDocName() -> str or None: diff --git a/exporter/SynthesisFusionAddin/src/UI/IconPaths.py b/exporter/SynthesisFusionAddin/src/UI/IconPaths.py index 261720494c..2804af221a 100644 --- a/exporter/SynthesisFusionAddin/src/UI/IconPaths.py +++ b/exporter/SynthesisFusionAddin/src/UI/IconPaths.py @@ -1,6 +1,6 @@ import os -from . import OsHelper +from src.UI import OsHelper """ Dictionaries that store all the icon paths in ConfigCommand. All path strings are OS-independent diff --git a/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py b/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py index 7e34757783..b06ae6f2af 100644 --- a/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py +++ b/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py @@ -1,14 +1,10 @@ -import logging -import traceback - import adsk.core import adsk.fusion -from ..general_imports import INTERNAL_ID -from ..Logging import logFailure -from ..Types import Joint, JointParentType, SignalType, Wheel, WheelType -from . import IconPaths -from .CreateCommandInputsHelper import ( +from src.Logging import logFailure +from src.Types import Joint, JointParentType, SignalType, Wheel, WheelType +from src.UI import IconPaths +from src.UI.CreateCommandInputsHelper import ( createBooleanInput, createTableInput, createTextBoxInput, diff --git a/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py b/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py index 30c9f078e6..5b90c1b671 100644 --- a/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py +++ b/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py @@ -1,10 +1,7 @@ -import logging.handlers -import traceback - import adsk.core import adsk.fusion -from ..Logging import logFailure +from src.Logging import getLogger, logFailure # Ripped all the boiler plate from the example code: https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-c90ce6a2-c282-11e6-a365-3417ebc87622 @@ -15,6 +12,8 @@ entities = [] occurrencesOfComponents = {} +logger = getLogger() + @logFailure(messageBox=True) def setupMarkingMenu(ui: adsk.core.UserInterface): @@ -207,6 +206,7 @@ def stopMarkingMenu(ui: adsk.core.UserInterface): if obj.isValid: obj.deleteMe() else: - ui.messageBox(str(obj) + " is not a valid object") + logger.warn(f"{str(obj)} is not a valid object") + cmdDefs.clear() handlers.clear() diff --git a/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py b/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py index bd45cfc062..999abd1176 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py @@ -1,15 +1,13 @@ import json -import os import time import traceback import urllib.parse import urllib.request -import webbrowser import adsk.core +from src import gm from src.APS.APS import CLIENT_ID, auth_path, convertAuthToken, getCodeChallenge -from src.general_imports import APP_NAME, DESCRIPTION, INTERNAL_ID, gm, my_addin_path from src.Logging import getLogger logger = getLogger() diff --git a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py index d7e1539e5e..cc99cffb07 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py @@ -1,8 +1,9 @@ +import traceback import webbrowser import adsk.core -from ..general_imports import * +from src import gm class ShowWebsiteCommandExecuteHandler(adsk.core.CommandEventHandler): diff --git a/exporter/SynthesisFusionAddin/src/UI/Toolbar.py b/exporter/SynthesisFusionAddin/src/UI/Toolbar.py index bfcc34189a..f9d150cc3c 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Toolbar.py +++ b/exporter/SynthesisFusionAddin/src/UI/Toolbar.py @@ -1,6 +1,5 @@ -from ..general_imports import * -from ..Logging import logFailure -from ..strings import INTERNAL_ID +from src import INTERNAL_ID, gm +from src.Logging import logFailure class Toolbar: diff --git a/exporter/SynthesisFusionAddin/src/__init__.py b/exporter/SynthesisFusionAddin/src/__init__.py new file mode 100644 index 0000000000..1e426279bb --- /dev/null +++ b/exporter/SynthesisFusionAddin/src/__init__.py @@ -0,0 +1,17 @@ +import os +import platform + +from src.GlobalManager import GlobalManager + +APP_NAME = "Synthesis" +APP_TITLE = "Synthesis Robot Exporter" +DESCRIPTION = "Exports files from Fusion into the Synthesis Format" +INTERNAL_ID = "Synthesis" +ADDIN_PATH = os.path.dirname(os.path.realpath(__file__)) + +SYSTEM = platform.system() +assert SYSTEM != "Linux" + +gm = GlobalManager() + +__all__ = ["APP_NAME", "APP_TITLE", "DESCRIPTION", "INTERNAL_ID", "ADDIN_PATH", "SYSTEM", "gm"] diff --git a/exporter/SynthesisFusionAddin/src/general_imports.py b/exporter/SynthesisFusionAddin/src/general_imports.py deleted file mode 100644 index aabdae5cac..0000000000 --- a/exporter/SynthesisFusionAddin/src/general_imports.py +++ /dev/null @@ -1,42 +0,0 @@ -import json -import os -import pathlib -import sys -import traceback -import uuid -from datetime import datetime -from time import time -from types import FunctionType - -import adsk.core -import adsk.fusion - -from .GlobalManager import * -from .Logging import getLogger -from .strings import * - -logger = getLogger() - -# hard coded to bypass errors for now -PROTOBUF = True -DEBUG = True - -try: - path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) - - path_proto_files = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "proto", "proto_out")) - - if not path in sys.path: - sys.path.insert(1, path) - - if not path_proto_files in sys.path: - sys.path.insert(2, path_proto_files) -except: - logger.error("Failed:\n{}".format(traceback.format_exc())) - -try: - # Setup the global state - gm: GlobalManager = GlobalManager() - my_addin_path = os.path.dirname(os.path.realpath(__file__)) -except: - logger.error("Failed:\n{}".format(traceback.format_exc())) diff --git a/exporter/SynthesisFusionAddin/src/strings.py b/exporter/SynthesisFusionAddin/src/strings.py deleted file mode 100644 index b5d79c055c..0000000000 --- a/exporter/SynthesisFusionAddin/src/strings.py +++ /dev/null @@ -1,4 +0,0 @@ -APP_NAME = "Synthesis" -APP_TITLE = "Synthesis Robot Exporter" -DESCRIPTION = "Exports files from Fusion into the Synthesis Format" -INTERNAL_ID = "Synthesis" diff --git a/exporter/SynthesisFusionAddin/tools/verifyIsortFormatting.py b/exporter/SynthesisFusionAddin/tools/verifyIsortFormatting.py index 0f9d899d5a..61772e05cb 100644 --- a/exporter/SynthesisFusionAddin/tools/verifyIsortFormatting.py +++ b/exporter/SynthesisFusionAddin/tools/verifyIsortFormatting.py @@ -18,9 +18,16 @@ def main() -> None: exitCode = 0 for i, (oldFileState, newFileState) in enumerate(zip(oldFileStates, newFileStates)): for j, (previousLine, newLine) in enumerate(zip(oldFileState, newFileState)): - if previousLine != newLine: - print(f"File {files[i]} is not formatted correctly!\nLine: {j + 1}") - exitCode = 1 + if previousLine == newLine: + continue + + print(f"File {files[i]} is not formatted correctly!\nLine: {j + 1}") + oldFileStateRange = range(max(0, j - 10), min(len(oldFileState), j + 11)) + print("\nOld file state:\n" + "\n".join(oldFileState[k].strip() for k in oldFileStateRange)) + newFileStateRange = range(max(0, j - 10), min(len(newFileState), j + 11)) + print("\nNew file state:\n" + "\n".join(newFileState[k].strip() for k in newFileStateRange)) + exitCode = 1 + break if not exitCode: print("All files are formatted correctly with isort!") diff --git a/fission/index.html b/fission/index.html index bf462bd999..5916fa6750 100644 --- a/fission/index.html +++ b/fission/index.html @@ -1,16 +1,22 @@ - - - - - - - - Fission | Synthesis - - -
- - + + + + + + + + Fission | Synthesis + + +
+ + diff --git a/fission/src/Synthesis.tsx b/fission/src/Synthesis.tsx index 5d34da6495..0e2fe2a29b 100644 --- a/fission/src/Synthesis.tsx +++ b/fission/src/Synthesis.tsx @@ -20,7 +20,6 @@ import UpdateAvailableModal from "@/modals/UpdateAvailableModal" import ViewModal from "@/modals/ViewModal" import ConnectToMultiplayerModal from "@/modals/aether/ConnectToMultiplayerModal" import ServerHostingModal from "@/modals/aether/ServerHostingModal" -import ChangeInputsModal from "@/ui/modals/configuring/inputs/ChangeInputsModal.tsx" import ChooseMultiplayerModeModal from "@/modals/configuring/ChooseMultiplayerModeModal" import ChooseSingleplayerModeModal from "@/modals/configuring/ChooseSingleplayerModeModal" import ConfigMotorModal from "@/modals/configuring/ConfigMotorModal" @@ -37,13 +36,9 @@ import ThemeEditorModal from "@/modals/configuring/theme-editor/ThemeEditorModal import MatchModeModal from "@/modals/spawning/MatchModeModal" import RobotSwitchPanel from "@/panels/RobotSwitchPanel" import SpawnLocationsPanel from "@/panels/SpawnLocationPanel" -import ConfigureGamepiecePickupPanel from "@/panels/configuring/ConfigureGamepiecePickupPanel" -import ConfigureShotTrajectoryPanel from "@/panels/configuring/ConfigureShotTrajectoryPanel" -import ScoringZonesPanel from "@/panels/configuring/scoring/ScoringZonesPanel" import ScoreboardPanel from "@/panels/information/ScoreboardPanel" import DriverStationPanel from "@/panels/simulation/DriverStationPanel" import PokerPanel from "@/panels/PokerPanel.tsx" -import ManageAssembliesModal from "@/modals/spawning/ManageAssembliesModal.tsx" import World from "@/systems/World.ts" import { AddRobotsModal, AddFieldsModal, SpawningModal } from "@/modals/spawning/SpawningModals.tsx" import ImportLocalMirabufModal from "@/modals/mirabuf/ImportLocalMirabufModal.tsx" @@ -51,14 +46,13 @@ import ImportMirabufPanel from "@/ui/panels/mirabuf/ImportMirabufPanel.tsx" import Skybox from "./ui/components/Skybox.tsx" import ChooseInputSchemePanel from "./ui/panels/configuring/ChooseInputSchemePanel.tsx" import ProgressNotifications from "./ui/components/ProgressNotification.tsx" -import ConfigureRobotModal from "./ui/modals/configuring/ConfigureRobotModal.tsx" -import ResetAllInputsModal from "./ui/modals/configuring/inputs/ResetAllInputsModal.tsx" -import ZoneConfigPanel from "./ui/panels/configuring/scoring/ZoneConfigPanel.tsx" +import ConfigureRobotBrainPanel from "./ui/panels/configuring/ConfigureRobotBrainPanel.tsx" import SceneOverlay from "./ui/components/SceneOverlay.tsx" import WPILibWSWorker from "@/systems/simulation/wpilib_brain/WPILibWSWorker.ts?worker" import WSViewPanel from "./ui/panels/WSViewPanel.tsx" import Lazy from "./util/Lazy.ts" + import RCConfigPWMGroupModal from "@/modals/configuring/rio-config/RCConfigPWMGroupModal.tsx" import RCConfigCANGroupModal from "@/modals/configuring/rio-config/RCConfigCANGroupModal.tsx" import DebugPanel from "./ui/panels/DebugPanel.tsx" @@ -66,7 +60,9 @@ import NewInputSchemeModal from "./ui/modals/configuring/theme-editor/NewInputSc import AssignNewSchemeModal from "./ui/modals/configuring/theme-editor/AssignNewSchemeModal.tsx" import AnalyticsConsent from "./ui/components/AnalyticsConsent.tsx" import PreferencesSystem from "./systems/preferences/PreferencesSystem.ts" +import ResetAllInputsModal from "./ui/modals/configuring/inputs/ResetAllInputsModal.tsx" import APSManagementModal from "./ui/modals/APSManagementModal.tsx" +import ConfigurePanel from "./ui/panels/configuring/assembly-config/ConfigurePanel.tsx" const worker = new Lazy(() => new WPILibWSWorker()) @@ -209,7 +205,6 @@ const initialModals = [ , , , - , , , , @@ -224,9 +219,7 @@ const initialModals = [ , , , - , , - , , , ] @@ -236,25 +229,18 @@ const initialPanels: ReactElement[] = [ , , , - , - , + , + , - , - , - , - , , , , + , ] export default Synthesis diff --git a/fission/src/index.css b/fission/src/index.css index afa1fa6dc6..f3c04e2d14 100644 --- a/fission/src/index.css +++ b/fission/src/index.css @@ -2,6 +2,24 @@ @tailwind components; @tailwind utilities; +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: "transparent"; +} + +::-webkit-scrollbar-thumb { + background: #444444; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: #555; +} + :root { /* font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; */ font-family: "Artifakt"; diff --git a/fission/src/mirabuf/MirabufLoader.ts b/fission/src/mirabuf/MirabufLoader.ts index 00c0068733..1355d9e38c 100644 --- a/fission/src/mirabuf/MirabufLoader.ts +++ b/fission/src/mirabuf/MirabufLoader.ts @@ -21,7 +21,7 @@ export interface MirabufRemoteInfo { src: string } -type MiraCache = { [id: string]: MirabufCacheInfo } +type MapCache = { [id: MirabufCacheID]: MirabufCacheInfo } const robotsDirName = "Robots" const fieldsDirName = "Fields" @@ -29,6 +29,33 @@ const root = await navigator.storage.getDirectory() const robotFolderHandle = await root.getDirectoryHandle(robotsDirName, { create: true }) const fieldFolderHandle = await root.getDirectoryHandle(fieldsDirName, { create: true }) +export const backUpRobots: Map = new Map() +export const backUpFields: Map = new Map() + +const canOPFS = await (async () => { + try { + if (robotFolderHandle.name == robotsDirName) { + robotFolderHandle.entries + robotFolderHandle.keys + + const fileHandle = await robotFolderHandle.getFileHandle("0", { create: true }) + const writable = await fileHandle.createWritable() + await writable.close() + await fileHandle.getFile() + + robotFolderHandle.removeEntry(fileHandle.name) + + return true + } else { + console.log(`No access to OPFS`) + return false + } + } catch (e) { + console.log(`No access to OPFS`) + return false + } +})() + export function UnzipMira(buff: Uint8Array): Uint8Array { // Check if file is gzipped via magic gzip numbers 31 139 if (buff[0] == 31 && buff[1] == 139) { @@ -42,11 +69,11 @@ class MirabufCachingService { /** * Get the map of mirabuf keys and paired MirabufCacheInfo from local storage * - * @param {MiraType} miraType Type of Mirabuf Assembly. + * @param {MiraType} miraType Type of Mirabuf Assembly * - * @returns {MiraCache} Map of cached keys and paired MirabufCacheInfo + * @returns {MapCache} Map of cached keys and paired MirabufCacheInfo */ - public static GetCacheMap(miraType: MiraType): MiraCache { + public static GetCacheMap(miraType: MiraType): MapCache { if ( (window.localStorage.getItem(MIRABUF_LOCALSTORAGE_GENERATION_KEY) ?? "") == MIRABUF_LOCALSTORAGE_GENERATION ) { @@ -159,18 +186,18 @@ class MirabufCachingService { thumbnailStorageID?: string ): Promise { try { - const map: MiraCache = this.GetCacheMap(miraType) + const map: MapCache = this.GetCacheMap(miraType) const id = map[key].id const _name = map[key].name const _thumbnailStorageID = map[key].thumbnailStorageID - const hi: MirabufCacheInfo = { + const info: MirabufCacheInfo = { id: id, cacheKey: key, miraType: miraType, name: name ?? _name, thumbnailStorageID: thumbnailStorageID ?? _thumbnailStorageID, } - map[key] = hi + map[key] = info window.localStorage.setItem(miraType == MiraType.ROBOT ? robotsDirName : fieldsDirName, JSON.stringify(map)) return true } catch (e) { @@ -213,16 +240,21 @@ class MirabufCachingService { */ public static async Get(id: MirabufCacheID, miraType: MiraType): Promise { try { - const fileHandle = await (miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle).getFileHandle( - id, - { - create: false, - } - ) - - // Get assembly from file - if (fileHandle) { - const buff = await fileHandle.getFile().then(x => x.arrayBuffer()) + // Get buffer from hashMap. If not in hashMap, check OPFS. Otherwise, buff is undefined + const cache = miraType == MiraType.ROBOT ? backUpRobots : backUpFields + const buff = + cache.get(id) ?? + (await (async () => { + const fileHandle = canOPFS + ? await (miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle).getFileHandle(id, { + create: false, + }) + : undefined + return fileHandle ? await fileHandle.getFile().then(x => x.arrayBuffer()) : undefined + })()) + + // If we have buffer, get assembly + if (buff) { const assembly = this.AssemblyFromBuffer(buff) World.AnalyticsSystem?.Event("Cache Get", { key: id, @@ -232,11 +264,10 @@ class MirabufCachingService { }) return assembly } else { - console.error(`Failed to get file handle for ID: ${id}`) - return undefined + console.error(`Failed to find arrayBuffer for id: ${id}`) } } catch (e) { - console.error(`Failed to find file from OPFS\n${e}`) + console.error(`Failed to find file\n${e}`) return undefined } } @@ -261,8 +292,15 @@ class MirabufCachingService { ) } - const dir = miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle - await dir.removeEntry(id) + if (canOPFS) { + const dir = miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle + await dir.removeEntry(id) + } + + const backUpCache = miraType == MiraType.ROBOT ? backUpRobots : backUpFields + if (backUpCache) { + backUpCache.delete(id) + } World.AnalyticsSystem?.Event("Cache Remove", { key: key, @@ -289,6 +327,9 @@ class MirabufCachingService { window.localStorage.removeItem(robotsDirName) window.localStorage.removeItem(fieldsDirName) + + backUpRobots.clear() + backUpFields.clear() } // Optional name for when assembly is being decoded anyway like in CacheAndGetLocal() @@ -298,7 +339,6 @@ class MirabufCachingService { miraType?: MiraType, name?: string ): Promise { - // Store in OPFS const backupID = Date.now().toString() try { if (!miraType) { @@ -306,16 +346,8 @@ class MirabufCachingService { miraType = this.AssemblyFromBuffer(miraBuff).dynamic ? MiraType.ROBOT : MiraType.FIELD } - const fileHandle = await (miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle).getFileHandle( - backupID, - { create: true } - ) - const writable = await fileHandle.createWritable() - await writable.write(miraBuff) - await writable.close() - // Local cache map - const map: MiraCache = this.GetCacheMap(miraType) + const map: MapCache = this.GetCacheMap(miraType) const info: MirabufCacheInfo = { id: backupID, cacheKey: key, @@ -331,6 +363,22 @@ class MirabufCachingService { type: miraType == MiraType.ROBOT ? "robot" : "field", fileSize: miraBuff.byteLength, }) + + // Store buffer + if (canOPFS) { + // Store in OPFS + const fileHandle = await ( + miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle + ).getFileHandle(backupID, { create: true }) + const writable = await fileHandle.createWritable() + await writable.write(miraBuff) + await writable.close() + } + + // Store in hash + const cache = miraType == MiraType.ROBOT ? backUpRobots : backUpFields + cache.set(backupID, miraBuff) + return info } catch (e) { console.error("Failed to cache mira " + e) @@ -353,7 +401,7 @@ class MirabufCachingService { export enum MiraType { ROBOT = 1, - FIELD = 2, + FIELD, } export default MirabufCachingService diff --git a/fission/src/mirabuf/MirabufParser.ts b/fission/src/mirabuf/MirabufParser.ts index dd7df1e7cf..7dab72156b 100644 --- a/fission/src/mirabuf/MirabufParser.ts +++ b/fission/src/mirabuf/MirabufParser.ts @@ -240,7 +240,6 @@ class MirabufParser { console.log("Failed to get part definitions") return } - console.log(partDefinitions) } private NewRigidNode(suffix?: string): RigidNode { diff --git a/fission/src/systems/input/DefaultInputs.ts b/fission/src/systems/input/DefaultInputs.ts index 2b9ac8d65a..e15fe82d44 100644 --- a/fission/src/systems/input/DefaultInputs.ts +++ b/fission/src/systems/input/DefaultInputs.ts @@ -91,8 +91,8 @@ class DefaultInputs { shift: false, meta: false, }), - new AxisInput("joint 5", "KeyN", "true", -1, false, false, -1, -1, EmptyModifierState, { - ctrl: false, + new AxisInput("joint 5", "KeyN", "KeyN", -1, false, false, -1, -1, EmptyModifierState, { + ctrl: true, alt: false, shift: false, meta: false, diff --git a/fission/src/systems/input/InputSystem.ts b/fission/src/systems/input/InputSystem.ts index 3a396f8968..d56aadd692 100644 --- a/fission/src/systems/input/InputSystem.ts +++ b/fission/src/systems/input/InputSystem.ts @@ -141,9 +141,6 @@ class InputSystem extends WorldSystem { private static _gpIndex: number | null public static gamepad: Gamepad | null - // The scheme most recently selected in the controls modal - public static selectedScheme: InputScheme | undefined - // Maps a brain index to a certain input scheme public static brainIndexSchemeMap: Map = new Map() diff --git a/fission/src/systems/preferences/PreferenceTypes.ts b/fission/src/systems/preferences/PreferenceTypes.ts index 37b04a83ce..9331cc425e 100644 --- a/fission/src/systems/preferences/PreferenceTypes.ts +++ b/fission/src/systems/preferences/PreferenceTypes.ts @@ -43,10 +43,29 @@ export type EjectorPreferences = { parentNode: string | undefined } +export type BehaviorType = "Elevator" | "Arm" + +export type SequentialBehaviorPreferences = { + jointIndex: number + parentJointIndex: number | undefined + type: BehaviorType + inverted: boolean +} + +export function DefaultSequentialConfig(index: number, type: BehaviorType): SequentialBehaviorPreferences { + return { + jointIndex: index, + parentJointIndex: undefined, + type: type, + inverted: false, + } +} + export type RobotPreferences = { inputsSchemes: InputScheme[] intake: IntakePreferences ejector: EjectorPreferences + sequentialConfig?: SequentialBehaviorPreferences[] } export type Alliance = "red" | "blue" diff --git a/fission/src/systems/simulation/Brain.ts b/fission/src/systems/simulation/Brain.ts index a047d65671..d784195e8e 100644 --- a/fission/src/systems/simulation/Brain.ts +++ b/fission/src/systems/simulation/Brain.ts @@ -3,8 +3,8 @@ import Mechanism from "../physics/Mechanism" abstract class Brain { protected _mechanism: Mechanism - constructor(mechansim: Mechanism) { - this._mechanism = mechansim + constructor(mechanism: Mechanism) { + this._mechanism = mechanism } public abstract Update(deltaT: number): void diff --git a/fission/src/systems/simulation/behavior/synthesis/ArcadeDriveBehavior.ts b/fission/src/systems/simulation/behavior/synthesis/ArcadeDriveBehavior.ts index 6851ad4305..a76d2f98d3 100644 --- a/fission/src/systems/simulation/behavior/synthesis/ArcadeDriveBehavior.ts +++ b/fission/src/systems/simulation/behavior/synthesis/ArcadeDriveBehavior.ts @@ -11,6 +11,10 @@ class ArcadeDriveBehavior extends Behavior { private _driveSpeed = 30 private _turnSpeed = 30 + public get wheels(): WheelDriver[] { + return this.leftWheels.concat(this.rightWheels) + } + constructor( leftWheels: WheelDriver[], rightWheels: WheelDriver[], diff --git a/fission/src/systems/simulation/behavior/synthesis/GenericArmBehavior.ts b/fission/src/systems/simulation/behavior/synthesis/GenericArmBehavior.ts index a9d19c5c03..e177549d54 100644 --- a/fission/src/systems/simulation/behavior/synthesis/GenericArmBehavior.ts +++ b/fission/src/systems/simulation/behavior/synthesis/GenericArmBehavior.ts @@ -1,30 +1,31 @@ -import HingeDriver from "@/systems/simulation/driver/HingeDriver" -import HingeStimulus from "@/systems/simulation/stimulus/HingeStimulus" -import Behavior from "@/systems/simulation/behavior/Behavior" -import InputSystem from "@/systems/input/InputSystem" +import { SequentialBehaviorPreferences } from "@/systems/preferences/PreferenceTypes" +import HingeDriver from "../../driver/HingeDriver" +import HingeStimulus from "../../stimulus/HingeStimulus" +import SequenceableBehavior from "./SequenceableBehavior" -class GenericArmBehavior extends Behavior { +class GenericArmBehavior extends SequenceableBehavior { private _hingeDriver: HingeDriver - private _inputName: string - private _brainIndex: number - private _rotationalSpeed = 6 + public get hingeDriver(): HingeDriver { + return this._hingeDriver + } - constructor(hingeDriver: HingeDriver, hingeStimulus: HingeStimulus, jointIndex: number, brainIndex: number) { - super([hingeDriver], [hingeStimulus]) + maxVelocity: number = 6 - this._hingeDriver = hingeDriver - this._inputName = "joint " + jointIndex - this._brainIndex = brainIndex - } + constructor( + hingeDriver: HingeDriver, + hingeStimulus: HingeStimulus, + jointIndex: number, + brainIndex: number, + sequentialConfig: SequentialBehaviorPreferences | undefined + ) { + super(jointIndex, brainIndex, [hingeDriver], [hingeStimulus], sequentialConfig) - // Sets the arms target rotational velocity - rotateArm(rotationalVelocity: number) { - this._hingeDriver.targetVelocity = rotationalVelocity + this._hingeDriver = hingeDriver } - public Update(_: number): void { - this.rotateArm(InputSystem.getInput(this._inputName, this._brainIndex) * this._rotationalSpeed) + applyInput = (velocity: number) => { + this._hingeDriver.targetVelocity = velocity } } diff --git a/fission/src/systems/simulation/behavior/synthesis/GenericElevatorBehavior.ts b/fission/src/systems/simulation/behavior/synthesis/GenericElevatorBehavior.ts index fb8b237d16..ceb93f813f 100644 --- a/fission/src/systems/simulation/behavior/synthesis/GenericElevatorBehavior.ts +++ b/fission/src/systems/simulation/behavior/synthesis/GenericElevatorBehavior.ts @@ -1,30 +1,31 @@ -import SliderDriver from "@/systems/simulation/driver/SliderDriver" -import SliderStimulus from "@/systems/simulation/stimulus/SliderStimulus" -import Behavior from "@/systems/simulation/behavior/Behavior" -import InputSystem from "@/systems/input/InputSystem" +import { SequentialBehaviorPreferences } from "@/systems/preferences/PreferenceTypes" +import SliderDriver from "../../driver/SliderDriver" +import SliderStimulus from "../../stimulus/SliderStimulus" +import SequenceableBehavior from "./SequenceableBehavior" -class GenericElevatorBehavior extends Behavior { +class GenericElevatorBehavior extends SequenceableBehavior { private _sliderDriver: SliderDriver - private _inputName: string - private _brainIndex: number - private _linearSpeed = 2.5 + maxVelocity = 6 - constructor(sliderDriver: SliderDriver, sliderStimulus: SliderStimulus, jointIndex: number, brainIndex: number) { - super([sliderDriver], [sliderStimulus]) - - this._sliderDriver = sliderDriver - this._inputName = "joint " + jointIndex - this._brainIndex = brainIndex + public get sliderDriver(): SliderDriver { + return this._sliderDriver } - // Changes the elevators target position - moveElevator(linearVelocity: number) { - this._sliderDriver.targetVelocity = linearVelocity + constructor( + sliderDriver: SliderDriver, + sliderStimulus: SliderStimulus, + jointIndex: number, + brainIndex: number, + sequentialConfig: SequentialBehaviorPreferences | undefined + ) { + super(jointIndex, brainIndex, [sliderDriver], [sliderStimulus], sequentialConfig) + + this._sliderDriver = sliderDriver } - public Update(_: number): void { - this.moveElevator(InputSystem.getInput(this._inputName, this._brainIndex) * this._linearSpeed) + applyInput = (velocity: number) => { + this._sliderDriver.targetVelocity = velocity } } diff --git a/fission/src/systems/simulation/behavior/synthesis/SequenceableBehavior.ts b/fission/src/systems/simulation/behavior/synthesis/SequenceableBehavior.ts new file mode 100644 index 0000000000..034765097c --- /dev/null +++ b/fission/src/systems/simulation/behavior/synthesis/SequenceableBehavior.ts @@ -0,0 +1,42 @@ +import { SequentialBehaviorPreferences } from "@/systems/preferences/PreferenceTypes" +import Driver from "../../driver/Driver" +import Stimulus from "../../stimulus/Stimulus" +import Behavior from "../Behavior" +import InputSystem from "@/systems/input/InputSystem" + +abstract class SequenceableBehavior extends Behavior { + private _jointIndex: number + private _brainIndex: number + private _sequentialConfig: SequentialBehaviorPreferences | undefined + + abstract maxVelocity: number + + public get jointIndex(): number { + return this._jointIndex + } + + constructor( + jointIndex: number, + brainIndex: number, + drivers: Driver[], + stimuli: Stimulus[], + sequentialConfig: SequentialBehaviorPreferences | undefined + ) { + super(drivers, stimuli) + + this._jointIndex = jointIndex + this._brainIndex = brainIndex + this._sequentialConfig = sequentialConfig + } + + abstract applyInput: (velocity: number) => void + + public Update(_: number): void { + const inputName = "joint " + (this._sequentialConfig?.parentJointIndex ?? this._jointIndex) + const inverted = this._sequentialConfig?.inverted ?? false + + this.applyInput(InputSystem.getInput(inputName, this._brainIndex) * this.maxVelocity * (inverted ? -1 : 1)) + } +} + +export default SequenceableBehavior diff --git a/fission/src/systems/simulation/driver/HingeDriver.ts b/fission/src/systems/simulation/driver/HingeDriver.ts index 29ab7fc6af..1558f0f4c0 100644 --- a/fission/src/systems/simulation/driver/HingeDriver.ts +++ b/fission/src/systems/simulation/driver/HingeDriver.ts @@ -11,6 +11,10 @@ class HingeDriver extends Driver { private _targetVelocity: number = 0.0 private _targetAngle: number + public get constraint(): Jolt.HingeConstraint { + return this._constraint + } + public get targetVelocity(): number { return this._targetVelocity } diff --git a/fission/src/systems/simulation/driver/SliderDriver.ts b/fission/src/systems/simulation/driver/SliderDriver.ts index dd442b38aa..9af74046e1 100644 --- a/fission/src/systems/simulation/driver/SliderDriver.ts +++ b/fission/src/systems/simulation/driver/SliderDriver.ts @@ -11,6 +11,10 @@ class SliderDriver extends Driver { private _targetVelocity: number = 0.0 private _targetPosition: number = 0.0 + public get constraint(): Jolt.SliderConstraint { + return this._constraint + } + public get targetVelocity(): number { return this._targetVelocity } diff --git a/fission/src/systems/simulation/synthesis_brain/SynthesisBrain.ts b/fission/src/systems/simulation/synthesis_brain/SynthesisBrain.ts index bdbd902102..03db0cdf2c 100644 --- a/fission/src/systems/simulation/synthesis_brain/SynthesisBrain.ts +++ b/fission/src/systems/simulation/synthesis_brain/SynthesisBrain.ts @@ -15,6 +15,7 @@ import SliderDriver from "../driver/SliderDriver" import SliderStimulus from "../stimulus/SliderStimulus" import GenericElevatorBehavior from "../behavior/synthesis/GenericElevatorBehavior" import PreferencesSystem from "@/systems/preferences/PreferencesSystem" +import { DefaultSequentialConfig } from "@/systems/preferences/PreferenceTypes" import InputSystem from "@/systems/input/InputSystem" class SynthesisBrain extends Brain { @@ -28,6 +29,17 @@ class SynthesisBrain extends Brain { // Tracks how many joins have been made with unique controls private _currentJointIndex = 1 + public get assemblyName(): string { + return this._assemblyName + } + + public get behaviors(): Behavior[] { + return this._behaviors + } + + // Tracks the number of each specific mira file spawned + public static numberRobotsSpawned: { [key: string]: number } = {} + public get inputSchemeName(): string { const scheme = InputSystem.brainIndexSchemeMap.get(this._brainIndex) if (scheme == undefined) return "Not Configured" @@ -132,8 +144,28 @@ class SynthesisBrain extends Brain { ) as HingeStimulus[] for (let i = 0; i < hingeDrivers.length; i++) { + let sequentialConfig = PreferencesSystem.getRobotPreferences(this._assemblyName).sequentialConfig?.find( + sc => sc.jointIndex == this._currentJointIndex + ) + + if (sequentialConfig == undefined) { + sequentialConfig = DefaultSequentialConfig(this._currentJointIndex, "Arm") + + if (PreferencesSystem.getRobotPreferences(this._assemblyName).sequentialConfig == undefined) + PreferencesSystem.getRobotPreferences(this._assemblyName).sequentialConfig = [] + + PreferencesSystem.getRobotPreferences(this._assemblyName).sequentialConfig?.push(sequentialConfig) + PreferencesSystem.savePreferences() + } + this._behaviors.push( - new GenericArmBehavior(hingeDrivers[i], hingeStimuli[i], this._currentJointIndex, this._brainIndex) + new GenericArmBehavior( + hingeDrivers[i], + hingeStimuli[i], + this._currentJointIndex, + this._brainIndex, + sequentialConfig + ) ) this._currentJointIndex++ } @@ -149,12 +181,27 @@ class SynthesisBrain extends Brain { ) as SliderStimulus[] for (let i = 0; i < sliderDrivers.length; i++) { + let sequentialConfig = PreferencesSystem.getRobotPreferences(this._assemblyName).sequentialConfig?.find( + sc => sc.jointIndex == this._currentJointIndex + ) + + if (sequentialConfig == undefined) { + sequentialConfig = DefaultSequentialConfig(this._currentJointIndex, "Elevator") + + if (PreferencesSystem.getRobotPreferences(this._assemblyName).sequentialConfig == undefined) + PreferencesSystem.getRobotPreferences(this._assemblyName).sequentialConfig = [] + + PreferencesSystem.getRobotPreferences(this._assemblyName).sequentialConfig?.push(sequentialConfig) + PreferencesSystem.savePreferences() + } + this._behaviors.push( new GenericElevatorBehavior( sliderDrivers[i], sliderStimuli[i], this._currentJointIndex, - this._brainIndex + this._brainIndex, + sequentialConfig ) ) this._currentJointIndex++ diff --git a/fission/src/ui/components/Checkbox.tsx b/fission/src/ui/components/Checkbox.tsx index 451891073a..6ebdd578f8 100644 --- a/fission/src/ui/components/Checkbox.tsx +++ b/fission/src/ui/components/Checkbox.tsx @@ -8,16 +8,19 @@ type CheckboxProps = { className?: string defaultState: boolean stateOverride?: boolean + hideLabel?: boolean onClick?: (checked: boolean) => void } -const Checkbox: React.FC = ({ label, className, defaultState, stateOverride, onClick }) => { +const Checkbox: React.FC = ({ label, className, defaultState, stateOverride, hideLabel, onClick }) => { const [state] = useState(defaultState) return ( - + {hideLabel ? null : ( + + )} ) => onClick && onClick(e.target.checked)} slotProps={{ diff --git a/fission/src/ui/components/MainHUD.tsx b/fission/src/ui/components/MainHUD.tsx index 47af184cbb..5c1e13a907 100644 --- a/fission/src/ui/components/MainHUD.tsx +++ b/fission/src/ui/components/MainHUD.tsx @@ -85,11 +85,6 @@ const MainHUD: React.FC = () => { onClick={() => openPanel("import-mirabuf")} />
- openModal("manage-assemblies")} - /> { icon={SynthesisIcons.MagnifyingGlass} onClick={() => openModal("view")} /> */} - openModal("change-inputs")} - /> -
-
- { - openPanel("scoring-zones") - }} - /> openModal("config-robot")} + onClick={() => openPanel("configure")} /> = ({ colorClass, size, value, pl return ( - + - ) -} - -const AssemblyCard: React.FC = ({ mira, update }) => { - const { openPanel } = usePanelControlContext() - const { closeModal } = useModalControlContext() - - const brain = useMemo(() => (mira.brain as SynthesisBrain)?.brainIndex, [mira]) - - return ( -
- -
-
-
- ) -} - -const ManageAssembliesModal: React.FC = ({ modalId }) => { - const [_, update] = useReducer(x => !x, false) - - const assemblies = [...World.SceneRenderer.sceneObjects.entries()] - .filter(x => { - const y = x[1] instanceof MirabufSceneObject - return y - }) - .map(x => x[1] as MirabufSceneObject) - - return ( - -
- - {assemblies.map(x => ( - - ))} -
-
- ) -} - -export default ManageAssembliesModal diff --git a/fission/src/ui/panels/DebugPanel.tsx b/fission/src/ui/panels/DebugPanel.tsx index 3daebda498..e94cdedd03 100644 --- a/fission/src/ui/panels/DebugPanel.tsx +++ b/fission/src/ui/panels/DebugPanel.tsx @@ -6,7 +6,11 @@ import WPILibBrain from "@/systems/simulation/wpilib_brain/WPILibBrain" import { MainHUD_AddToast } from "../components/MainHUD" import { ToastType } from "../ToastContext" import { Random } from "@/util/Random" -import MirabufCachingService, { MiraType } from "@/mirabuf/MirabufLoader" +import MirabufCachingService, { + backUpFields as hashedMiraFields, + backUpRobots as hashedMiraRobots, + MiraType, +} from "@/mirabuf/MirabufLoader" import { Box, styled } from "@mui/material" import { usePanelControlContext } from "../PanelContext" import APS from "@/aps/APS" @@ -113,6 +117,8 @@ const DebugPanel: React.FC = ({ panelId }) => { onClick={() => { console.log(MirabufCachingService.GetCacheMap(MiraType.ROBOT)) console.log(MirabufCachingService.GetCacheMap(MiraType.FIELD)) + console.log(hashedMiraRobots) + console.log(hashedMiraFields) }} /> + ) + })} +
+ {/* TODO: remove the accept button on this version */} + + ) : ( + <> +
+ v != null && setViewType(v)} + sx={{ + alignSelf: "center", + }} + > + SynthesisBrain + WIPLIBBrain + + {viewType === ConfigureRobotBrainTypes.SYNTHESIS ? ( + <> + + Behaviors + + + {GetJoints(selectedRobot)} + + ) : ( + <> + + Example WIPLIB Brain + + + + + Example 2 + + + + + Example 3 + + + + + Example 4 + + + + )} +
+ + )} + + ) +} + +export default ConfigureRobotBrainPanel diff --git a/fission/src/ui/panels/configuring/assembly-config/ConfigurePanel.tsx b/fission/src/ui/panels/configuring/assembly-config/ConfigurePanel.tsx new file mode 100644 index 0000000000..245ad48311 --- /dev/null +++ b/fission/src/ui/panels/configuring/assembly-config/ConfigurePanel.tsx @@ -0,0 +1,299 @@ +import { MiraType } from "@/mirabuf/MirabufLoader" +import MirabufSceneObject from "@/mirabuf/MirabufSceneObject" +import World from "@/systems/World" +import Label from "@/ui/components/Label" +import Panel, { PanelPropsImpl } from "@/ui/components/Panel" +import SelectMenu, { SelectMenuOption } from "@/ui/components/SelectMenu" +import { ToggleButton, ToggleButtonGroup } from "@/ui/components/ToggleButtonGroup" +import { useEffect, useMemo, useReducer, useState } from "react" +import ConfigureGamepiecePickupInterface from "./interfaces/ConfigureGamepiecePickupInterface" +import ConfigureShotTrajectoryInterface from "./interfaces/ConfigureShotTrajectoryInterface" +import ConfigureScoringZonesInterface from "./interfaces/scoring/ConfigureScoringZonesInterface" +import SequentialBehaviorsInterface from "./interfaces/SequentialBehaviorsInterface" +import ChangeInputsInterface from "./interfaces/inputs/ConfigureInputsInterface" +import InputSystem from "@/systems/input/InputSystem" +import SynthesisBrain from "@/systems/simulation/synthesis_brain/SynthesisBrain" +import { usePanelControlContext } from "@/ui/PanelContext" +import Button from "@/ui/components/Button" +import { setSelectedBrainIndexGlobal } from "../ChooseInputSchemePanel" +import ConfigureSchemeInterface from "./interfaces/inputs/ConfigureSchemeInterface" +import { SynthesisIcons } from "@/ui/components/StyledComponents" + +enum ConfigMode { + INTAKE, + EJECTOR, + MOTORS, + CONTROLS, + SCORING_ZONES, +} + +// eslint-disable-next-line react-refresh/only-export-components +export enum ConfigurationType { + ROBOT, + FIELD, + INPUTS, +} + +let selectedConfigurationType: ConfigurationType = ConfigurationType.ROBOT +// eslint-disable-next-line react-refresh/only-export-components +export function setSelectedConfigurationType(type: ConfigurationType) { + selectedConfigurationType = type +} + +function getConfigurationType() { + return selectedConfigurationType +} + +/** Option for selecting a robot of field */ +class AssemblySelectionOption extends SelectMenuOption { + assemblyObject: MirabufSceneObject + + constructor(name: string, assemblyObject: MirabufSceneObject) { + super(name) + this.assemblyObject = assemblyObject + } +} + +interface ConfigurationSelectionProps { + configurationType: ConfigurationType + onAssemblySelected: (assembly: MirabufSceneObject | undefined) => void +} + +const AssemblySelection: React.FC = ({ configurationType, onAssemblySelected }) => { + // Update is used when a robot or field is deleted to update the select menu + const [u, update] = useReducer(x => !x, false) + const { openPanel } = usePanelControlContext() + + const robots = useMemo(() => { + const assemblies = [...World.SceneRenderer.sceneObjects.values()].filter(x => { + if (x instanceof MirabufSceneObject) { + return x.miraType === MiraType.ROBOT + } + return false + }) as MirabufSceneObject[] + + return assemblies + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [u]) + + const fields = useMemo(() => { + const assemblies = [...World.SceneRenderer.sceneObjects.values()].filter(x => { + if (x instanceof MirabufSceneObject) { + return x.miraType === MiraType.FIELD + } + return false + }) as MirabufSceneObject[] + + return assemblies + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [u]) + + /** Robot or field select menu */ + return ( + { + return new AssemblySelectionOption( + `${configurationType == ConfigurationType.ROBOT ? `[${InputSystem.brainIndexSchemeMap.get((assembly.brain as SynthesisBrain).brainIndex)?.schemeName ?? "-"}]` : ""} ${assembly.assemblyName}`, + assembly + ) + })} + onOptionSelected={val => { + onAssemblySelected((val as AssemblySelectionOption)?.assemblyObject) + }} + defaultHeaderText={`Select a ${configurationType == ConfigurationType.ROBOT ? "Robot" : "Field"}`} + onDelete={val => { + World.SceneRenderer.RemoveSceneObject((val as AssemblySelectionOption).assemblyObject.id) + onAssemblySelected(undefined) + update() + }} + onAddClicked={() => { + openPanel("import-mirabuf") + }} + noOptionsText={`No ${configurationType == ConfigurationType.ROBOT ? "robots" : "fields"} spawned!`} + /> + ) +} + +class ConfigModeSelectionOption extends SelectMenuOption { + configMode: ConfigMode + + constructor(name: string, configMode: ConfigMode) { + super(name) + this.configMode = configMode + } +} + +const robotModes = [ + new ConfigModeSelectionOption("Intake", ConfigMode.INTAKE), + new ConfigModeSelectionOption("Ejector", ConfigMode.EJECTOR), + new ConfigModeSelectionOption("Sequential Joints", ConfigMode.MOTORS), + new ConfigModeSelectionOption("Controls", ConfigMode.CONTROLS), +] +const fieldModes = [new ConfigModeSelectionOption("Scoring Zones", ConfigMode.SCORING_ZONES)] + +interface ConfigModeSelectionProps { + configurationType: ConfigurationType + onModeSelected: (mode: ConfigMode | undefined) => void +} + +const ConfigModeSelection: React.FC = ({ configurationType, onModeSelected }) => { + return ( + { + onModeSelected((val as ConfigModeSelectionOption)?.configMode) + }} + defaultHeaderText="Select a Configuration Mode" + indentation={1} + /> + ) +} + +interface ConfigInterfaceProps { + configMode: ConfigMode + assembly: MirabufSceneObject + openPanel: (panelId: string) => void +} + +/** The interface for the actual configuration */ +const ConfigInterface: React.FC = ({ configMode, assembly, openPanel }) => { + switch (configMode) { + case ConfigMode.INTAKE: + return + case ConfigMode.EJECTOR: + return + case ConfigMode.MOTORS: + return + case ConfigMode.CONTROLS: { + const brainIndex = (assembly.brain as SynthesisBrain).brainIndex + const scheme = InputSystem.brainIndexSchemeMap.get(brainIndex) + + return ( + <> + - ) - })} - - {/* TODO: remove the accept button on this version */} - - ) : ( - <> - {/* Button for user to select the parent node */} - trySetSelectedNode(body.GetID())} - /> - - {/* Slider for user to set velocity of ejector configuration */} - { - setZoneSize(vel as number) - }} - step={0.01} - /> - { - if (transformGizmo) { - const robotTransformation = JoltMat44_ThreeMatrix4( - World.PhysicsSystem.GetBody(selectedRobot.GetRootNodeId()!).GetWorldTransform() - ) - transformGizmo.mesh.position.setFromMatrixPosition(robotTransformation) - transformGizmo.mesh.rotation.setFromRotationMatrix(robotTransformation) - } - setZoneSize((MIN_ZONE_SIZE + MAX_ZONE_SIZE) / 2.0) - setSelectedNode(selectedRobot?.rootNodeId) - }} - /> - - )} - + <> + {/* Button for user to select the parent node */} + trySetSelectedNode(body.GetID())} + /> + + {/* Slider for user to set velocity of ejector configuration */} + { + setZoneSize(vel as number) + }} + step={0.01} + /> + {Spacer(10)} + - ) - })} - - {/* TODO: remove the accept button on this version */} - - ) : ( - <> - {/* Button for user to select the parent node */} - trySetSelectedNode(body.GetID())} - /> - - {/* Slider for user to set velocity of ejector configuration */} - { - setEjectorVelocity(vel as number) - }} - step={0.01} - /> - { - if (transformGizmo) { - const robotTransformation = JoltMat44_ThreeMatrix4( - World.PhysicsSystem.GetBody(selectedRobot.GetRootNodeId()!).GetWorldTransform() - ) - transformGizmo.mesh.position.setFromMatrixPosition(robotTransformation) - transformGizmo.mesh.rotation.setFromRotationMatrix(robotTransformation) - } - setEjectorVelocity((MIN_VELOCITY + MAX_VELOCITY) / 2.0) - setSelectedNode(selectedRobot?.rootNodeId) - }} - /> - - )} - + <> + {/* Button for user to select the parent node */} + trySetSelectedNode(body.GetID())} + /> + + {/* Slider for user to set velocity of ejector configuration */} + { + setEjectorVelocity(vel as number) + }} + step={0.01} + /> + {Spacer(10)} + - ) - })} - - - ) : ( - <> - {zones?.length > 0 ? ( - - {zones.map((zonePrefs: ScoringZonePreferences, i: number) => ( - { - return zonePrefs - })()} - field={selectedField} - openPanel={openPanel} - save={() => saveZones(zones, selectedField)} - deleteZone={() => { - setZones(zones.filter((_, idx) => idx !== i)) - saveZones( - zones.filter((_, idx) => idx !== i), - selectedField - ) - }} - /> - ))} - - ) : ( - - )} -