Skip to content

Commit

Permalink
Adds support for changing the JOTEGO analogizer config (#303)
Browse files Browse the repository at this point in the history
  • Loading branch information
neil-morrison44 authored Jul 27, 2024
1 parent e774065 commit fe71bcb
Show file tree
Hide file tree
Showing 14 changed files with 228 additions and 8 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "pocket-sync",
"private": true,
"version": "4.10.0",
"version": "4.11.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
Binary file added src-tauri/Assets/jtpatreon/common/crtcfg.bin
Binary file not shown.
2 changes: 1 addition & 1 deletion src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pocket-sync"
version = "4.10.0"
version = "4.11.0"
description = "A GUI tool for doing stuff with the Analogue Pocket"
authors = ["neil-morrison44"]
license = "AGPL-3.0"
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
"package": {
"productName": "Pocket Sync",
"version": "4.10.0"
"version": "4.11.0"
},
"tauri": {
"allowlist": {
Expand Down
2 changes: 1 addition & 1 deletion src/components/cores/info/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@
}

.core-info__supports--false {
opacity: 0.25;
opacity: 0.45;
}

.core-info__supports--button {
Expand Down
5 changes: 5 additions & 0 deletions src/components/cores/info/installed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { CoreInfoTxtSelectorFamily } from "../../../recoil/cores/selectors"
import { ProgressLoader } from "../../loader/progress"
import { AnalogizerIcon } from "../icons/AnalogizerIcon"
import { DownloadCount } from "./downloadCounts"
import { JTAnalogizerSettings } from "./jtanalogizer"

type CoreInfoProps = {
coreName: string
Expand Down Expand Up @@ -292,6 +293,10 @@ export const InstalledCoreInfo = ({ coreName, onBack }: CoreInfoProps) => {
</button>
</div>

{coreInfo.core.metadata.platform_ids.includes("jtpatreon") && (
<JTAnalogizerSettings coreName={coreName} />
)}

<div className="core-info__info-row">
<Details title={t("info_txt_title")}>
<InfoTxt coreName={coreName} />
Expand Down
16 changes: 16 additions & 0 deletions src/components/cores/info/jtanalogizer/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.jt-analogizer__options-title{
margin: 0;
margin-block-end: 12px;

&:not(:first-child){
margin-block-start: 12px;
}
}

.jt-analogizer__options{
display: flex;
flex-wrap: wrap;
gap: 10px;
place-items: flex-start start;
justify-content: start;
}
80 changes: 80 additions & 0 deletions src/components/cores/info/jtanalogizer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { useRecoilState, useRecoilValue } from "recoil"
import { DataJSONSelectorFamily } from "../../../../recoil/selectors"
import { Suspense, useMemo } from "react"
import {
JT_ANALOGIZER_SNAC_OPTIONS,
JT_ANALOGIZER_VIDEO_OPTIONS,
JTCRTConfigSelector,
} from "../../../../recoil/cores/selectors"
import { useTranslation } from "react-i18next"
import { Details } from "../../../shared/details"
import { AnalogizerIcon } from "../../icons/AnalogizerIcon"
import { SupportsBubble } from "../supportsBubble"

import "./index.css"

type JTAnalogizerSettingsProps = {
coreName: string
}

export const JTAnalogizerSettings = ({
coreName,
}: JTAnalogizerSettingsProps) => {
const coreData = useRecoilValue(DataJSONSelectorFamily(coreName))
const hasCRTConfig = useMemo(
() =>
coreData.data.data_slots.find(
({ filename }) => filename === "crtcfg.bin"
) !== undefined,
[coreData]
)

if (!hasCRTConfig) return null

return (
<Suspense fallback={<div style={{ height: "230px" }}></div>}>
<JTAnalogizerSettingsInner />
</Suspense>
)
}

const JTAnalogizerSettingsInner = () => {
const { t } = useTranslation("core_info")
const [crtConfig, setCrtConfig] = useRecoilState(JTCRTConfigSelector)

return (
<Details
title={t("jt_analogizer_config.title")}
renderIcon={() => <AnalogizerIcon />}
>
<h4 className="jt-analogizer__options-title">
{t("jt_analogizer_config.video")}
</h4>
<div className="jt-analogizer__options">
{JT_ANALOGIZER_VIDEO_OPTIONS.map(([_, name]) => (
<SupportsBubble
supports={crtConfig.video === name}
key={name}
onClick={() => setCrtConfig({ ...crtConfig, video: name })}
>
{name}
</SupportsBubble>
))}
</div>
<h4 className="jt-analogizer__options-title">
{t("jt_analogizer_config.snac")}
</h4>
<div className="jt-analogizer__options">
{JT_ANALOGIZER_SNAC_OPTIONS.map(([_, name]) => (
<SupportsBubble
supports={crtConfig.snac === name}
key={name}
onClick={() => setCrtConfig({ ...crtConfig, snac: name })}
>
{name}
</SupportsBubble>
))}
</div>
</Details>
)
}
8 changes: 7 additions & 1 deletion src/components/shared/details/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
font-weight: bold;
cursor: pointer;
display: flex;
justify-content: space-between;
justify-content: flex-start;
gap: 12px;
user-select: none;
/* stylelint-disable-next-line property-no-vendor-prefix */
-webkit-user-select: none;
Expand All @@ -21,6 +22,11 @@
background-color: rgb(255 255 255 / 10%);
}


& > :last-child{
margin-inline-start: auto;
}

}

.details__title--sticky {
Expand Down
3 changes: 3 additions & 0 deletions src/components/shared/details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ type DetailsProps = {
children: ReactNode
openByDefault?: boolean
sticky?: boolean
renderIcon?: () => ReactNode
}

export const Details = ({
title,
children,
openByDefault = false,
sticky = false,
renderIcon,
}: DetailsProps) => {
const [isOpen, setIsOpen] = useState(openByDefault)

Expand All @@ -22,6 +24,7 @@ export const Details = ({
className={`details__title ${sticky ? "details__title--sticky" : ""}`}
onClick={() => setIsOpen((c) => !c)}
>
{renderIcon && renderIcon()}
{title}
{isOpen ? <ContractIcon /> : <ExpandIcon />}
</div>
Expand Down
5 changes: 5 additions & 0 deletions src/i18n/locales/en/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@
"original_gg": "Original GG",
"original_gg_plus": "Original GG+",
"pinball_neon_matrix": "Pinball Neon Matrix"
},
"jt_analogizer_config": {
"title": "Analogizer Config",
"video": "Analog Video",
"snac": "SNAC Controllers"
}
},
"core_info_required_files": {
Expand Down
88 changes: 86 additions & 2 deletions src/recoil/cores/selectors.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { selector, selectorFamily } from "recoil"
import { DefaultValue, selector, selectorFamily } from "recoil"
import { CoreInfoSelectorFamily, coresListSelector } from "../selectors"
import { coreInventoryAtom } from "../inventory/atoms"
import { FileWatchAtomFamily } from "../fileSystem/atoms"
import { invokeFileExists, invokeReadTextFile } from "../../utils/invokes"
import {
invokeFileExists,
invokeReadBinaryFile,
invokeReadTextFile,
invokeSaveFile,
} from "../../utils/invokes"
import { JTCrtConfig } from "../../types"
import { pocketPathAtom } from "../atoms"

type UpdateInfo = {
coreName: string
Expand Down Expand Up @@ -53,3 +60,80 @@ export const CoreInfoTxtSelectorFamily = selectorFamily<string, string>({
return text
},
})

export const JT_ANALOGIZER_VIDEO_OPTIONS: [number, JTCrtConfig["video"]][] = [
[0x820, "RBGS (SCART)"],
[0xc08, "RGsB"],
[0xa08, "YPbPr (Component video)"],
[0x900, "Y/C NTSC (SVideo, Composite video)"],
[0x980, "Y/C PAL (SVideo, Composite video)"],
[0x801, "Scandoubler RGBHV (SCANLINES 0%)"],
[0x803, "Scandoubler RGBHV (SCANLINES 25%)"],
[0x805, "Scandoubler RGBHV (SCANLINES 50%)"],
[0x807, "Scandoubler RGBHV (SCANLINES 75%)"],
[0x000, "Disable Analog Video"],
] as const

export const JT_ANALOGIZER_SNAC_OPTIONS: [number, JTCrtConfig["snac"]][] = [
[0x00, "None"],
[0x01, "DB15 Normal"],
[0x02, "NES"],
[0x03, "SNES"],
[0x04, "PCE 2BTN/6BTN"],
[0x06, "PCE Multitap"],
] as const

const DEFAULT_CRT_CONFIG = {
video: "Disable Analog Video",
snac: "None",
} as const

export const JTCRTConfigSelector = selector<JTCrtConfig>({
key: "JTCRTConfigSelector",
get: async ({ get }) => {
const path = "Assets/jtpatreon/common/crtcfg.bin"
get(FileWatchAtomFamily(path))
const exists = await invokeFileExists(path)
if (!exists) return DEFAULT_CRT_CONFIG

const binary = await invokeReadBinaryFile(path)
const configValue = new DataView(binary.buffer).getUint32(0, false)

const videoValue = (configValue >> 20) & 0xfff
const snacValue = (configValue >> 12) & 0xff

const video = JT_ANALOGIZER_VIDEO_OPTIONS.find(
([key]) => key === videoValue
)
const snac = JT_ANALOGIZER_SNAC_OPTIONS.find(([key]) => key === snacValue)

if (!video || !snac) return DEFAULT_CRT_CONFIG

return { video: video[1], snac: snac[1] }
},
set: ({ get }, newValue) => {
const pocketPath = get(pocketPathAtom)
const path = `${pocketPath}/Assets/jtpatreon/common/crtcfg.bin`

if (newValue instanceof DefaultValue) {
newValue = DEFAULT_CRT_CONFIG
}

const videoValue = JT_ANALOGIZER_VIDEO_OPTIONS.find(
([_, value]) => newValue.video === value
)
const snacValue = JT_ANALOGIZER_SNAC_OPTIONS.find(
([_, value]) => newValue.snac === value
)

if (!videoValue) throw new Error(`Non-video value ${newValue.video}`)
if (!snacValue) throw new Error(`Non-snac value ${newValue.snac}`)

const configValue = (videoValue[0] << 20) | (snacValue[0] << 12)

const binary = new Uint8Array(4)
new DataView(binary.buffer).setUint32(0, configValue, false)

invokeSaveFile(path, binary)
},
})
21 changes: 21 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,24 @@ export type ProgressEvent = {
export type SortMode = "name" | "last_update"

export type Job = { id: string; status: "Running" | "Stopping" }

export type JTCrtConfig = {
video:
| "RBGS (SCART)"
| "RGsB"
| "YPbPr (Component video)"
| "Y/C NTSC (SVideo, Composite video)"
| "Y/C PAL (SVideo, Composite video)"
| "Scandoubler RGBHV (SCANLINES 0%)"
| "Scandoubler RGBHV (SCANLINES 25%)"
| "Scandoubler RGBHV (SCANLINES 50%)"
| "Scandoubler RGBHV (SCANLINES 75%)"
| "Disable Analog Video"
snac:
| "None"
| "DB15 Normal"
| "NES"
| "SNES"
| "PCE 2BTN/6BTN"
| "PCE Multitap"
}

0 comments on commit fe71bcb

Please sign in to comment.