Skip to content

Commit dfd844f

Browse files
Merge remote-tracking branch 'origin/dev' into ryan/1973/animate-game-piece-intake
2 parents bc8a88e + 7e9089c commit dfd844f

18 files changed

+1394
-48
lines changed

fission/src/mirabuf/FieldMiraEditor.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { mirabuf } from "../proto/mirabuf"
2+
import { ScoringZonePreferences } from "@/systems/preferences/PreferenceTypes"
23

34
interface DevtoolMiraData {
4-
"devtool:scoring_zones": unknown
5+
"devtool:scoring_zones": ScoringZonePreferences[]
56
"devtool:camera_locations": unknown
67
"devtool:spawn_points": unknown
78
"devtool:a": unknown

fission/src/mirabuf/MirabufLoader.ts

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,49 @@ class MirabufCachingService {
241241
}
242242
}
243243

244+
/**
245+
* Caches and gets local Mirabuf file with cache info
246+
*
247+
* @param {ArrayBuffer} buffer ArrayBuffer of Mirabuf file.
248+
* @param {MiraType} miraType Type of Mirabuf Assembly.
249+
*
250+
* @returns {Promise<{assembly: mirabuf.Assembly, cacheInfo: MirabufCacheInfo} | undefined>} Promise with the result of the promise. Assembly and cache info of the mirabuf file if successful, undefined if not.
251+
*/
252+
public static async cacheAndGetLocalWithInfo(
253+
buffer: ArrayBuffer,
254+
miraType: MiraType
255+
): Promise<{ assembly: mirabuf.Assembly; cacheInfo: MirabufCacheInfo } | undefined> {
256+
const key = await this.hashBuffer(buffer)
257+
const map = MirabufCachingService.getCacheMap(miraType)
258+
const target = map[key]
259+
const assembly = this.assemblyFromBuffer(buffer)
260+
261+
// Check if assembly has devtool data and update name accordingly
262+
let displayName = assembly.info?.name ?? undefined
263+
if (assembly.data?.parts?.userData?.data) {
264+
const devtoolKeys = Object.keys(assembly.data.parts.userData.data).filter(k => k.startsWith("devtool:"))
265+
if (devtoolKeys.length > 0) {
266+
displayName = displayName ? `Edited ${displayName}` : "Edited Field"
267+
}
268+
}
269+
270+
if (!target) {
271+
const cacheInfo = await MirabufCachingService.storeInCache(key, buffer, miraType, displayName)
272+
if (cacheInfo) {
273+
return { assembly, cacheInfo }
274+
}
275+
} else {
276+
// Update existing cache info with new name if it has devtool data
277+
if (displayName && displayName !== target.name) {
278+
await MirabufCachingService.cacheInfo(key, miraType, displayName)
279+
target.name = displayName
280+
}
281+
return { assembly, cacheInfo: target }
282+
}
283+
284+
return undefined
285+
}
286+
244287
/**
245288
* Caches and gets local Mirabuf file
246289
*
@@ -258,8 +301,17 @@ class MirabufCachingService {
258301
const target = map[key]
259302
const assembly = this.assemblyFromBuffer(buffer)
260303

304+
// Check if assembly has devtool data and update name accordingly
305+
let displayName = assembly.info?.name ?? undefined
306+
if (assembly.data?.parts?.userData?.data) {
307+
const devtoolKeys = Object.keys(assembly.data.parts.userData.data).filter(k => k.startsWith("devtool:"))
308+
if (devtoolKeys.length > 0) {
309+
displayName = displayName ? `Edited ${displayName}` : "Edited Field"
310+
}
311+
}
312+
261313
if (!target) {
262-
await MirabufCachingService.storeInCache(key, buffer, miraType, assembly.info?.name ?? undefined)
314+
await MirabufCachingService.storeInCache(key, buffer, miraType, displayName)
263315
}
264316

265317
return assembly
@@ -369,6 +421,55 @@ class MirabufCachingService {
369421
backUpFields = {}
370422
}
371423

424+
/**
425+
* Persists devtool changes back to the cache by re-encoding the assembly
426+
*
427+
* @param {MirabufCacheID} id ID of the cached mirabuf file
428+
* @param {MiraType} miraType Type of Mirabuf Assembly
429+
* @param {mirabuf.Assembly} assembly The updated assembly with devtool changes
430+
*
431+
* @returns {Promise<boolean>} Promise with the result. True if successful, false if not.
432+
*/
433+
public static async persistDevtoolChanges(
434+
id: MirabufCacheID,
435+
miraType: MiraType,
436+
assembly: mirabuf.Assembly
437+
): Promise<boolean> {
438+
try {
439+
// Re-encode the assembly with devtool changes
440+
const updatedBuffer = mirabuf.Assembly.encode(assembly).finish()
441+
442+
// Update the cached buffer
443+
const cache = miraType == MiraType.ROBOT ? backUpRobots : backUpFields
444+
if (cache[id]) {
445+
cache[id].buffer = updatedBuffer
446+
}
447+
448+
// Update OPFS if available
449+
if (canOPFS) {
450+
const fileHandle = await (
451+
miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle
452+
).getFileHandle(id, { create: false })
453+
const writable = await fileHandle.createWritable()
454+
await writable.write(updatedBuffer)
455+
await writable.close()
456+
}
457+
458+
World.analyticsSystem?.event("Devtool Cache Persist", {
459+
key: id,
460+
type: miraType == MiraType.ROBOT ? "robot" : "field",
461+
assemblyName: assembly.info?.name ?? "unknown",
462+
fileSize: updatedBuffer.byteLength,
463+
})
464+
465+
return true
466+
} catch (e) {
467+
console.error("Failed to persist devtool changes", e)
468+
World.analyticsSystem?.exception("Failed to persist devtool changes to cache")
469+
return false
470+
}
471+
}
472+
372473
// Optional name for when assembly is being decoded anyway like in CacheAndGetLocal()
373474
private static async storeInCache(
374475
key: string,

fission/src/mirabuf/MirabufSceneObject.ts

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { BodyAssociate, LayerReserve } from "@/systems/physics/PhysicsSystem"
1111
import Mechanism from "@/systems/physics/Mechanism"
1212
import {
1313
Alliance,
14+
Station,
1415
EjectorPreferences,
1516
FieldPreferences,
1617
IntakePreferences,
@@ -42,6 +43,7 @@ import {
4243
import { SimConfigData } from "@/ui/panels/simulation/SimConfigShared"
4344
import WPILibBrain from "@/systems/simulation/wpilib_brain/WPILibBrain"
4445
import { OnContactAddedEvent } from "@/systems/physics/ContactEvents"
46+
import FieldMiraEditor from "./FieldMiraEditor"
4547

4648
const DEBUG_BODIES = false
4749

@@ -73,6 +75,7 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
7375
private _mechanism: Mechanism
7476
private _brain: Brain | undefined
7577
private _alliance: Alliance | undefined
78+
private _station: Station | undefined
7679

7780
private _debugBodies: Map<string, RnDebugMeshes> | null
7881
private _physicsLayerReserve: LayerReserve | undefined
@@ -90,14 +93,14 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
9093

9194
private _nameTag: SceneOverlayTag | undefined
9295
private _centerOfMassIndicator: THREE.Mesh | undefined
93-
private _centerOfMassListenerUnsubscribe: (() => void) | undefined
9496
private _intakeActive = false
9597
private _ejectorActive = false
9698

9799
private _lastEjectableToastTime = 0
98100
private static readonly EJECTABLE_TOAST_COOLDOWN_MS = 500
99101

100102
private _collision?: (event: OnContactAddedEvent) => void
103+
private _cacheId?: string
101104

102105
public get intakeActive() {
103106
return this._intakeActive
@@ -145,7 +148,7 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
145148
}
146149

147150
public get activeEjectables(): Jolt.BodyID[] {
148-
return this._ejectables.map(e => e.gamePieceBodyId!)
151+
return this._ejectables.map(e => e.gamePieceBodyId!).filter(x => x !== undefined)
149152
}
150153

151154
public get miraType(): MiraType {
@@ -164,6 +167,10 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
164167
return this._alliance
165168
}
166169

170+
public get station() {
171+
return this._station
172+
}
173+
167174
public set brain(brain: Brain | undefined) {
168175
this._brain = brain
169176
const simLayer = World.simulationSystem.getSimulationLayer(this._mechanism)!
@@ -174,11 +181,25 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
174181
this._alliance = alliance
175182
}
176183

177-
public constructor(mirabufInstance: MirabufInstance, assemblyName: string, progressHandle?: ProgressHandle) {
184+
public set station(station: Station | undefined) {
185+
this._station = station
186+
}
187+
188+
public get cacheId() {
189+
return this._cacheId
190+
}
191+
192+
public constructor(
193+
mirabufInstance: MirabufInstance,
194+
assemblyName: string,
195+
progressHandle?: ProgressHandle,
196+
cacheId?: string
197+
) {
178198
super()
179199

180200
this._mirabufInstance = mirabufInstance
181201
this._assemblyName = assemblyName
202+
this._cacheId = cacheId
182203

183204
progressHandle?.update("Creating mechanism...", 0.9)
184205

@@ -221,18 +242,8 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
221242
})
222243
material.depthTest = false
223244
this._centerOfMassIndicator = new THREE.Mesh(new THREE.SphereGeometry(0.02), material)
224-
this._centerOfMassIndicator.visible = PreferencesSystem.getGlobalPreference("ShowCenterOfMassIndicators")
225-
245+
this._centerOfMassIndicator.visible = false
226246
World.sceneRenderer.scene.add(this._centerOfMassIndicator)
227-
228-
this._centerOfMassListenerUnsubscribe = PreferencesSystem.addPreferenceEventListener(
229-
"ShowCenterOfMassIndicators",
230-
e => {
231-
if (this._centerOfMassIndicator) {
232-
this._centerOfMassIndicator.visible = e.prefValue
233-
}
234-
}
235-
)
236247
}
237248
}
238249

@@ -353,13 +364,14 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
353364
})
354365
this._debugBodies?.clear()
355366
this._physicsLayerReserve?.release()
356-
this._centerOfMassIndicator?.geometry?.dispose()
367+
if (this._centerOfMassIndicator) {
368+
World.sceneRenderer.scene.remove(this._centerOfMassIndicator)
369+
this._centerOfMassIndicator = undefined
370+
}
371+
357372
if (this._brain && this._brain instanceof SynthesisBrain) {
358373
this._brain.clearControls()
359374
}
360-
if (this._centerOfMassListenerUnsubscribe) {
361-
this._centerOfMassListenerUnsubscribe()
362-
}
363375
}
364376

365377
public eject() {
@@ -453,6 +465,7 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
453465
if (this._centerOfMassIndicator) {
454466
const netCoM = totalMass > 0 ? weightedCOM.Div(totalMass) : weightedCOM
455467
this._centerOfMassIndicator.position.set(netCoM.GetX(), netCoM.GetY(), netCoM.GetZ())
468+
this._centerOfMassIndicator.visible = PreferencesSystem.getGlobalPreference("ShowCenterOfMassIndicators")
456469
}
457470
}
458471

@@ -660,6 +673,21 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
660673
}
661674

662675
this._fieldPreferences = PreferencesSystem.getFieldPreferences(this.assemblyName)
676+
677+
// For fields, sync devtool data with field preferences
678+
if (this.miraType === MiraType.FIELD) {
679+
const parts = this._mirabufInstance.parser.assembly.data?.parts
680+
if (parts) {
681+
const editor = new FieldMiraEditor(parts)
682+
const devtoolScoringZones = editor.getUserData("devtool:scoring_zones")
683+
684+
if (devtoolScoringZones && Array.isArray(devtoolScoringZones)) {
685+
this._fieldPreferences.scoringZones = devtoolScoringZones
686+
PreferencesSystem.setFieldPreferences(this.assemblyName, this._fieldPreferences)
687+
PreferencesSystem.savePreferences()
688+
}
689+
}
690+
}
663691
}
664692

665693
public updateSimConfig(config: SimConfigData | undefined) {
@@ -792,15 +820,16 @@ class MirabufSceneObject extends SceneObject implements ContextSupplier {
792820

793821
export async function createMirabuf(
794822
assembly: mirabuf.Assembly,
795-
progressHandle?: ProgressHandle
823+
progressHandle?: ProgressHandle,
824+
cacheId?: string
796825
): Promise<MirabufSceneObject | null | undefined> {
797826
const parser = new MirabufParser(assembly, progressHandle)
798827
if (parser.maxErrorSeverity >= ParseErrorSeverity.UNIMPORTABLE) {
799828
console.error(`Assembly Parser produced significant errors for '${assembly.info!.name!}'`)
800829
return
801830
}
802831

803-
return new MirabufSceneObject(new MirabufInstance(parser), assembly.info!.name!, progressHandle)
832+
return new MirabufSceneObject(new MirabufInstance(parser), assembly.info!.name!, progressHandle, cacheId)
804833
}
805834

806835
/**

fission/src/systems/preferences/PreferenceTypes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ export type MotorPreferences = {
141141

142142
export type Alliance = "red" | "blue"
143143

144+
export type Station = 1 | 2 | 3
145+
144146
export type ScoringZonePreferences = {
145147
name: string
146148
alliance: Alliance

0 commit comments

Comments
 (0)