Skip to content

Commit cc0ee2a

Browse files
committed
Merge branch 'dev' into alexey/2054/button-sounds-fix
2 parents e6a306a + 669dd92 commit cc0ee2a

35 files changed

+861
-457
lines changed

.github/workflows/FissionBuild.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,8 @@ jobs:
3535
run: |
3636
cd fission
3737
bun run build && echo "Build Passed" || (echo "Build Failed" && exit 1)
38+
39+
- name: Build Electron Version of Fission
40+
run: |
41+
cd fission
42+
bun run electron:make && echo "Build Passed" || (echo "Build Failed" && exit 1)
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
import { defineConfig, mergeConfig } from "vite"
1+
import { defineConfig, mergeConfig, type UserConfig } from "vite"
22
import baseConfig from "../vite.config"
33

44
// https://vitejs.dev/config
5-
export default defineConfig((env) => mergeConfig(baseConfig(env), {}))
5+
export default defineConfig(async (env) => {
6+
const base = typeof baseConfig === 'function' ? await baseConfig(env) : baseConfig
7+
return mergeConfig(base, {} as UserConfig)
8+
})

fission/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"style": "bun run fmt && bun run lint",
2323
"style:fix": "bun run fmt:fix && bun run lint:fix",
2424
"assetpack": "git lfs pull && tar -xf public/assetpack.zip -C public/",
25+
"assetpack:update": "cd public && zip -FS -r assetpack.zip Downloadables",
2526
"playwright:install": "bun x playwright install",
2627
"electron:start": "electron-forge start",
2728
"electron:package": "electron-forge package",

fission/public/assetpack.zip

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:985ef0918d3b8200fc076cc31d9af0199b08586e45fda4ecc716555a01660fee
3-
size 193149510
2+
oid sha256:23bfaf7899d84b00331c12bf1ada20d27d3c50856b14bb5733821b44848812ba
3+
size 193147860

fission/src/mirabuf/FieldMiraEditor.ts

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
import type { ScoringZonePreferences } from "@/systems/preferences/PreferenceTypes"
2-
import { mirabuf } from "../proto/mirabuf"
1+
import type MirabufSceneObject from "@/mirabuf/MirabufSceneObject.ts"
2+
import { mirabuf } from "@/proto/mirabuf"
3+
import {
4+
defaultFieldPreferences,
5+
type FieldPreferences,
6+
type ScoringZonePreferences,
7+
} from "@/systems/preferences/PreferenceTypes"
38

4-
interface DevtoolMiraData {
9+
export interface DevtoolMiraData {
510
"devtool:scoring_zones": ScoringZonePreferences[]
611
"devtool:camera_locations": unknown
7-
"devtool:spawn_points": unknown
12+
"devtool:spawn_locations": FieldPreferences["spawnLocations"]
813
"devtool:a": unknown
914
"devtool:b": unknown
1015
"devtool:test": unknown
@@ -15,6 +20,87 @@ interface DevtoolMiraData {
1520
// additional devtool keys to be added in future
1621
}
1722

23+
export const devtoolHandlers = {
24+
"devtool:scoring_zones": {
25+
get(field) {
26+
return field.fieldPreferences?.scoringZones ?? defaultFieldPreferences().scoringZones
27+
},
28+
set(field, val) {
29+
val ??= defaultFieldPreferences().scoringZones
30+
if (!field.fieldPreferences || !this.validate(val)) {
31+
console.warn("validation failed", val, field.fieldPreferences)
32+
return
33+
}
34+
field.fieldPreferences.scoringZones = val
35+
field.updateScoringZones()
36+
},
37+
validate(val): val is ScoringZonePreferences[] {
38+
if (!Array.isArray(val)) return false
39+
return val.every(
40+
z =>
41+
typeof z === "object" &&
42+
z !== null &&
43+
typeof z.name === "string" &&
44+
(z.alliance === "red" || z.alliance === "blue") &&
45+
(typeof z.parentNode === "string" || z.parentNode === undefined) &&
46+
typeof z.points === "number" &&
47+
typeof z.destroyGamepiece === "boolean" &&
48+
typeof z.persistentPoints === "boolean" &&
49+
Array.isArray(z.deltaTransformation)
50+
)
51+
},
52+
},
53+
"devtool:spawn_locations": {
54+
get(field) {
55+
return field.fieldPreferences?.spawnLocations ?? defaultFieldPreferences().spawnLocations
56+
},
57+
set(field, val) {
58+
val ??= defaultFieldPreferences().spawnLocations
59+
if (!field.fieldPreferences || !this.validate(val)) {
60+
console.warn("validation failed", val, field.fieldPreferences)
61+
return
62+
}
63+
field.fieldPreferences.spawnLocations = val
64+
},
65+
validate(val: unknown): val is FieldPreferences["spawnLocations"] {
66+
const isStructureCorrect =
67+
typeof val === "object" &&
68+
val != null &&
69+
"red" in val &&
70+
"blue" in val &&
71+
"default" in val &&
72+
"hasConfiguredLocations" in val
73+
74+
if (!isStructureCorrect) return false
75+
return (["red", "blue"] as const).every(v => {
76+
const obj = val[v]
77+
if (!(typeof obj === "object" && obj != null && 1 in obj && 2 in obj && 3 in obj)) return false
78+
return ([1, 2, 3] as const).every(v => {
79+
const spawnposition = obj[v]
80+
return (
81+
typeof spawnposition == "object" &&
82+
spawnposition != null &&
83+
"pos" in spawnposition &&
84+
"yaw" in spawnposition &&
85+
Array.isArray(spawnposition["pos"]) &&
86+
spawnposition["pos"].length == 3 &&
87+
typeof spawnposition["yaw"] == "number"
88+
)
89+
})
90+
})
91+
},
92+
},
93+
} as const satisfies Partial<{
94+
[K in keyof DevtoolMiraData]: {
95+
get(field: MirabufSceneObject): DevtoolMiraData[K]
96+
set(field: MirabufSceneObject, val: unknown | null): void
97+
validate(val: unknown): val is DevtoolMiraData[K]
98+
}
99+
}>
100+
101+
export type DevtoolKey = keyof typeof devtoolHandlers
102+
export const devtoolKeys = Object.keys(devtoolHandlers) as DevtoolKey[]
103+
18104
/**
19105
* Utility for reading and writing developer tool data in the mira file's UserData field.
20106
* Docs: https://www.mirabuf.dev/#mirabuf.UserData

fission/src/mirabuf/MirabufInstance.ts

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ import { ParseErrorSeverity } from "./MirabufParser.ts"
88
type MirabufPartInstanceGUID = string
99

1010
const WIREFRAME = false
11+
const CHROME_VERSION_FOR_INSTANCED_MESH = 139
12+
13+
const detectInstancedMeshSupport = (): boolean => {
14+
const userAgent = navigator.userAgent
15+
const chromeMatch = userAgent.match(/Chrome\/(\d+)/)
16+
17+
if (chromeMatch) {
18+
const chromeVersion = parseInt(chromeMatch[1], 10)
19+
console.log(
20+
`Detected Chrome ${chromeVersion}, using ${chromeVersion >= CHROME_VERSION_FOR_INSTANCED_MESH ? "InstancedMesh" : "BatchedMesh"}`
21+
)
22+
return chromeVersion >= CHROME_VERSION_FOR_INSTANCED_MESH
23+
}
24+
25+
console.log(`Non-Chrome browser detected (${userAgent}), using BatchedMesh`)
26+
return false
27+
}
28+
29+
const USE_INSTANCED_MESH = detectInstancedMeshSupport()
1130

1231
export enum MaterialStyle {
1332
REGULAR = 0,
@@ -93,8 +112,8 @@ const transformGeometry = (geometry: THREE.BufferGeometry, mesh: mirabuf.IMesh)
93112
class MirabufInstance {
94113
private _mirabufParser: MirabufParser
95114
private _materials: Map<string, THREE.Material>
96-
private _meshes: Map<MirabufPartInstanceGUID, Array<[THREE.BatchedMesh, number]>>
97-
private _batches: Array<THREE.BatchedMesh>
115+
private _meshes: Map<MirabufPartInstanceGUID, Array<[THREE.InstancedMesh | THREE.BatchedMesh, number]>>
116+
private _batches: Array<THREE.InstancedMesh | THREE.BatchedMesh>
98117

99118
public get parser() {
100119
return this._mirabufParser
@@ -160,6 +179,63 @@ class MirabufInstance {
160179
* Creates ThreeJS meshes from the parsed mirabuf file.
161180
*/
162181
private createMeshes() {
182+
if (USE_INSTANCED_MESH) {
183+
this.createInstancedMeshes()
184+
} else {
185+
this.createBatchedMeshes()
186+
}
187+
}
188+
189+
/**
190+
* Creates InstancedMesh objects, as newer version of Chrome break with BatchedMesh
191+
*/
192+
private createInstancedMeshes() {
193+
const assembly = this._mirabufParser.assembly
194+
const instances = assembly.data!.parts!.partInstances!
195+
196+
Object.values(instances).forEach(instance => {
197+
const definition = assembly.data!.parts!.partDefinitions![instance.partDefinitionReference!]
198+
const bodies = definition?.bodies ?? []
199+
200+
bodies.forEach(body => {
201+
const mesh = body?.triangleMesh?.mesh
202+
if (!mesh?.verts || !mesh.normals || !mesh.uv || !mesh.indices) return
203+
204+
const appearanceOverride = body.appearanceOverride
205+
const material = WIREFRAME
206+
? new THREE.MeshStandardMaterial({ wireframe: true, color: 0x000000 })
207+
: appearanceOverride && this._materials.has(appearanceOverride)
208+
? this._materials.get(appearanceOverride)!
209+
: fillerMaterials[nextFillerMaterial++ % fillerMaterials.length]
210+
211+
const geometry = new THREE.BufferGeometry()
212+
transformGeometry(geometry, mesh)
213+
214+
// Create InstancedMesh with count of 1 for this body
215+
const instancedMesh = new THREE.InstancedMesh(geometry, material, 1)
216+
instancedMesh.castShadow = true
217+
instancedMesh.receiveShadow = true
218+
219+
const mat = this._mirabufParser.globalTransforms.get(instance.info!.GUID!)!
220+
instancedMesh.setMatrixAt(0, mat)
221+
instancedMesh.instanceMatrix.needsUpdate = true
222+
223+
this._batches.push(instancedMesh)
224+
225+
let bodies = this._meshes.get(instance.info!.GUID!)
226+
if (!bodies) {
227+
bodies = []
228+
this._meshes.set(instance.info!.GUID!, bodies)
229+
}
230+
bodies.push([instancedMesh, 0])
231+
})
232+
})
233+
}
234+
235+
/**
236+
* Creates BatchedMesh, more efficient, but broken in newer versions of Chrome
237+
*/
238+
private createBatchedMeshes() {
163239
const assembly = this._mirabufParser.assembly
164240
const instances = assembly.data!.parts!.partInstances!
165241

@@ -171,6 +247,7 @@ class MirabufInstance {
171247

172248
const batchMap = new Map<THREE.Material, Map<string, [mirabuf.IBody, Array<mirabuf.IPartInstance>]>>()
173249
const countMap = new Map<THREE.Material, BatchCounts>()
250+
174251
// Filter all instances by first material, then body
175252
Object.values(instances).forEach(instance => {
176253
const definition = assembly.data!.parts!.partDefinitions![instance.partDefinitionReference!]
@@ -180,7 +257,6 @@ class MirabufInstance {
180257
if (!mesh?.verts || !mesh.normals || !mesh.uv || !mesh.indices) return
181258

182259
const appearanceOverride = body.appearanceOverride
183-
184260
const material = WIREFRAME
185261
? new THREE.MeshStandardMaterial({ wireframe: true, color: 0x000000 })
186262
: appearanceOverride && this._materials.has(appearanceOverride)

0 commit comments

Comments
 (0)