@@ -48,6 +48,9 @@ const downloadLatestOptiScaler = callable<
4848 }
4949> ( "download_optiscaler_nightly" ) ;
5050
51+ const getOptiScalerFGType = callable < [ ] , { status : string ; fgtype : string ; message ?: string } > ( "get_optiscaler_fgtype" ) ;
52+ const setOptiScalerFGType = callable < [ string ] , { status : string ; message : string } > ( "set_optiscaler_fgtype" ) ;
53+
5154function FGModInstallerSection ( ) {
5255 const [ installing , setInstalling ] = useState ( false ) ;
5356 const [ uninstalling , setUninstalling ] = useState ( false ) ;
@@ -311,6 +314,155 @@ function FGModInstallerSection() {
311314 ) ;
312315}
313316
317+ function OptiScalerFGTypeSection ( ) {
318+ const [ fgType , setFgType ] = useState < string > ( "unknown" ) ;
319+ const [ isUpdating , setIsUpdating ] = useState ( false ) ;
320+ const [ updateMessage , setUpdateMessage ] = useState < string | null > ( null ) ;
321+
322+ const fetchFGType = async ( ) => {
323+ try {
324+ const result = await getOptiScalerFGType ( ) ;
325+ if ( result . status === "success" ) {
326+ setFgType ( result . fgtype ) ;
327+ } else {
328+ setFgType ( "unknown" ) ;
329+ console . error ( "Failed to get FGType:" , result . message ) ;
330+ }
331+ } catch ( error ) {
332+ logError ( `Error fetching FGType: ${ String ( error ) } ` ) ;
333+ console . error ( "Error fetching FGType:" , error ) ;
334+ setFgType ( "unknown" ) ;
335+ }
336+ } ;
337+
338+ useEffect ( ( ) => {
339+ // Initially fetch FGType when component mounts
340+ fetchFGType ( ) ;
341+
342+ // Set up interval to refresh every 3 seconds
343+ const intervalId = setInterval ( fetchFGType , 3000 ) ;
344+
345+ // Clean up interval on unmount
346+ return ( ) => clearInterval ( intervalId ) ;
347+ } , [ ] ) ;
348+
349+ useEffect ( ( ) => {
350+ if ( updateMessage ) {
351+ const timer = setTimeout ( ( ) => setUpdateMessage ( null ) , 3000 ) ;
352+ return ( ) => clearTimeout ( timer ) ;
353+ }
354+ return ( ) => { } ;
355+ } , [ updateMessage ] ) ;
356+
357+ const handleSetFGType = async ( type : string ) => {
358+ setIsUpdating ( true ) ;
359+ try {
360+ const result = await setOptiScalerFGType ( type ) ;
361+ if ( result . status === "success" ) {
362+ setUpdateMessage ( `Successfully set FGType to ${ type } ` ) ;
363+ fetchFGType ( ) ; // Refresh immediately
364+ } else {
365+ setUpdateMessage ( `Failed to set FGType: ${ result . message } ` ) ;
366+ }
367+ } catch ( error ) {
368+ logError ( `Error setting FGType: ${ String ( error ) } ` ) ;
369+ console . error ( "Error setting FGType:" , error ) ;
370+ setUpdateMessage ( `Error: ${ String ( error ) } ` ) ;
371+ } finally {
372+ setIsUpdating ( false ) ;
373+ }
374+ } ;
375+
376+ const getFGTypeDescription = ( ) => {
377+ switch ( fgType ) {
378+ case "auto" :
379+ return "Default setting (usually falls back to nofg)" ;
380+ case "nofg" :
381+ return "No frame generation" ;
382+ case "optifg" :
383+ return "AMD FidelityFX frame generation" ;
384+ case "nukems" :
385+ return "Nukem9's DLSS-to-FSR3 implementation" ;
386+ default :
387+ return "Unknown setting" ;
388+ }
389+ } ;
390+
391+ return (
392+ < PanelSection title = "OptiScaler Frame Generation Settings" >
393+ < PanelSectionRow >
394+ < div style = { {
395+ padding : '10px' ,
396+ backgroundColor : 'rgba(0, 0, 0, 0.2)' ,
397+ borderRadius : '4px' ,
398+ marginBottom : '10px'
399+ } } >
400+ < div style = { { fontWeight : 'bold' , marginBottom : '5px' } } >
401+ Current FGType: < span style = { { color : fgType === "unknown" ? "red" : "green" } } > { fgType } </ span >
402+ </ div >
403+ < div style = { { fontSize : '0.8em' , opacity : 0.8 } } >
404+ { getFGTypeDescription ( ) }
405+ </ div >
406+ </ div >
407+ </ PanelSectionRow >
408+
409+ < PanelSectionRow >
410+ < ButtonItem
411+ layout = "below"
412+ onClick = { ( ) => handleSetFGType ( "auto" ) }
413+ disabled = { isUpdating || fgType === "auto" }
414+ >
415+ Set to Auto
416+ </ ButtonItem >
417+ < div style = { { fontSize : '0.8em' , marginTop : '4px' , opacity : 0.8 } } >
418+ Default setting, lets OptiScaler decide
419+ </ div >
420+ </ PanelSectionRow >
421+
422+ < PanelSectionRow >
423+ < ButtonItem
424+ layout = "below"
425+ onClick = { ( ) => handleSetFGType ( "optifg" ) }
426+ disabled = { isUpdating || fgType === "optifg" }
427+ >
428+ Set to OptiFG
429+ </ ButtonItem >
430+ < div style = { { fontSize : '0.8em' , marginTop : '4px' , opacity : 0.8 } } >
431+ AMD FidelityFX frame generation (requires amd_fidelityfx_dx12.dll)
432+ </ div >
433+ </ PanelSectionRow >
434+
435+ < PanelSectionRow >
436+ < ButtonItem
437+ layout = "below"
438+ onClick = { ( ) => handleSetFGType ( "nukems" ) }
439+ disabled = { isUpdating || fgType === "nukems" }
440+ >
441+ Set to Nukems
442+ </ ButtonItem >
443+ < div style = { { fontSize : '0.8em' , marginTop : '4px' , opacity : 0.8 } } >
444+ Nukem9's DLSS-to-FSR3 implementation (recommended)
445+ </ div >
446+ </ PanelSectionRow >
447+
448+ { updateMessage && (
449+ < PanelSectionRow >
450+ < div style = { {
451+ padding : '10px' ,
452+ backgroundColor : updateMessage . includes ( "Failed" ) || updateMessage . includes ( "Error" )
453+ ? 'rgba(255, 0, 0, 0.2)'
454+ : 'rgba(0, 128, 0, 0.2)' ,
455+ borderRadius : '4px' ,
456+ marginTop : '10px'
457+ } } >
458+ { updateMessage }
459+ </ div >
460+ </ PanelSectionRow >
461+ ) }
462+ </ PanelSection >
463+ ) ;
464+ }
465+
314466function InstalledGamesSection ( ) {
315467 const [ games , setGames ] = useState < { appid : number ; name : string } [ ] > ( [ ] ) ;
316468 const [ selectedGame , setSelectedGame ] = useState < { appid : number ; name : string } | null > ( null ) ;
@@ -567,6 +719,7 @@ export default definePlugin(() => ({
567719 content : (
568720 < >
569721 < FGModInstallerSection />
722+ < OptiScalerFGTypeSection />
570723 < InstalledGamesSection />
571724 </ >
572725 ) ,
0 commit comments