Commit 5fe97161 authored by Ategon Dev's avatar Ategon Dev
Browse files

Merge branch canvas:main into main

parents 2491f201 18449235
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -6602,6 +6602,12 @@
      "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
      "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="
    },
    "node_modules/@types/uuid": {
      "version": "10.0.0",
      "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
      "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
      "dev": true
    },
    "node_modules/@typescript-eslint/eslint-plugin": {
      "version": "5.62.0",
      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
@@ -16492,6 +16498,7 @@
        "rate-limit-redis": "^4.2.0",
        "redis": "^4.6.12",
        "socket.io": "^4.7.2",
        "uuid": "^10.0.0",
        "winston": "^3.11.0"
      },
      "devDependencies": {
@@ -16499,6 +16506,7 @@
        "@types/cors": "^2.8.17",
        "@types/express": "^4.17.17",
        "@types/express-session": "^1.17.7",
        "@types/uuid": "^10.0.0",
        "@typescript-eslint/eslint-plugin": "^7.1.0",
        "@typescript-eslint/parser": "^7.1.0",
        "dotenv": "^16.3.1",
@@ -16795,6 +16803,18 @@
      "engines": {
        "node": ">= 0.8"
      }
    },
    "packages/server/node_modules/uuid": {
      "version": "10.0.0",
      "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
      "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
      "funding": [
        "https://github.com/sponsors/broofa",
        "https://github.com/sponsors/ctavan"
      ],
      "bin": {
        "uuid": "dist/bin/uuid"
      }
    }
  }
}
+3 −1
Original line number Diff line number Diff line
@@ -7,7 +7,9 @@ import Bugsnag from "@bugsnag/js";
import BugsnagPluginReact from "@bugsnag/plugin-react";
import BugsnagPerformance from "@bugsnag/browser-performance";

let ErrorBoundary: any = <></>;
let ErrorBoundary: any = ({ children }: React.PropsWithChildren) => (
  <>{children}</>
);

if (import.meta.env.VITE_BUGSNAG_KEY) {
  Bugsnag.start({
+34 −10
Original line number Diff line number Diff line
@@ -102,10 +102,25 @@ export class Canvas extends EventEmitter<CanvasEvents> {
    if (Object.keys(this.pixels).length > 0)
      Network.clearPreviousState("canvas");

    Network.waitForState("canvas").then(([pixels]) => {
      console.log("loadConfig just received new canvas data");
      this.handleBatch(pixels);
    // Network.waitForState("canvas").then(([pixels]) => {
    //   console.log("loadConfig just received new canvas data");
    //   this.handleBatch(pixels);
    // });

    Network.on("canvas", (start, end, pixels) => {
      console.log("[Canvas] received canvas section");
      this.handleBatch(start, end, pixels);
    });

    const chunks = Network.getCanvasChunks();
    console.log(`[Canvas] Received ${chunks.length} chunks to load`);
    let loaded = 0;
    for (const chunk of chunks) {
      console.log(`[Canvas] Loading canvas chunk ${loaded}...`);
      this.handleBatch(chunk.start, chunk.end, chunk.pixels);

      loaded++;
    }
  }

  hasConfig() {
@@ -267,27 +282,36 @@ export class Canvas extends EventEmitter<CanvasEvents> {
    getRenderer().usePixels(serializeBuild);
  };

  handleBatch = (pixels: string[]) => {
  handleBatch = (
    start: [x: number, y: number],
    end: [x: number, y: number],
    pixels: string[]
  ) => {
    if (!this.config.canvas) {
      throw new Error("handleBatch called with no config");
    }

    let serializeBuild: CanvasPixel[] = [];
    const width = end[0] - start[0];
    const height = end[1] - start[1];

    for (let x = 0; x < this.config.canvas.size[0]; x++) {
      for (let y = 0; y < this.config.canvas.size[1]; y++) {
        const hex = pixels[this.config.canvas.size[0] * y + x];
    for (let x = 0; x < width; x++) {
      for (let y = 0; y < height; y++) {
        const hex = pixels[width * y + x];
        const palette = this.Pallete.getColorFromHex(hex);

        const canvasX = x + start[0];
        const canvasY = y + start[1];

        // we still store a copy of the pixels in this instance for non-rendering functions
        this.pixels[x + "_" + y] = {
        this.pixels[canvasX + "_" + canvasY] = {
          type: "full",
          color: palette?.id || -1,
        };

        serializeBuild.push({
          x,
          y,
          x: canvasX,
          y: canvasY,
          hex: hex === "transparent" ? "null" : hex,
        });
      }
+38 −44
Original line number Diff line number Diff line
@@ -8,8 +8,6 @@ export type CanvasPixel = {
  hex: string;
};

const bezier = (n: number) => n * n * (3 - 2 * n);

const isWorker = () => {
  return (
    // @ts-ignore
@@ -41,8 +39,18 @@ export class CanvasRenderer extends EventEmitter<RendererEvents> {
  private blank?: RCanvas;
  private blank_ctx?: RContext;

  private pixels: CanvasPixel[] = [];
  private allPixels: CanvasPixel[] = [];
  /**
   * Pixels that need to be drawn next draw call
   *
   * Key = x,y (eg 0,0)
   */
  private pixels: Map<string, string> = new Map();
  /**
   * Every pixel
   *
   * Key = x,y (eg 0,0)
   */
  private allPixels: Map<string, string> = new Map();
  private isWorker = isWorker();

  private _stopRender = false;
@@ -87,37 +95,15 @@ export class CanvasRenderer extends EventEmitter<RendererEvents> {
  }

  usePixels(pixels: CanvasPixel[], replace = false) {
    if (replace) {
      this.pixels = pixels;
      this.allPixels = pixels;
    } else {
    for (const pixel of pixels) {
      this.usePixel(pixel);
    }
  }
  }

  usePixel(pixel: CanvasPixel) {
    {
      let existing = this.pixels.find(
        (p) => p.x === pixel.x && p.y === pixel.y
      );
      if (existing) {
        this.pixels.splice(this.pixels.indexOf(existing), 1);
      }
    }

    {
      let existing = this.allPixels.find(
        (p) => p.x === pixel.x && p.y === pixel.y
      );
      if (existing) {
        this.allPixels.splice(this.allPixels.indexOf(existing), 1);
      }
    }

    this.pixels.push(pixel);
    this.allPixels.push(pixel);
    let key = pixel.x + "," + pixel.y;
    this.pixels.set(key, pixel.hex);
    this.allPixels.set(key, pixel.hex);
  }

  startRender() {
@@ -179,16 +165,19 @@ export class CanvasRenderer extends EventEmitter<RendererEvents> {
  draw() {
    const start = performance.now();

    const pixels = [...this.pixels];
    this.pixels = [];
    const pixels = new Map(this.pixels);
    this.pixels.clear();

    if (pixels.length) {
      console.log("[CanvasRenderer#draw] drawing " + pixels.length + " pixels");
    if (pixels.size) {
      console.log("[CanvasRenderer#draw] drawing " + pixels.size + " pixels");
    }

    for (const pixel of pixels) {
      this.ctx.fillStyle = pixel.hex === "null" ? "#fff" : "#" + pixel.hex;
      this.ctx.fillRect(pixel.x, pixel.y, 1, 1);
    for (const [x_y, hex] of pixels) {
      const x = parseInt(x_y.split(",")[0]);
      const y = parseInt(x_y.split(",")[1]);

      this.ctx.fillStyle = hex === "null" ? "#fff" : "#" + hex;
      this.ctx.fillRect(x, y, 1, 1);
    }

    const diff = performance.now() - start;
@@ -219,9 +208,12 @@ export class CanvasRenderer extends EventEmitter<RendererEvents> {
    this.ctx.fillStyle = "#fff";
    this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);

    for (const pixel of this.allPixels) {
      this.ctx.fillStyle = pixel.hex === "null" ? "#fff" : "#" + pixel.hex;
      this.ctx.fillRect(pixel.x, pixel.y, 1, 1);
    for (const [x_y, hex] of this.allPixels) {
      const x = parseInt(x_y.split(",")[0]);
      const y = parseInt(x_y.split(",")[1]);

      this.ctx.fillStyle = hex === "null" ? "#fff" : "#" + hex;
      this.ctx.fillRect(x, y, 1, 1);
    }
  }

@@ -234,11 +226,13 @@ export class CanvasRenderer extends EventEmitter<RendererEvents> {

      ctx.clearRect(0, 0, canvas.width, canvas.height);

      for (const pixel of this.allPixels) {
        if (pixel.hex !== "null") continue;
      for (const [x_y, hex] of this.allPixels) {
        if (hex !== "null") continue;
        const x = parseInt(x_y.split(",")[0]);
        const y = parseInt(x_y.split(",")[1]);

        ctx.fillStyle = "rgba(0,140,0,0.5)";
        ctx.fillRect(pixel.x, pixel.y, 1, 1);
        ctx.fillRect(x, y, 1, 1);
      }
    }
  }
+23 −3
Original line number Diff line number Diff line
@@ -20,7 +20,11 @@ export interface INetworkEvents {
  user: (user: AuthSession) => void;
  standing: (standing: IAccountStanding) => void;
  config: (user: ClientConfig) => void;
  canvas: (pixels: string[]) => void;
  canvas: (
    start: [x: number, y: number],
    end: [x: number, y: number],
    pixels: string[]
  ) => void;
  pixels: (data: { available: number }) => void;
  pixelLastPlaced: (time: number) => void;
  online: (count: number) => void;
@@ -55,6 +59,12 @@ class Network extends EventEmitter<INetworkEvents> {
    [key in keyof INetworkEvents]?: SentEventValue<key>;
  } = {};

  private canvasChunks: {
    start: [number, number];
    end: [number, number];
    pixels: string[];
  }[] = [];

  constructor() {
    super();

@@ -123,8 +133,14 @@ class Network extends EventEmitter<INetworkEvents> {
      this.emit("config", config);
    });

    this.socket.on("canvas", (pixels) => {
      this.acceptState("canvas", pixels);
    this.socket.on("canvas", (start, end, pixels) => {
      // this.acceptState("canvas", start, end, pixels);
      this.emit("canvas", start, end, pixels);
      this.canvasChunks.push({ start, end, pixels });
    });

    this.socket.on("clearCanvasChunks", () => {
      this.canvasChunks = [];
    });

    this.socket.on("availablePixels", (count) => {
@@ -191,6 +207,10 @@ class Network extends EventEmitter<INetworkEvents> {
    delete this.stateEvents[ev];
  }

  getCanvasChunks() {
    return this.canvasChunks;
  }

  /**
   * Wait for event, either being already sent, or new one
   *
Loading