feat: use programmer art textures when on versions 1.13 and below
This commit is contained in:
parent
dca9e43e99
commit
0bfe70809d
13 changed files with 97 additions and 53 deletions
|
|
@ -36,6 +36,7 @@ function Blocks({
|
|||
usableBlocks,
|
||||
coords,
|
||||
scale,
|
||||
version,
|
||||
setLoading,
|
||||
}: Props) {
|
||||
const app = useApp();
|
||||
|
|
@ -49,7 +50,7 @@ function Blocks({
|
|||
// Tile solid colors at smaller scales
|
||||
if (scale >= 0.5) {
|
||||
blocks.forEach((block) => {
|
||||
tilemap.tile(textures[`${block.name}.png`] ?? missingTexture, block.x * 16, block.y * 16);
|
||||
tilemap.tile(textures[block.name], block.x * 16, block.y * 16);
|
||||
});
|
||||
} else {
|
||||
blocks.forEach((block) => {
|
||||
|
|
@ -67,7 +68,7 @@ function Blocks({
|
|||
tileBlocks();
|
||||
}, []);
|
||||
|
||||
useEffect(tileBlocks, [blocks]);
|
||||
useEffect(tileBlocks, [blocks, version]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!tilemapRef.current) return;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import { TexturesContext } from "@/context/Textures";
|
|||
import { ThemeContext } from "@/context/Theme";
|
||||
import { ToolContext } from "@/context/Tool";
|
||||
|
||||
import { useTextures } from "@/hooks/useTextures";
|
||||
|
||||
import Blocks from "./Blocks";
|
||||
import Cursor from "./Cursor";
|
||||
import Grid from "./Grid";
|
||||
|
|
@ -29,10 +31,11 @@ function Canvas() {
|
|||
const { image, imageDimensions, usableBlocks } = useContext(ImageContext);
|
||||
const { setLoading } = useContext(LoadingContext);
|
||||
const { settings } = useContext(SettingsContext);
|
||||
const { missingTexture, textures, solidTextures } = useContext(TexturesContext);
|
||||
const { missingTexture, solidTextures } = useContext(TexturesContext);
|
||||
const { isDark } = useContext(ThemeContext);
|
||||
const { tool, radius, selectedBlock, cssCursor, setTool, setSelectedBlock, setCssCursor } = useContext(ToolContext);
|
||||
|
||||
const textures = useTextures(version);
|
||||
const stageContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [mousePosition, setMousePosition] = useState<Position>({ x: 0, y: 0 });
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { Separator } from "@/components/ui/separator";
|
|||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Toggle } from "@/components/ui/toggle";
|
||||
|
||||
import { getBlockData } from "@/utils/getBlockData";
|
||||
import { useBlockData } from "@/hooks/useBlockData";
|
||||
|
||||
import BlockSelector from "./open-image/BlockSelector";
|
||||
import VersionCombobox from "../VersionCombobox";
|
||||
|
|
@ -34,7 +34,7 @@ function OpenImage({ close }: DialogProps) {
|
|||
},
|
||||
});
|
||||
|
||||
const blockData = getBlockData(version);
|
||||
const blockData = useBlockData(version);
|
||||
const divRef = useRef<HTMLDivElement>(null);
|
||||
const userModifiedBlocks = useRef(false);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,17 +2,18 @@ import { useContext, useState } from "react";
|
|||
import * as PIXI from "pixi.js";
|
||||
|
||||
import { CanvasContext } from "@/context/Canvas";
|
||||
import { TexturesContext } from "@/context/Textures";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
import { useTextures } from "@/hooks/useTextures";
|
||||
|
||||
function SaveImage({ close }: DialogProps) {
|
||||
const { blocks, canvasSize } = useContext(CanvasContext);
|
||||
const { missingTexture, textures } = useContext(TexturesContext);
|
||||
const { blocks, canvasSize, version } = useContext(CanvasContext);
|
||||
|
||||
const [fileName, setFileName] = useState("blockmatic");
|
||||
const textures = useTextures(version);
|
||||
|
||||
const onSubmit = () => {
|
||||
const width = canvasSize.maxX - canvasSize.minX;
|
||||
|
|
@ -26,8 +27,7 @@ function SaveImage({ close }: DialogProps) {
|
|||
|
||||
const container = new PIXI.Container();
|
||||
blocks.forEach((block) => {
|
||||
const texture = textures[`${block.name}.png`] ?? missingTexture;
|
||||
const sprite = new PIXI.Sprite(texture);
|
||||
const sprite = new PIXI.Sprite(textures[block.name]);
|
||||
sprite.x = block.x * 16;
|
||||
sprite.y = block.y * 16;
|
||||
container.addChild(sprite);
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import React, { useContext, useMemo, useState } from "react";
|
|||
import { Container, Graphics, Sprite, Stage } from "@pixi/react";
|
||||
|
||||
import { CanvasContext } from "@/context/Canvas";
|
||||
import { TexturesContext } from "@/context/Textures";
|
||||
import { ThemeContext } from "@/context/Theme";
|
||||
|
||||
import { getBlockData } from "@/utils/getBlockData";
|
||||
import { useBlockData } from "@/hooks/useBlockData";
|
||||
import { useTextures } from "@/hooks/useTextures";
|
||||
|
||||
interface Props {
|
||||
stageWidth: number;
|
||||
|
|
@ -17,10 +17,10 @@ interface Props {
|
|||
|
||||
function BlockSelector({ stageWidth, searchInput, selectedBlocks, setSelectedBlocks, userModifiedBlocks }: Props) {
|
||||
const { version } = useContext(CanvasContext);
|
||||
const { missingTexture, textures } = useContext(TexturesContext);
|
||||
const { isDark } = useContext(ThemeContext);
|
||||
|
||||
const blockData = getBlockData(version);
|
||||
const blockData = useBlockData(version);
|
||||
const textures = useTextures(version);
|
||||
|
||||
const [hoverPosition, setHoverPosition] = useState<Position | null>(null);
|
||||
|
||||
|
|
@ -46,7 +46,6 @@ function BlockSelector({ stageWidth, searchInput, selectedBlocks, setSelectedBlo
|
|||
>
|
||||
<Container>
|
||||
{filteredBlocks.map((block, index) => {
|
||||
const texture = textures[`${block}.png`] ?? missingTexture;
|
||||
const x = (index % blocksPerColumn) * (32 + 2) + 2;
|
||||
const y = Math.floor(index / blocksPerColumn) * (32 + 2) + 2;
|
||||
|
||||
|
|
@ -54,7 +53,7 @@ function BlockSelector({ stageWidth, searchInput, selectedBlocks, setSelectedBlo
|
|||
<>
|
||||
<Sprite
|
||||
key={block}
|
||||
texture={texture}
|
||||
texture={textures[block]}
|
||||
x={x}
|
||||
y={y}
|
||||
scale={2}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import { Container, Graphics, Sprite, Stage } from "@pixi/react";
|
|||
import { BlocksIcon } from "lucide-react";
|
||||
|
||||
import { CanvasContext } from "@/context/Canvas";
|
||||
import { TexturesContext } from "@/context/Textures";
|
||||
import { ThemeContext } from "@/context/Theme";
|
||||
import { ToolContext } from "@/context/Tool";
|
||||
|
||||
import { getBlockData } from "@/utils/getBlockData";
|
||||
import { useBlockData } from "@/hooks/useBlockData";
|
||||
import { useTextures } from "@/hooks/useTextures";
|
||||
|
||||
interface Props {
|
||||
stageWidth: number;
|
||||
|
|
@ -16,17 +16,17 @@ interface Props {
|
|||
|
||||
function BlockSelector({ stageWidth, searchInput }: Props) {
|
||||
const { version } = useContext(CanvasContext);
|
||||
const { missingTexture, textures } = useContext(TexturesContext);
|
||||
const { isDark } = useContext(ThemeContext);
|
||||
const { selectedBlock, setSelectedBlock } = useContext(ToolContext);
|
||||
|
||||
const [hoverPosition, setHoverPosition] = useState<Position | null>(null);
|
||||
const [selectedBlockPosition, setSelectedBlockPosition] = useState<Position | null>({ x: 0, y: 0 });
|
||||
|
||||
const blockData = getBlockData(version);
|
||||
|
||||
const blocksPerColumn = Math.floor(stageWidth / (32 + 2));
|
||||
|
||||
const blockData = useBlockData(version);
|
||||
const filteredBlocks = useMemo(() => Object.keys(blockData).filter((value) => value.includes(searchInput)), [searchInput, blockData]);
|
||||
const textures = useTextures(version, filteredBlocks);
|
||||
|
||||
const getBlockPosition = (index: number): Position => {
|
||||
const x = (index % blocksPerColumn) * (32 + 2) + 2;
|
||||
|
|
@ -62,7 +62,7 @@ function BlockSelector({ stageWidth, searchInput }: Props) {
|
|||
>
|
||||
<Container>
|
||||
{filteredBlocks.map((block, index) => {
|
||||
const texture = textures[`${block}.png`] ?? missingTexture;
|
||||
const texture = textures[block];
|
||||
const { x, y } = getBlockPosition(index);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { Label } from "@/components/ui/label";
|
|||
import { CanvasContext } from "@/context/Canvas";
|
||||
import { ToolContext } from "@/context/Tool";
|
||||
|
||||
import { getBlockData } from "@/utils/getBlockData";
|
||||
import { useBlockData } from "@/hooks/useBlockData";
|
||||
import { findBlockFromRgb } from "@/utils/findBlockFromRgb";
|
||||
|
||||
function ColorPicker() {
|
||||
|
|
@ -19,7 +19,7 @@ function ColorPicker() {
|
|||
const rgb = useMemo(() => hsvaToRgba(hsva), [hsva]);
|
||||
|
||||
const limitRgba = (x: number) => Math.min(Math.max(x, 0), 255);
|
||||
const blockData = getBlockData(version);
|
||||
const blockData = useBlockData(version);
|
||||
|
||||
useEffect(() => {
|
||||
const blockInfo = blockData[selectedBlock];
|
||||
|
|
|
|||
|
|
@ -6,12 +6,16 @@ import { ToolContext } from "@/context/Tool";
|
|||
import { TexturesContext } from "@/context/Textures";
|
||||
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Button } from "../ui/button";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import { useTextures } from "@/hooks/useTextures";
|
||||
|
||||
function Replace() {
|
||||
const { setBlocks } = useContext(CanvasContext);
|
||||
const { version, setBlocks } = useContext(CanvasContext);
|
||||
const { selectedBlock, tool, setTool } = useContext(ToolContext);
|
||||
const { missingTexture, textures } = useContext(TexturesContext);
|
||||
const { missingTexture } = useContext(TexturesContext);
|
||||
|
||||
const textures = useTextures(version);
|
||||
|
||||
const [oldTool, setOldTool] = useState<Tool>("hand");
|
||||
const [waitingId, setWaitingId] = useState<number | null>(null);
|
||||
|
|
@ -55,7 +59,7 @@ function Replace() {
|
|||
>
|
||||
<Stage width={32} height={32} options={{ backgroundAlpha: 0 }}>
|
||||
<Container>
|
||||
<Sprite texture={textures[`${block1}.png`] ?? missingTexture} scale={2} />
|
||||
<Sprite texture={textures[block1] ?? missingTexture} scale={2} />
|
||||
</Container>
|
||||
</Stage>
|
||||
</button>
|
||||
|
|
@ -67,7 +71,7 @@ function Replace() {
|
|||
>
|
||||
<Stage width={32} height={32} options={{ backgroundAlpha: 0 }}>
|
||||
<Container>
|
||||
<Sprite texture={textures[`${block2}.png`] ?? missingTexture} scale={2} />
|
||||
<Sprite texture={textures[block2] ?? missingTexture} scale={2} />
|
||||
</Container>
|
||||
</Stage>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -4,26 +4,26 @@ import * as PIXI from "pixi.js";
|
|||
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
|
||||
import { TexturesContext } from "@/context/Textures";
|
||||
import { ToolContext } from "@/context/Tool";
|
||||
|
||||
import _blockData from "@/data/blocks/data.json";
|
||||
import { useTextures } from "@/hooks/useTextures";
|
||||
import { CanvasContext } from "@/context/Canvas";
|
||||
const blockData: BlockData = _blockData;
|
||||
|
||||
function SelectedBlock() {
|
||||
const { missingTexture, textures } = useContext(TexturesContext);
|
||||
const { version } = useContext(CanvasContext);
|
||||
const { selectedBlock } = useContext(ToolContext);
|
||||
|
||||
const textures = useTextures(version);
|
||||
const divRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [selectedBlockName, setSelectedBlockName] = useState("Stone");
|
||||
const [selectedBlockTexture, setSelectedBlockTexture] = useState<PIXI.Texture>();
|
||||
|
||||
useEffect(() => {
|
||||
const blockInfo = blockData[selectedBlock];
|
||||
setSelectedBlockName(blockInfo.name);
|
||||
setSelectedBlockTexture(textures[`${selectedBlock}.png`] ?? missingTexture);
|
||||
}, [textures, selectedBlock, missingTexture]);
|
||||
}, [textures, selectedBlock]);
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
|
|
@ -32,7 +32,7 @@ function SelectedBlock() {
|
|||
<div ref={divRef} className="absolute bottom-1 w-8 h-8 outline outline-1 outline-zinc-800 dark:outline-zinc-200">
|
||||
<Stage width={divRef.current?.clientWidth} height={divRef.current?.clientHeight}>
|
||||
<Container>
|
||||
<Sprite texture={selectedBlockTexture} scale={2} />
|
||||
<Sprite texture={textures[selectedBlock]} scale={2} />
|
||||
</Container>
|
||||
</Stage>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,12 +4,15 @@ import * as PIXI from "pixi.js";
|
|||
import { LoadingContext } from "./Loading";
|
||||
|
||||
import spritesheet from "@/data/blocks/spritesheet.json";
|
||||
import programmerArtSpritesheet from "@/data/blocks/programmer-art/spritesheet.json";
|
||||
|
||||
import _blockData from "@/data/blocks/data.json";
|
||||
const blockData: BlockData = _blockData;
|
||||
|
||||
interface Context {
|
||||
missingTexture: PIXI.Texture | undefined;
|
||||
textures: Record<string, PIXI.Texture>;
|
||||
programmerArtTextures: Record<string, PIXI.Texture>;
|
||||
solidTextures: Record<string, PIXI.Texture>;
|
||||
}
|
||||
|
||||
|
|
@ -24,6 +27,7 @@ export const TexturesProvider = ({ children }: Props) => {
|
|||
|
||||
const [missingTexture, setMissingTexture] = useState<PIXI.Texture>();
|
||||
const [textures, setTextures] = useState<Record<string, PIXI.Texture>>({});
|
||||
const [programmerArtTextures, setProgrammerArtTextures] = useState<Record<string, PIXI.Texture>>({});
|
||||
const [solidTextures, setSolidTextures] = useState<Record<string, PIXI.Texture>>({});
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -34,12 +38,18 @@ export const TexturesProvider = ({ children }: Props) => {
|
|||
setMissingTexture(new PIXI.Texture(missingBaseTexture));
|
||||
|
||||
// Load textures
|
||||
const sheet = new PIXI.Spritesheet(PIXI.BaseTexture.from("/blocks/spritesheet.png"), spritesheet);
|
||||
sheet.parse().then((t) => {
|
||||
// Add air texture
|
||||
const airBaseTexture = new PIXI.BaseTexture("/blocks/air.png");
|
||||
const airTexture = new PIXI.Texture(airBaseTexture);
|
||||
|
||||
setTextures({ ...t, "air.png": new PIXI.Texture(airBaseTexture) });
|
||||
const sheet = new PIXI.Spritesheet(PIXI.BaseTexture.from("/blocks/spritesheet.png"), spritesheet);
|
||||
sheet.parse().then((t) => {
|
||||
setTextures({ ...t, "air.png": airTexture });
|
||||
});
|
||||
|
||||
const programmerArtSheet = new PIXI.Spritesheet(PIXI.BaseTexture.from("/blocks/programmer-art/spritesheet.png"), programmerArtSpritesheet);
|
||||
programmerArtSheet.parse().then((t) => {
|
||||
setProgrammerArtTextures({ ...t, "air.png": airTexture });
|
||||
});
|
||||
|
||||
// Load solid textures
|
||||
|
|
@ -68,5 +78,5 @@ export const TexturesProvider = ({ children }: Props) => {
|
|||
setLoading(false);
|
||||
}, []);
|
||||
|
||||
return <TexturesContext.Provider value={{ missingTexture, textures, solidTextures }}>{children}</TexturesContext.Provider>;
|
||||
return <TexturesContext.Provider value={{ missingTexture, textures, programmerArtTextures, solidTextures }}>{children}</TexturesContext.Provider>;
|
||||
};
|
||||
|
|
|
|||
18
src/hooks/useBlockData.ts
Normal file
18
src/hooks/useBlockData.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { useMemo } from "react";
|
||||
|
||||
import _blockData from "@/data/blocks/data.json";
|
||||
const blockData: BlockData = _blockData;
|
||||
|
||||
export function useBlockData(version: number): BlockData {
|
||||
return useMemo(() => {
|
||||
const result: BlockData = {};
|
||||
|
||||
for (const key in blockData) {
|
||||
if (blockData[key].version <= version) {
|
||||
result[key] = blockData[key];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}, [version]);
|
||||
}
|
||||
23
src/hooks/useTextures.ts
Normal file
23
src/hooks/useTextures.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { useContext, useMemo } from "react";
|
||||
import { BaseTexture, Texture } from "pixi.js";
|
||||
|
||||
import { TexturesContext } from "@/context/Textures";
|
||||
import { useBlockData } from "./useBlockData";
|
||||
|
||||
export function useTextures(version: number, blocks?: string[]): Record<string, Texture> {
|
||||
const { missingTexture, textures, programmerArtTextures } = useContext(TexturesContext);
|
||||
|
||||
const blockData = useBlockData(version);
|
||||
const blocksToUse = blocks || Object.keys(blockData);
|
||||
|
||||
return useMemo(() => {
|
||||
return blocksToUse.reduce<Record<string, Texture>>((textureMap, block) => {
|
||||
if (version <= 1130) {
|
||||
textureMap[block] = programmerArtTextures[`${block}.png`] ?? missingTexture;
|
||||
} else {
|
||||
textureMap[block] = textures[`${block}.png`] ?? missingTexture;
|
||||
}
|
||||
return textureMap;
|
||||
}, {});
|
||||
}, [blocksToUse, version, missingTexture, textures, programmerArtTextures]);
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import _blockData from "@/data/blocks/data.json";
|
||||
const blockData: BlockData = _blockData;
|
||||
|
||||
export function getBlockData(version: number) {
|
||||
const filteredData: BlockData = {};
|
||||
|
||||
for (const key in blockData) {
|
||||
if (blockData[key].version <= version) {
|
||||
filteredData[key] = blockData[key];
|
||||
}
|
||||
}
|
||||
|
||||
return filteredData;
|
||||
}
|
||||
Loading…
Reference in a new issue