virginmap overlay (fixes #32)

This commit is contained in:
Grant 2024-06-04 19:31:59 -06:00
parent e69f5bf618
commit b38b1d8b59
12 changed files with 153 additions and 4 deletions

View File

@ -23,3 +23,13 @@
pointer-events: none;
touch-action: none;
}
.board-overlay {
position: absolute;
top: 0;
left: 0;
}
.no-interact {
pointer-events: none;
}

View File

@ -9,6 +9,7 @@ import { IPosition } from "@sc07-canvas/lib/src/net";
import { Template } from "./Template";
import { IRouterData, Router } from "../lib/router";
import { KeybindManager } from "../lib/keybinds";
import { VirginOverlay } from "./Overlay/VirginOverlay";
export const CanvasWrapper = () => {
const { config } = useAppContext();
@ -17,6 +18,7 @@ export const CanvasWrapper = () => {
return (
<main>
<PanZoomWrapper>
<VirginOverlay />
{config && <Template />}
<CanvasInner />
</PanZoomWrapper>

View File

@ -0,0 +1,22 @@
import { Switch } from "@nextui-org/react";
import { useAppContext } from "../../contexts/AppContext";
export const OverlaySettings = () => {
const { showVirginOverlay, setShowVirginOverlay } = useAppContext();
return (
<>
<header>
<h2>Overlays</h2>
</header>
<section>
<Switch
isSelected={showVirginOverlay}
onValueChange={setShowVirginOverlay}
>
Virgin Map Overlay
</Switch>
</section>
</>
);
};

View File

@ -0,0 +1,81 @@
import { useEffect, useRef } from "react";
import { useAppContext } from "../../contexts/AppContext";
import { Canvas } from "../../lib/canvas";
import { KeybindManager } from "../../lib/keybinds";
export const VirginOverlay = () => {
const { config, showVirginOverlay, setShowVirginOverlay } = useAppContext();
const canvasRef = useRef<HTMLCanvasElement | null>(null);
useEffect(() => {
const handleKeybind = () => {
setShowVirginOverlay((v) => !v);
};
KeybindManager.on("TOGGLE_VIRGIN", handleKeybind);
return () => {
KeybindManager.off("TOGGLE_VIRGIN", handleKeybind);
};
}, [setShowVirginOverlay]);
useEffect(() => {
if (!config) {
console.warn("[VirginOverlay] config is not defined");
return;
}
if (!canvasRef.current) {
console.warn("[VirginOverlay] canvasRef is not defined");
return;
}
const [width, height] = config.canvas.size;
canvasRef.current.width = width;
canvasRef.current.height = height;
}, [config]);
useEffect(() => {
if (!canvasRef.current) {
console.warn("[VirginOverlay] canvasRef is not defined");
return;
}
const updateVirginmap = () => {
const ctx = canvasRef.current!.getContext("2d");
if (!ctx) {
console.warn("[VirginOverlay] canvas context cannot be aquired");
return;
}
ctx.clearRect(0, 0, canvasRef.current!.width, canvasRef.current!.height);
const pixels = Canvas.instance!.getAllPixels();
for (const pixel of pixels) {
if (pixel.color !== -1) continue;
ctx.fillStyle = "rgba(0,140,0,0.5)";
ctx.fillRect(pixel.x, pixel.y, 1, 1);
}
};
var updateInterval = setInterval(updateVirginmap, 1000);
return () => {
clearInterval(updateInterval);
};
}, [canvasRef]);
return (
<canvas
id="virgin-overlay"
className="board-overlay no-interact pixelate"
ref={(r) => (canvasRef.current = r)}
width="1000"
height="1000"
style={{
display: showVirginOverlay ? "block" : "none",
}}
/>
);
};

View File

@ -4,6 +4,7 @@ import { TemplateSettings } from "./TemplateSettings";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faXmark } from "@fortawesome/free-solid-svg-icons/faXmark";
import { ChatSettings } from "./ChatSettings";
import { OverlaySettings } from "../Overlay/OverlaySettings";
export const SettingsSidebar = () => {
const { settingsSidebar, setSettingsSidebar, setShowKeybinds } =
@ -34,6 +35,7 @@ export const SettingsSidebar = () => {
</section>
<TemplateSettings />
<ChatSettings />
<OverlaySettings />
</div>
);
};

View File

@ -1,7 +1,4 @@
#template {
position: absolute;
top: 0;
left: 0;
width: 100px;
> * {

View File

@ -136,6 +136,7 @@ export const Template = () => {
return (
<div
id="template"
className="board-overlay"
ref={templateHolder}
style={{
top: y,

View File

@ -42,6 +42,8 @@ export const AppContext = ({ children }: PropsWithChildren) => {
}>();
const [showKeybinds, setShowKeybinds] = useState(false);
const [showVirginOverlay, setShowVirginOverlay] = useState(false);
const [hasAdmin, setHasAdmin] = useState(false);
useEffect(() => {
@ -140,6 +142,8 @@ export const AppContext = ({ children }: PropsWithChildren) => {
setPixelWhois,
showKeybinds,
setShowKeybinds,
showVirginOverlay,
setShowVirginOverlay,
}}
>
{!config && (

View File

@ -99,6 +99,27 @@ export class Canvas extends EventEmitter<CanvasEvents> {
return this.PanZoom;
}
getAllPixels() {
let pixels: {
x: number;
y: number;
color: number;
}[] = [];
for (const [x_y, value] of Object.entries(this.pixels)) {
if (value.type === "pending") continue;
const [x, y] = x_y.split("_").map((v) => parseInt(v));
pixels.push({
x,
y,
color: value.color,
});
}
return pixels;
}
/**
* Get nearby pixels
* @param x

View File

@ -31,6 +31,11 @@ const KEYBINDS = enforceObjectType({
alt: true,
},
],
TOGGLE_VIRGIN: [
{
key: "KeyV",
},
],
});
class KeybindManager_ extends EventEmitter<{

View File

@ -50,6 +50,7 @@ export class Template extends EventEmitter<TemplateEvents> {
this.$wrapper = templateHolder;
this.$imageLoader = document.createElement("img");
this.$imageLoader.style.setProperty("display", "none");
this.$imageLoader.setAttribute("crossorigin", "");
this.$imageLoader.addEventListener("load", () => {
console.log("imageLoader loaded image");
@ -101,7 +102,7 @@ export class Template extends EventEmitter<TemplateEvents> {
switch (key) {
case "enable":
this.setElementVisible([this.$canvas, this.$imageLoader], !!value);
this.setElementVisible([this.$canvas], !!value);
break;
}

View File

@ -53,6 +53,9 @@ export interface IAppContext {
showKeybinds: boolean;
setShowKeybinds: (v: boolean) => void;
showVirginOverlay: boolean;
setShowVirginOverlay: React.Dispatch<React.SetStateAction<boolean>>;
hasAdmin: boolean;
}