Commit e5821027 authored by Grant's avatar Grant
Browse files

add pixel stacking

parent c3b8467b
Loading
Loading
Loading
Loading
+43 −2
Original line number Diff line number Diff line
@@ -5,10 +5,47 @@ import {
  ModalHeader,
  useDisclosure,
} from "@nextui-org/react";
import { CanvasLib } from "@sc07-canvas/lib/src/canvas";
import { useAppContext } from "../contexts/AppContext";
import { Canvas } from "../lib/canvas";
import { useEffect, useState } from "react";
import { ClientConfig } from "@sc07-canvas/lib/src/net";

const getTimeLeft = (pixels: { available: number }, config: ClientConfig) => {
  // this implementation matches the server's implementation

  const cooldown = CanvasLib.getPixelCooldown(pixels.available + 1, config);
  const pixelExpiresAt =
    Canvas.instance?.lastPlace && Canvas.instance.lastPlace + cooldown * 1000;
  const pixelCooldown = pixelExpiresAt && (Date.now() - pixelExpiresAt) / 1000;

  if (!pixelCooldown) return undefined;
  if (pixelCooldown > 0) return 0;

  return Math.abs(pixelCooldown).toFixed(1);
};

const PlaceCountdown = () => {
  const { pixels, config } = useAppContext();
  const [timeLeft, setTimeLeft] = useState(getTimeLeft(pixels, config));

  useEffect(() => {
    const timer = setInterval(() => {
      setTimeLeft(getTimeLeft(pixels, config));
    }, 100);

    return () => {
      clearInterval(timer);
    };
  }, [pixels]);

  return (
    <>{pixels.available + 1 < config.canvas.pixel.maxStack && timeLeft + "s"}</>
  );
};

export const CanvasMeta = () => {
  const { canvasPosition, cursorPosition } = useAppContext();
  const { canvasPosition, cursorPosition, pixels, config } = useAppContext();
  const { isOpen, onOpen, onOpenChange } = useDisclosure();

  return (
@@ -30,7 +67,11 @@ export const CanvasMeta = () => {
          </span>
        )}
        <span>
          Pixels: <span>123</span>
          Pixels:{" "}
          <span>
            {pixels.available}/{config.canvas.pixel.maxStack}
          </span>{" "}
          <PlaceCountdown />
        </span>
        <span>
          Users Online: <span>321</span>
+12 −2
Original line number Diff line number Diff line
@@ -6,12 +6,12 @@ import {
  useState,
} from "react";
import {
  AuthSession,
  ClientConfig,
  IAppContext,
  ICanvasPosition,
  IPosition,
} from "../types";
import { AuthSession } from "@sc07-canvas/lib/src/net";
} from "@sc07-canvas/lib/src/net";
import Network from "../lib/network";

const appContext = createContext<IAppContext>({} as any);
@@ -24,6 +24,8 @@ export const AppContext = ({ children }: PropsWithChildren) => {
  const [canvasPosition, setCanvasPosition] = useState<ICanvasPosition>();
  const [cursorPosition, setCursorPosition] = useState<IPosition>();

  const [pixels, setPixels] = useState({ available: 0 });

  useEffect(() => {
    function handleConfig(config: ClientConfig) {
      console.info("Server sent config", config);
@@ -34,14 +36,21 @@ export const AppContext = ({ children }: PropsWithChildren) => {
      setAuth(user);
    }

    function handlePixels(pixels: { available: number }) {
      setPixels(pixels);
    }

    Network.on("user", handleUser);
    Network.on("config", handleConfig);
    Network.waitFor("pixels").then(([data]) => handlePixels(data));
    Network.on("pixels", handlePixels);

    Network.socket.connect();

    return () => {
      Network.off("user", handleUser);
      Network.off("config", handleConfig);
      Network.off("pixels", handlePixels);
    };
  }, []);

@@ -54,6 +63,7 @@ export const AppContext = ({ children }: PropsWithChildren) => {
        setCanvasPosition,
        cursorPosition,
        setCursorPosition,
        pixels,
      }}
    >
      {config ? children : "Loading..."}
+18 −10
Original line number Diff line number Diff line
import EventEmitter from "eventemitter3";
import { ClientConfig, IPalleteContext, IPosition, Pixel } from "../types";
import {
  ClientConfig,
  IPalleteContext,
  IPosition,
  Pixel,
} from "@sc07-canvas/lib/src/net";
import Network from "./network";
import {
  ClickEvent,
@@ -30,7 +35,7 @@ export class Canvas extends EventEmitter<CanvasEvents> {
  private pixels: {
    [x_y: string]: { color: number; type: "full" | "pending" };
  } = {};
  private lastPlace: number | undefined;
  lastPlace: number | undefined;

  constructor(
    config: ClientConfig,
@@ -52,6 +57,9 @@ export class Canvas extends EventEmitter<CanvasEvents> {
    this.PanZoom.addListener("click", this.handleMouseDown.bind(this));

    Network.waitFor("canvas").then(([pixels]) => this.handleBatch(pixels));
    Network.waitFor("pixelLastPlaced").then(
      ([time]) => (this.lastPlace = time)
    );

    this.draw();
  }
@@ -133,14 +141,13 @@ export class Canvas extends EventEmitter<CanvasEvents> {
  place(x: number, y: number) {
    if (!this.Pallete.getSelectedColor()) return;

    if (this.lastPlace) {
      if (this.lastPlace + this.config.pallete.pixel_cooldown > Date.now()) {
        console.log("cannot place; cooldown");
        return;
      }
    }

    this.lastPlace = Date.now();
    // TODO: redo this as the server now verifies placements differently
    // if (this.lastPlace) {
    //   if (this.lastPlace + this.config.pallete.pixel_cooldown > Date.now()) {
    //     console.log("cannot place; cooldown");
    //     return;
    //   }
    // }

    Network.socket
      .emitWithAck("place", {
@@ -150,6 +157,7 @@ export class Canvas extends EventEmitter<CanvasEvents> {
      })
      .then((ack) => {
        if (ack.success) {
          this.lastPlace = Date.now();
          this.handlePixel(ack.data);
        } else {
          // TODO: handle undo pixel
+10 −0
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@ export interface INetworkEvents {
  user: (user: AuthSession) => void;
  config: (user: ClientConfig) => void;
  canvas: (pixels: string[]) => void;
  pixels: (data: { available: number }) => void;
  pixelLastPlaced: (time: number) => void;
}

type SentEventValue<K extends keyof INetworkEvents> = EventEmitter.ArgumentMap<
@@ -45,6 +47,14 @@ class Network extends EventEmitter<INetworkEvents> {
      this._emit("canvas", pixels);
    });

    this.socket.on("availablePixels", (count) => {
      this._emit("pixels", { available: count });
    });

    this.socket.on("pixelLastPlaced", (time) => {
      this._emit("pixelLastPlaced", time);
    });

    // this.socket.on("config", (config) => {
    //   Pallete.load(config.pallete);
    //   Canvas.load(config.canvas);
+21 −0
Original line number Diff line number Diff line
import { type ClientConfig } from "./net";

export const CanvasLib = new (class {
  /**
   * Get pixel cooldown
   *
   * @param pixelNumber What pixel is this
   * @param config
   * @returns Seconds to take to give the pixel
   */
  getPixelCooldown(pixelNumber: number, config: ClientConfig) {
    return pixelNumber * config.canvas.pixel.cooldown;
    // const factorial = (n: number) => (n == 0 ? 1 : n * factorial(n - 1));

    // return (
    //   config.canvas.pixel.cooldown *
    //   config.canvas.pixel.multiplier *
    //   (2 + pixelNumber + factorial(pixelNumber))
    // );
  }
})();
Loading