Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions fission/src/mirabuf/FieldMiraEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { mirabuf } from "@/proto/mirabuf"
import {
defaultFieldPreferences,
type FieldPreferences,
type ProtectedZonePreferences,
type ScoringZonePreferences,
} from "@/systems/preferences/PreferenceTypes"

export interface DevtoolMiraData {
"devtool:scoring_zones": ScoringZonePreferences[]
"devtool:protected_zones": ProtectedZonePreferences[]
"devtool:camera_locations": unknown
"devtool:spawn_locations": FieldPreferences["spawnLocations"]
"devtool:a": unknown
Expand Down
18 changes: 9 additions & 9 deletions fission/src/systems/preferences/PreferenceTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,26 +147,26 @@ export type Alliance = "red" | "blue"

export type Station = 1 | 2 | 3

export type ScoringZonePreferences = {
/**
* Base properties shared by all zone types
*/
export type BaseZonePreferences = {
name: string
alliance: Alliance
parentNode: string | undefined
deltaTransformation: number[]
}

export type ScoringZonePreferences = BaseZonePreferences & {
points: number
destroyGamepiece: boolean
persistentPoints: boolean

deltaTransformation: number[]
}

export type ProtectedZonePreferences = {
name: string
alliance: Alliance
export type ProtectedZonePreferences = BaseZonePreferences & {
penaltyPoints: number
parentNode: string | undefined
contactType: ContactType
activeDuring: MatchModeType[]

deltaTransformation: number[]
}

export type SpawnLocation = Readonly<{
Expand Down
91 changes: 91 additions & 0 deletions fission/src/ui/modals/DevtoolZoneModificationModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Stack, Typography } from "@mui/material"
import type React from "react"
import { useState } from "react"
import { globalAddToast } from "../components/GlobalUIControls"

interface DevtoolZoneModificationModalProps {
isOpen: boolean
onClose: () => void
zoneType: "scoring" | "protected"
zoneName: string
onTemporaryModification: () => void
onPermanentModification: () => void
}

const DevtoolZoneModificationModal: React.FC<DevtoolZoneModificationModalProps> = ({
isOpen,
onClose,
zoneType,
zoneName,
onTemporaryModification,
onPermanentModification,
}) => {
const [isModifying, setIsModifying] = useState(false)

const handleTemporaryModification = () => {
onTemporaryModification()
onClose()
}

const handlePermanentModification = async () => {
setIsModifying(true)
try {
await onPermanentModification()
globalAddToast?.("info", "Zone Modified", `${zoneName} has been permanently modified in the field file.`)
} catch (error) {
globalAddToast?.(
"error",
"Modification Failed",
"Failed to permanently modify zone in the field file cache."
)
console.error("Failed to modify zone in field file:", error)
} finally {
setIsModifying(false)
onClose()
}
}

return (
<Dialog open={isOpen} onClose={onClose} maxWidth="sm" fullWidth>
<DialogTitle>Modify {zoneType === "scoring" ? "Scoring" : "Protected"} Zone</DialogTitle>
<DialogContent>
<Stack spacing={2}>
<Typography variant="body1">
The {zoneType} zone "{zoneName}" was defined in the field file and is cached.
</Typography>
<Typography variant="body2" color="text.secondary">
Choose how you'd like to save your modifications:
</Typography>
<Stack spacing={1}>
<Typography variant="body2">
<strong>Temporary modification:</strong> Save changes until next field reload. Original zone
will reappear when you refresh the page.
</Typography>
<Typography variant="body2">
<strong>Permanent modification:</strong> Save changes to the local asset file. This will
persist your modifications until you remove it from the cache.
</Typography>
</Stack>
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={onClose} disabled={isModifying}>
Cancel
</Button>
<Button onClick={handleTemporaryModification} disabled={isModifying} variant="outlined" color="warning">
Temporary Modification
</Button>
<Button
onClick={handlePermanentModification}
disabled={isModifying}
variant="contained"
color="primary"
>
{isModifying ? "Modifying..." : "Permanent Modification"}
</Button>
</DialogActions>
</Dialog>
)
}

export default DevtoolZoneModificationModal
17 changes: 12 additions & 5 deletions fission/src/ui/panels/DeveloperToolPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ const DeveloperToolPanel: React.FC<PanelImplProps<void, void>> = ({ panel }) =>
if (parts) {
const newEditor = new FieldMiraEditor(parts)
setEditor(newEditor)
setKeys(newEditor.getAllDevtoolKeys())
setKeys(
newEditor
.getAllDevtoolKeys()
.filter(k => Object.prototype.hasOwnProperty.call(devtoolHandlers, k))
)
setFieldLoaded(true)
} else {
setEditor(undefined)
Expand All @@ -50,7 +54,9 @@ const DeveloperToolPanel: React.FC<PanelImplProps<void, void>> = ({ panel }) =>
setJsonValue("")
setError("")
} else if (currentField && editor) {
setKeys(editor.getAllDevtoolKeys())
setKeys(
editor.getAllDevtoolKeys().filter(k => Object.prototype.hasOwnProperty.call(devtoolHandlers, k))
)
}
}
const allKeys = editor?.getAllDevtoolKeys()
Expand All @@ -64,7 +70,8 @@ const DeveloperToolPanel: React.FC<PanelImplProps<void, void>> = ({ panel }) =>
// Load value when key changes
useEffect(() => {
const field = World.sceneRenderer.mirabufSceneObjects.getField()
if (!editor || !field || !selectedKey) return
if (!editor || !field || !selectedKey || !Object.prototype.hasOwnProperty.call(devtoolHandlers, selectedKey))
return

const val = devtoolHandlers[selectedKey].get(field)
editor.setUserData(selectedKey, val)
Expand All @@ -83,7 +90,7 @@ const DeveloperToolPanel: React.FC<PanelImplProps<void, void>> = ({ panel }) =>
}
editor.setUserData(selectedKey, parsed)

setKeys(editor.getAllDevtoolKeys())
setKeys(editor.getAllDevtoolKeys().filter(k => Object.prototype.hasOwnProperty.call(devtoolHandlers, k)))

// Persist changes to cache
const field = World.sceneRenderer.mirabufSceneObjects.getField()
Expand Down Expand Up @@ -127,7 +134,7 @@ const DeveloperToolPanel: React.FC<PanelImplProps<void, void>> = ({ panel }) =>
const handleRemove = () => {
if (!editor || !selectedKey) return
editor.removeUserData(selectedKey)
setKeys(editor.getAllDevtoolKeys())
setKeys(editor.getAllDevtoolKeys().filter(k => Object.prototype.hasOwnProperty.call(devtoolHandlers, k)))
setSelectedKey(undefined)
setJsonValue("")
setError("")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import World from "@/systems/World"
import Label from "@/ui/components/Label"
import type { PanelImplProps } from "@/ui/components/Panel"
import TransformGizmoControl from "@/ui/components/TransformGizmoControl"
import { CloseType, type UIScreen, useUIContext } from "@/ui/helpers/UIProviderHelpers"
import { CloseType, type Panel, type UIScreen, useUIContext } from "@/ui/helpers/UIProviderHelpers"
import ChooseInputSchemePanel from "../ChooseInputSchemePanel"
import { CONFIG_OPTS, ConfigMode, type ConfigurationType } from "./ConfigTypes"
import AssemblySelection, { type AssemblySelectionOption } from "./configure/AssemblySelection"
Expand Down Expand Up @@ -79,7 +79,13 @@ const ConfigInterface: React.FC<ConfigInterfaceProps<void, ConfigurePanelCustomP
console.error("Field does not contain scoring zone preferences!")
return <Label size="md">ERROR: Field does not contain scoring zone configuration!</Label>
}
return <ConfigureScoringZonesInterface selectedField={assembly} initialZones={zones} />
return (
<ConfigureScoringZonesInterface
panel={panel as Panel<any, any>}
selectedField={assembly}
initialZones={zones}
/>
)
}
case ConfigMode.PROTECTED_ZONES: {
const zones = assembly.fieldPreferences?.protectedZones ?? []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type MirabufSceneObject from "@/mirabuf/MirabufSceneObject"
import PreferencesSystem from "@/systems/preferences/PreferencesSystem"
import type { ProtectedZonePreferences } from "@/systems/preferences/PreferenceTypes"
import Label from "@/ui/components/Label"
import type { Panel } from "@/ui/helpers/UIProviderHelpers"
import ManageProtectedZonesInterface from "./ManageProtectedZonesInterface"
import ZoneConfigInterface from "./ProtectedZoneConfigInterface"

Expand All @@ -21,9 +22,10 @@ const protectedZones = (zones: ProtectedZonePreferences[] | undefined, field: Mi
interface ConfigureZonesProps {
selectedField: MirabufSceneObject
initialZones: ProtectedZonePreferences[]
panel?: Panel<any, any>
}

const ConfigureProtectedZonesInterface: React.FC<ConfigureZonesProps> = ({ selectedField, initialZones }) => {
const ConfigureProtectedZonesInterface: React.FC<ConfigureZonesProps> = ({ selectedField, initialZones, panel }) => {
const [selectedZone, setSelectedZone] = useState<ProtectedZonePreferences | undefined>(undefined)

return (
Expand All @@ -33,6 +35,7 @@ const ConfigureProtectedZonesInterface: React.FC<ConfigureZonesProps> = ({ selec
selectedField={selectedField}
initialZones={initialZones}
selectZone={setSelectedZone}
panel={panel}
/>
) : (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ const saveZones = (zones: ScoringZonePreferences[] | undefined, field: MirabufSc
field.updateScoringZones()
}

import type { Panel } from "@/ui/helpers/UIProviderHelpers"

interface ConfigureZonesProps {
selectedField: MirabufSceneObject
initialZones: ScoringZonePreferences[]
panel?: Panel<any, any>
}

const ConfigureScoringZonesInterface: React.FC<ConfigureZonesProps> = ({ selectedField, initialZones }) => {
const ConfigureScoringZonesInterface: React.FC<ConfigureZonesProps> = ({ selectedField, initialZones, panel }) => {
const [selectedZone, setSelectedZone] = useState<ScoringZonePreferences | undefined>(undefined)

return (
Expand All @@ -36,6 +39,7 @@ const ConfigureScoringZonesInterface: React.FC<ConfigureZonesProps> = ({ selecte
selectedField={selectedField}
initialZones={initialZones}
selectZone={setSelectedZone}
panel={panel}
/>
) : (
<>
Expand Down Expand Up @@ -66,6 +70,7 @@ const ConfigureScoringZonesInterface: React.FC<ConfigureZonesProps> = ({ selecte
saveAllZones={() => {
saveZones(selectedField.fieldPreferences?.scoringZones, selectedField)
}}
panel={panel}
/>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import World from "@/systems/World"
import Label from "@/ui/components/Label"
import ScrollView from "@/ui/components/ScrollView"
import { AddButton, DeleteButton, EditButton } from "@/ui/components/StyledComponents"
import type { Panel } from "@/ui/helpers/UIProviderHelpers"
import { useUIContext } from "@/ui/helpers/UIProviderHelpers"

const saveZones = (zones: ProtectedZonePreferences[] | undefined, field: MirabufSceneObject | undefined) => {
if (!zones || !field) return
Expand Down Expand Up @@ -59,11 +61,21 @@ interface ProtectedZonesProps {
selectedField: MirabufSceneObject
initialZones: ProtectedZonePreferences[]
selectZone: (zone: ProtectedZonePreferences) => void
panel?: Panel<any, any>
}

const ManageZonesInterface: React.FC<ProtectedZonesProps> = ({ selectedField, initialZones, selectZone }) => {
const ManageZonesInterface: React.FC<ProtectedZonesProps> = ({ selectedField, initialZones, selectZone, panel }) => {
const [zones, setZones] = useState<ProtectedZonePreferences[]>(initialZones)

const { configureScreen } = useUIContext()

// Show the panel's default footer buttons when this interface is active
useEffect(() => {
if (panel) {
configureScreen(panel, { hideAccept: false, hideCancel: false }, {})
}
}, [panel, configureScreen])

const saveEvent = useCallback(() => {
saveZones(zones, selectedField)
}, [zones, selectedField])
Expand Down
Loading
Loading