Skip to content

Commit

Permalink
tracking: reimplement game tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
GGonryun committed Aug 15, 2024
1 parent aa37106 commit e5e81ea
Show file tree
Hide file tree
Showing 23 changed files with 783 additions and 8 deletions.
22 changes: 22 additions & 0 deletions apps/charity/pages/api/cron/flush-game-tracks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { prisma } from '@worksheets/prisma';
import { createClient } from '@worksheets/services/kv';
import {
gatherLoot,
generateGameTracks,
rewardUsers,
sendNotifications,
} from '@worksheets/services/tracks';
import { createCronJob } from '@worksheets/util/cron';
import { asyncEagerIterate } from '@worksheets/util/generators';

export default createCronJob(async () => {
const kv = createClient();

const tracks = await asyncEagerIterate(generateGameTracks(kv));

const { loots, notifications } = await gatherLoot(prisma, tracks);

// for every item we'll update the user's inventory
await rewardUsers(prisma, loots);
await sendNotifications(prisma, notifications);
});
30 changes: 29 additions & 1 deletion libs/data/quests/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Prisma } from '@worksheets/prisma';
import { TOKENS_PER_REFERRAL_ACCOUNT } from '@worksheets/util/settings';
import {
PER_GAME_PLAY_REWARD,
TOKENS_PER_REFERRAL_ACCOUNT,
} from '@worksheets/util/settings';

export const QUESTS: Prisma.PlatformQuestUncheckedCreateInput[] = [
// prize wheels
Expand Down Expand Up @@ -362,6 +365,31 @@ export const QUESTS: Prisma.PlatformQuestUncheckedCreateInput[] = [
},
},
},
// infinites
{
id: 'PLAY_MINUTES_INFINITE',
order: 1000,
version: 0,
taskId: 'PLAY_MINUTES_INFINITE',
loot: {},
},
{
id: 'PLAY_GAME_INFINITE',
order: 1001,
version: 0,
taskId: 'PLAY_GAME_INFINITE',
loot: {
createMany: {
data: [
{
itemId: '1',
quantity: PER_GAME_PLAY_REWARD,
chance: 1,
},
],
},
},
},
{
id: 'ADD_FRIEND_INFINITE',
order: 1002,
Expand Down
27 changes: 27 additions & 0 deletions libs/data/tasks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,33 @@ export const TASKS: Prisma.TaskUncheckedCreateInput[] = [
'Earn an bonus entries every time someone enters the raffle using your referral link',
data: {},
},
// infinites
{
version: 3,
id: 'PLAY_MINUTES_INFINITE',
type: TaskType.PLAY_MINUTES,
category: TaskCategory.GAMEPLAY,
frequency: TaskFrequency.INFINITE,
requiredRepetitions: 60, // seconds
maxRepetitions: MAX_INT,
name: 'Play Games for 1 Minute',
description:
'Earn rewards for every a minute you play a game on Charity Games.',
data: {},
},
{
version: 2,
id: 'PLAY_MINUTES_5_INFINITE',
type: TaskType.PLAY_MINUTES,
category: TaskCategory.GAMEPLAY,
frequency: TaskFrequency.INFINITE,
requiredRepetitions: 300, // seconds
maxRepetitions: MAX_INT,
name: 'Play Games for 5 Minutes',
description:
'Earn rewards for every 5 minutes you play a game on Charity Games.',
data: {},
},
{
version: 1,
id: 'PLAY_GAME_INFINITE',
Expand Down
3 changes: 3 additions & 0 deletions libs/prisma/src/schemas/main.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,9 @@ enum TaskStatus {

enum TaskType {
PLAY_GAME
PLAY_MINUTES
REFERRAL_PLAY_MINUTES
FRIEND_PLAY_MINUTES
ADD_FRIEND
ADD_REFERRAL
RAFFLE_PARTICIPATION
Expand Down
7 changes: 5 additions & 2 deletions libs/services/tasks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,10 @@ export class TasksService {
}

async trackGameActions(opts: {
type: Extract<TaskType, 'PLAY_GAME' | 'SUBMIT_LEADERBOARD_SCORE'>;
type: Extract<
TaskType,
'PLAY_GAME' | 'PLAY_MINUTES' | 'SUBMIT_LEADERBOARD_SCORE'
>;
gameId: string;
userId: string;
repetitions: number;
Expand Down Expand Up @@ -740,7 +743,7 @@ export class TasksService {
async trackGameQuests(opts: {
userId: string;
gameId: string;
type: Extract<TaskType, 'PLAY_GAME'>;
type: Extract<TaskType, 'PLAY_GAME' | 'PLAY_MINUTES'>;
repetitions: number;
}): Promise<TaskProgress[]> {
console.info(
Expand Down
1 change: 0 additions & 1 deletion libs/services/tracks/TODO

This file was deleted.

109 changes: 109 additions & 0 deletions libs/services/tracks/src/caches.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { TRPCError } from '@trpc/server';
import { Prisma, PrismaClient } from '@worksheets/prisma';

/**
* Temporary local in-memory cache for item data
* Use this if you're writing a function that needs to fetch item data multiple times
*/
export const itemCache = (db: PrismaClient) => {
const items: Record<string, Prisma.ItemGetPayload<true>> = {};

const get = async (itemId: string) => {
if (items[itemId]) {
return items[itemId];
}
const item = await db.item.findUnique({
where: { id: itemId },
});

if (!item) {
throw new Error(`Item not found: ${itemId}`);
}

items[itemId] = item;

return item;
};

const safeGet = async (itemId: string) => {
try {
return await get(itemId);
} catch (error) {
return null;
}
};

return { get, safeGet };
};

/**
* Temporary local in-memory cache for game data
* Use this if you're writing a function that needs to fetch game data multiple times
*/
export const gameCache = (db: PrismaClient) => {
const games: Record<string, Prisma.GameGetPayload<true>> = {};

const get = async (gameId: string) => {
if (games[gameId]) {
return games[gameId];
}
const game = await db.game.findUnique({
where: { id: gameId },
});

if (!game) {
throw new Error(`Game not found: ${gameId}`);
}

games[gameId] = game;
return game;
};

const safeGet = async (gameId: string) => {
try {
return await get(gameId);
} catch (error) {
return null;
}
};

return { get, safeGet };
};

/**
* A temporary local in-memory cache for user data
* If the user is not found in the cache, it will be fetched from the database
*/
export const userCache = (db: PrismaClient) => {
const users: Record<string, Prisma.UserGetPayload<true>> = {};

const get = async (userId: string) => {
if (users[userId]) {
return users[userId];
}
const user = await db.user.findUnique({
where: { id: userId },
});

if (!user)
throw new TRPCError({
code: 'NOT_FOUND',
message: 'User not found',
cause: { userId },
});

if (user) {
users[userId] = user;
}
return user;
};

const safeGet = async (userId: string) => {
try {
return await get(userId);
} catch (error) {
return null;
}
};
return { get, safeGet };
};
Loading

0 comments on commit e5e81ea

Please sign in to comment.