Skip to content

Commit

Permalink
Skinned catcher
Browse files Browse the repository at this point in the history
  • Loading branch information
solstice23 committed Nov 6, 2024
1 parent bc24a4a commit d0ae83f
Show file tree
Hide file tree
Showing 12 changed files with 64 additions and 14 deletions.
Binary file modified src/assets/classic-skin.zip
Binary file not shown.
Binary file added src/assets/fallback-skin/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/fallback-skin/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/assets/simple-skin.zip
Binary file not shown.
5 changes: 4 additions & 1 deletion src/assets/simple-skin/skin.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[Colour]
Combo1: 255,255,255
Nevertint: true
Nevertint: true

[CatchTheBeat]
CatcherSkinFallback: false
7 changes: 5 additions & 2 deletions src/contexts/SettingsContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const SettingsProvider = ({children}) => {
const [verticalScale, verticalScaleRef, setVerticalScale] = useSetting("verticalScale", 1);
const [maxSpinLeniency, maxSpinLeniencyRef, setMaxSpinLeniency] = useSetting("maxSpinLeniency", 0.8, true);

const [showGrid,showGridRef , setShowGrid] = useSetting("showGrid", true, true);
const [showGrid, showGridRef , setShowGrid] = useSetting("showGrid", true, true);
const [derandomize, derandomizeRef, setDerandomize] = useSetting("derandomize", false);

const [hardRock, hardRockRef, setHardRock] = useSetting("hardRock", false);
Expand All @@ -16,13 +16,15 @@ export const SettingsProvider = ({children}) => {
const [gameSpeed, gameSpeedRef, setGameSpeed] = useSetting("gameSpeed", 1, false);

const [showBananaPathShade, showBananaPathShadeRef, setShowBananaPathShade] = useSetting("showBananaPathShade", true, true);

const [showFPS, showFPSRef, setShowFPS] = useSetting("showFPS", false, true);

const [backgroundDim, backgroundDimRef, setBackgroundDim] = useSetting("backgroundDim", 0.8, true);

const [volume, volumeRef, setVolume] = useSetting("volume", 1, true);

const [skinnedCatcher, skinnedCatcherRef , setSkinnedCatcher] = useSetting("skinnedCatcher", false, true);

const [useLegacyDOMRenderer, useLegacyDOMRendererRef, setUseLegacyDOMRenderer] = useSetting("useLegacyDOMrenderer", false, true);

return (
Expand All @@ -38,6 +40,7 @@ export const SettingsProvider = ({children}) => {
showFPS, setShowFPS, showFPSRef,
backgroundDim, setBackgroundDim, backgroundDimRef,
volume, setVolume, volumeRef,
skinnedCatcher, setSkinnedCatcher, skinnedCatcherRef,
useLegacyDOMRenderer, setUseLegacyDOMRenderer, useLegacyDOMRendererRef,
}}>
{children}
Expand Down
2 changes: 1 addition & 1 deletion src/contexts/SkinContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export const SKinProvider = ({children}) => {
)
}

function SkinCSSLayer(skin) {
function SkinCSSLayer(skin) { // This is deprecated, for the old dom renderer
skin = skin.skin;
let styleString = "";
const addSkinElement = (selector, image) => {
Expand Down
33 changes: 26 additions & 7 deletions src/modules/Main/Playfield/AutoCatcher.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import { useEffect, useRef, useLayoutEffect, useState, useContext, useMemo, useCallback } from "react";
import { SettingsContext } from "../../../contexts/SettingsContext";
import { SkinContext } from "../../../contexts/SkinContext";
import "./AutoCatcher.scss";
import { calculatePreempt } from "../../../utils/ApproachRate";
import { parseHitObjects } from "../../../parser/HitobjectsParser";
import { PlayStateContext } from "../../../contexts/PlayStateContext";
import { CalculateScaleFromCircleSize, CalculateCatchWidthByCircleSize } from "../../../utils/CalculateCSScale";
import useRefState from "../../../hooks/useRefState";
import clsx from "clsx";
import fallbackCatcherSkin from "../../../assets/fallback-skin/[email protected]";

export function AutoCatcher({ beatmap, catcherPath }) {
const ref = useRef(null);

const [width, widthRef, setWidth] = useRefState(0);
const [width, widthRef, setWidth] = useRefState(0); // the catcher width (osu px, total 512px width)
const [parentWidth, parentWidthRef, setParentWidth] = useRefState(0);

const {
derandomize,
hardRock,
easy,
skinnedCatcher
} = useContext(SettingsContext);

/*const [fruitSize, setFruitSize] = useState(0);
Expand All @@ -37,7 +42,7 @@ export function AutoCatcher({ beatmap, catcherPath }) {


const onResize = () => {
setWidth(ref.current.parentElement.offsetWidth);
setParentWidth(ref.current.parentElement.offsetWidth);
//recalculateFruitSize();
}

Expand All @@ -55,8 +60,7 @@ export function AutoCatcher({ beatmap, catcherPath }) {
useLayoutEffect(() => {
const catcherWidth = CalculateCatchWidthByCircleSize(beatmap.difficulty.circleSize); // TODO: HR, EZ
console.log("Catcher width", catcherWidth);
ref.current.style.width = `${catcherWidth / 512 * width}px`;
ref.current.style.left = `-${catcherWidth / 512 * width / 2}px`;
setWidth(catcherWidth);
}, [beatmap.difficulty.circleSize, width, hardRock, easy]);


Expand Down Expand Up @@ -94,7 +98,7 @@ export function AutoCatcher({ beatmap, catcherPath }) {
}
//console.log(newIndex, currentTime, newIndex + 1 < path.length && path[newIndex + 1].fromTime <= currentTime, path[newIndex + 1].fromTime);
//console.log(newIndex, currentTime, newIndex - 1 >= 0 && path[newIndex].fromTime > currentTime, path[newIndex].fromTime);
const width = widthRef.current;
const width = parentWidthRef.current;
const seg = path[newIndex];
//console.log(seg, currentTime);
const percent = Math.min((currentTime - seg.fromTime) / (seg.toTime - seg.fromTime), 1);
Expand All @@ -119,13 +123,28 @@ export function AutoCatcher({ beatmap, catcherPath }) {
}
animationRef.current = requestAnimationFrame(aniUpdate);
return () => cancelAnimationFrame(animationRef.current);
}, [width, beatmap, derandomize, hardRock, easy, catcherPath]);
}, [parentWidth, width, beatmap, derandomize, hardRock, easy, catcherPath]);


const {
skin
} = useContext(SkinContext);

const catcherSkinFallback = skin?.catcherSkinFallback ?? true;
const catcherSkin = skinnedCatcher ?
(skin?.["fruit-catcher-idle"] ??
(catcherSkinFallback ? fallbackCatcherSkin : null))
: null;

return (
<div
className="auto-catcher"
className={clsx("auto-catcher", {skinned: catcherSkin})}
style={{
'width': `${width / 512 * parentWidth}px`,
'left': `-${width / 512 * parentWidth / 2}px`,
'--skin-height': `${width / 512 * parentWidth / 612 * 640}px`, // skin is 612*640
'--catcher-skin': `url(${catcherSkin})`
}}
ref={ref}
>
</div>
Expand Down
10 changes: 10 additions & 0 deletions src/modules/Main/Playfield/AutoCatcher.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,14 @@
height: 6px;
border-radius: 0 0 10px 10px;
background-color: #fff;

&.skinned {
background-image: var(--catcher-skin);
background-color: transparent;
background-size: contain;
background-position: top center;
height: var(--skin-height);
bottom: calc(var(--skin-height) * -1 + (30 / 640 * var(--skin-height))); // there is a 30px gap at the top of the skin, somehow
border-radius: 0;
}
}
7 changes: 7 additions & 0 deletions src/modules/Navbar/SettingsPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export function SettingsPanel () {
showFPS, setShowFPS,
backgroundDim, setBackgroundDim,
useLegacyDOMRenderer, setUseLegacyDOMRenderer,
skinnedCatcher, setSkinnedCatcher
} = useContext(SettingsContext);

const [open, setOpen] = useState(false);
Expand Down Expand Up @@ -150,6 +151,12 @@ export function SettingsPanel () {
onChange={(value) => setUseLegacyDOMRenderer(value)}
/>
<SkinSelector />
<Checkbox
label="Skinned Catcher"
description="Apply skin to the catcher"
value={skinnedCatcher}
onChange={(value) => setSkinnedCatcher(value)}
/>
</div>
</button>
</ClickAwayListener>
Expand Down
4 changes: 2 additions & 2 deletions src/modules/Navbar/SettingsPanel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 15px;
height: 15px;
width: 14px;
height: 14px;
border-radius: 100px;
border: 2px solid var(--accent-color);
filter: brightness(1.05);
Expand Down
10 changes: 9 additions & 1 deletion src/parser/SkinParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ const skinFilenames = [
"fruit-orange-overlay",
"fruit-orange",
"fruit-pear-overlay",
"fruit-pear"
"fruit-pear",
"fruit-catcher-idle",
"fruit-catcher-kiai"
]

const imgFileToBlobUrl = async (imgFile, mimeType = "image/png") => {
Expand Down Expand Up @@ -86,6 +88,12 @@ export async function parseSkinFromZipFile(zipFile, name = null) {
comboColours = comboColours.map(([r, g, b]) => r * 256 * 256 + g * 256 + b);
skin.comboColours = comboColours;

// Catcher fallback settings
// Catcher skin fallback
let catcherSkinFallbackValue = skinIni.find(line => line.startsWith("CatcherSkinFallback"))?.split(":")?.[1]?.trim() ?? "true";
catcherSkinFallbackValue = catcherSkinFallbackValue === "true" ? true : false;
skin.catcherSkinFallback = catcherSkinFallbackValue;

// Skin name
const nameLine = skinIni.find(line => line.startsWith("Name:"));
if (nameLine) {
Expand Down

0 comments on commit d0ae83f

Please sign in to comment.