Merge branch 'improve_stack_gain' into 'main'

Improve handling of the user pixel stack

See merge request sc07/canvas!8
This commit is contained in:
Grant 2024-07-13 00:03:06 +00:00
commit 85dd5d76b8
8 changed files with 58 additions and 23 deletions

View File

@ -18,6 +18,7 @@ const getTimeLeft = (pixels: { available: number }, config: ClientConfig) => {
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;
@ -43,7 +44,7 @@ const PlaceCountdown = () => {
return (
<>
{timeLeft
? pixels.available + 1 < config.canvas.pixel.maxStack && timeLeft + "s"
? pixels.available < config.canvas.pixel.maxStack && timeLeft + "s"
: ""}
</>
);

View File

@ -53,11 +53,9 @@ export class Canvas extends EventEmitter<CanvasEvents> {
this.PanZoom.addListener("click", this.handleMouseDown.bind(this));
this.PanZoom.addListener("longPress", this.handleLongPress);
Network.waitForState("pixelLastPlaced").then(
([time]) => (this.lastPlace = time)
);
Network.on("pixel", this.handlePixel);
Network.on("square", this.handleSquare);
Network.on("pixelLastPlaced", this.handlePixelLastPlaced);
}
destroy() {
@ -70,6 +68,7 @@ export class Canvas extends EventEmitter<CanvasEvents> {
Network.off("pixel", this.handlePixel);
Network.off("square", this.handleSquare);
Network.off("pixelLastPlaced", this.handlePixelLastPlaced);
}
/**
@ -309,6 +308,10 @@ export class Canvas extends EventEmitter<CanvasEvents> {
getRenderer().usePixel({ x, y, hex: palette?.hex || "null" });
};
handlePixelLastPlaced = (time: number) => {
this.lastPlace = time;
};
Pallete = {
getColor: (colorId: number) => {
return this.config.pallete.colors.find((c) => c.id === colorId);
@ -358,7 +361,6 @@ export class Canvas extends EventEmitter<CanvasEvents> {
)
.then((ack) => {
if (ack.success) {
this.lastPlace = Date.now();
this.handlePixel(ack.data);
} else {
console.warn(

View File

@ -12,7 +12,7 @@ Table User {
display_name String
picture_url String
profile_url String
lastPixelTime DateTime [default: `now()`, not null]
lastTimeGainStarted DateTime [default: `now()`, not null]
pixelStack Int [not null, default: 0]
undoExpires DateTime
isAdmin Boolean [not null, default: false]

View File

@ -0,0 +1 @@
ALTER TABLE "User" RENAME COLUMN "lastPixelTime" TO "lastTimeGainStarted";

View File

@ -25,7 +25,7 @@ model User {
picture_url String?
profile_url String?
lastPixelTime DateTime @default(now()) // the time the last pixel was placed at
lastTimeGainStarted DateTime @default(now()) // the time base used to determine the amount of stack the user should gain
pixelStack Int @default(0) // amount of pixels stacked for this user
undoExpires DateTime? // when the undo for the most recent pixel expires at

View File

@ -430,11 +430,6 @@ class Canvas {
},
});
await prisma.user.update({
where: { sub: user.sub },
data: { lastPixelTime: new Date() },
});
// maybe only update specific element?
// i don't think it needs to be awaited
await this.updateCanvasRedisAtPos(x, y);

View File

@ -63,7 +63,7 @@ prisma.paletteColor
Logger.error("Failed to get pallete colors", e);
});
const getClientConfig = (): ClientConfig => {
export const getClientConfig = (): ClientConfig => {
return {
version: commitHash,
pallete: {
@ -122,12 +122,9 @@ export class SocketServer {
continue;
}
// time in seconds since last pixel placement
// TODO: this causes a mismatch between placement times
// - going from 0 stack to 6 stack has a steady increase between each
// - going from 3 stack to 6 stack takes longer
// time in seconds since last stack gain (including a potential bonus depending on previously remaining time)
const timeSinceLastPlace =
(Date.now() - user.lastPixelTime.getTime()) / 1000;
(Date.now() - user.lastTimeGainStarted.getTime()) / 1000;
const cooldown = CanvasLib.getPixelCooldown(
user.pixelStack + 1,
getClientConfig()
@ -180,7 +177,7 @@ export class SocketServer {
if (user) {
socket.emit("availablePixels", user.pixelStack);
socket.emit("pixelLastPlaced", user.lastPixelTime.getTime());
socket.emit("pixelLastPlaced", user.lastTimeGainStarted.getTime());
const ban = user.getBan();
socket.emit(

View File

@ -10,7 +10,8 @@ import {
import { Ban, User as UserDB } from "@prisma/client";
import { Instance } from "./Instance";
import { ConditionalPromise } from "../lib/utils";
import { CanvasLib } from "@sc07-canvas/lib/src/canvas";
import { getClientConfig } from "../lib/SocketServer";
const Logger = getLogger();
/**
@ -37,7 +38,7 @@ export class User {
static instances: Map<string, User> = new Map();
sub: string;
lastPixelTime: Date;
lastTimeGainStarted: Date;
pixelStack: number;
authSession?: AuthSession;
undoExpires?: Date;
@ -54,7 +55,7 @@ export class User {
Logger.debug("User class instansiated for " + data.sub);
this.sub = data.sub;
this.lastPixelTime = data.lastPixelTime;
this.lastTimeGainStarted = data.lastTimeGainStarted;
this.pixelStack = data.pixelStack;
this.undoExpires = data.undoExpires || undefined;
@ -80,7 +81,7 @@ export class User {
if (!userData) throw new UserNotFound();
this.lastPixelTime = userData.lastPixelTime;
this.lastTimeGainStarted = userData.lastTimeGainStarted;
this.pixelStack = userData.pixelStack;
this.undoExpires = userData.undoExpires || undefined;
this.isAdmin = userData.isAdmin;
@ -120,15 +121,53 @@ export class User {
}
async modifyStack(modifyBy: number): Promise<any> {
let new_date = new Date();
if (modifyBy > 0) {
let cooldown_to_add = 0.0;
for (let i = 0; i < modifyBy; i++) {
cooldown_to_add += CanvasLib.getPixelCooldown(
this.pixelStack + i + 1,
getClientConfig()
);
}
new_date = new Date(
this.lastTimeGainStarted.valueOf() + cooldown_to_add * 1000
);
} else if (modifyBy < 0) {
const cooldown_before_change_s = CanvasLib.getPixelCooldown(
this.pixelStack + 1,
getClientConfig()
);
const cooldown_after_change_s = CanvasLib.getPixelCooldown(
this.pixelStack + 1 + modifyBy,
getClientConfig()
);
const would_gain_next_at_timestamp_ms =
this.lastTimeGainStarted.valueOf() + cooldown_before_change_s * 1000;
const time_before_next =
would_gain_next_at_timestamp_ms - Date.now().valueOf();
// To avoid issue if a negative value is present for some reason
if (time_before_next > 0) {
if (time_before_next < cooldown_after_change_s * 1000) {
new_date = new Date(
Date.now() - cooldown_after_change_s * 1000 + time_before_next
);
}
}
}
const updatedUser = await prisma.user.update({
where: { sub: this.sub },
data: {
pixelStack: { increment: modifyBy },
lastTimeGainStarted: new_date,
},
});
for (const socket of this.sockets) {
socket.emit("availablePixels", updatedUser.pixelStack);
socket.emit("pixelLastPlaced", updatedUser.lastTimeGainStarted.getTime());
}
// we just modified the user data, so we should force an update