From 0ab45349cbb8239e34d4d75e03c701c275a24ad3 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 21 Feb 2025 05:09:17 +0000 Subject: [PATCH 01/27] Fix issue #391: Homes --- .../migrations/0195_add_home_types.sql | 9 + app/drizzle/schema.ts | 88 +++++++++ app/src/app/home/page.tsx | 118 +++++++++++- app/src/server/api/routers/home.ts | 182 +++++++++++++++++- app/tests/libs/home.test.ts | 78 ++++++++ app/tests/utils/db.ts | 14 ++ 6 files changed, 483 insertions(+), 6 deletions(-) create mode 100644 app/drizzle/migrations/0195_add_home_types.sql create mode 100644 app/tests/libs/home.test.ts create mode 100644 app/tests/utils/db.ts diff --git a/app/drizzle/migrations/0195_add_home_types.sql b/app/drizzle/migrations/0195_add_home_types.sql new file mode 100644 index 00000000..765fb9a0 --- /dev/null +++ b/app/drizzle/migrations/0195_add_home_types.sql @@ -0,0 +1,9 @@ +INSERT INTO `HomeType` (`id`, `name`, `regenBonus`, `storageSlots`, `cost`) +VALUES + ('one-bed-apartment', 'One Bed Room Apartment', 20, 5, 3000000), + ('studio-apartment', 'Studio Apartment', 30, 10, 7000000), + ('two-bed-house', 'Two Bed Room House', 40, 15, 13000000), + ('town-house', 'Town House', 50, 20, 30000000), + ('small-mansion', 'Small Mansion', 60, 25, 40000000), + ('small-estate', 'Small Estate', 70, 30, 50000000), + ('large-estate', 'Large Estate', 100, 40, 70000000); diff --git a/app/drizzle/schema.ts b/app/drizzle/schema.ts index 5fa296bc..2aaed519 100644 --- a/app/drizzle/schema.ts +++ b/app/drizzle/schema.ts @@ -387,6 +387,94 @@ export const bloodlineRollsRelations = relations(bloodlineRolls, ({ one }) => ({ }), })); +export const homeType = mysqlTable( + "HomeType", + { + id: varchar("id", { length: 191 }).primaryKey().notNull(), + name: varchar("name", { length: 191 }).notNull(), + regenBonus: int("regenBonus").notNull(), + storageSlots: int("storageSlots").notNull(), + cost: bigint("cost", { mode: "number" }).notNull(), + createdAt: datetime("createdAt", { mode: "date", fsp: 3 }) + .default(sql`(CURRENT_TIMESTAMP(3))`) + .notNull(), + updatedAt: datetime("updatedAt", { mode: "date", fsp: 3 }) + .default(sql`(CURRENT_TIMESTAMP(3))`) + .notNull(), + }, + (table) => { + return { + nameKey: uniqueIndex("HomeType_name_key").on(table.name), + }; + }, +); + +export const userHome = mysqlTable( + "UserHome", + { + id: varchar("id", { length: 191 }).primaryKey().notNull(), + userId: varchar("userId", { length: 191 }).notNull(), + homeTypeId: varchar("homeTypeId", { length: 191 }).notNull(), + createdAt: datetime("createdAt", { mode: "date", fsp: 3 }) + .default(sql`(CURRENT_TIMESTAMP(3))`) + .notNull(), + updatedAt: datetime("updatedAt", { mode: "date", fsp: 3 }) + .default(sql`(CURRENT_TIMESTAMP(3))`) + .notNull(), + }, + (table) => { + return { + userIdKey: uniqueIndex("UserHome_userId_key").on(table.userId), + }; + }, +); + +export const userHomeStorage = mysqlTable( + "UserHomeStorage", + { + id: varchar("id", { length: 191 }).primaryKey().notNull(), + userHomeId: varchar("userHomeId", { length: 191 }).notNull(), + itemId: varchar("itemId", { length: 191 }).notNull(), + slot: int("slot").notNull(), + createdAt: datetime("createdAt", { mode: "date", fsp: 3 }) + .default(sql`(CURRENT_TIMESTAMP(3))`) + .notNull(), + updatedAt: datetime("updatedAt", { mode: "date", fsp: 3 }) + .default(sql`(CURRENT_TIMESTAMP(3))`) + .notNull(), + }, + (table) => { + return { + storageKey: uniqueIndex("UserHomeStorage_storage_key").on( + table.userHomeId, + table.slot + ), + }; + }, +); + +export const userHomeRelations = relations(userHome, ({ one }) => ({ + user: one(userData, { + fields: [userHome.userId], + references: [userData.userId], + }), + homeType: one(homeType, { + fields: [userHome.homeTypeId], + references: [homeType.id], + }), +})); + +export const userHomeStorageRelations = relations(userHomeStorage, ({ one }) => ({ + userHome: one(userHome, { + fields: [userHomeStorage.userHomeId], + references: [userHome.id], + }), + item: one(item, { + fields: [userHomeStorage.itemId], + references: [item.id], + }), +})); + export const captcha = mysqlTable( "Captcha", { diff --git a/app/src/app/home/page.tsx b/app/src/app/home/page.tsx index f818a836..aaf3fa5d 100644 --- a/app/src/app/home/page.tsx +++ b/app/src/app/home/page.tsx @@ -20,6 +20,41 @@ export default function Home() { const { userData, sectorVillage, access, ownVillage, updateUser } = useRequireInVillage("/home"); + const { data, refetch } = api.home.getHome.useQuery(undefined, { + enabled: !!access && !!ownVillage, + }); + + const { mutate: upgradeHome, isPending: isUpgrading } = + api.home.upgradeHome.useMutation({ + onSuccess: async (data) => { + showMutationToast(data); + if (data.success) { + await refetch(); + await updateUser(); + } + }, + }); + + const { mutate: storeItem, isPending: isStoringItem } = + api.home.storeItem.useMutation({ + onSuccess: async (data) => { + showMutationToast(data); + if (data.success) { + await refetch(); + } + }, + }); + + const { mutate: removeItem, isPending: isRemovingItem } = + api.home.removeItem.useMutation({ + onSuccess: async (data) => { + showMutationToast(data); + if (data.success) { + await refetch(); + } + }, + }); + const { mutate: toggleSleep, isPending: isTogglingSleep } = api.home.toggleSleep.useMutation({ onSuccess: async (data) => { @@ -98,13 +133,88 @@ export default function Home() { <> - WIP +
+ {data?.home ? ( +
+

{data.home.name}

+

Regeneration Bonus: +{data.home.regenBonus}

+

Storage Slots: {data.home.storageSlots}

+
+ ) : ( +

You don't own a home yet

+ )} + +
+ {data?.availableHomes.map((home) => ( +
+

{home.name}

+

Regeneration: +{home.regenBonus}

+

Storage: {home.storageSlots} slots

+

Cost: {home.cost.toLocaleString()} Ryo

+ {data.home?.id !== home.id && ( + + )} +
+ ))} +
+
- - WIP + + {data?.home ? ( +
+ {Array.from({ length: data.home.storageSlots }).map((_, i) => { + const storedItem = data.storage?.find((s) => s.slot === i); + return ( +
+ {storedItem ? ( + + ) : ( + + )} +
+ ); + })} +
+ ) : ( +

Purchase a home to store items

+ )}
)} diff --git a/app/src/server/api/routers/home.ts b/app/src/server/api/routers/home.ts index 5d89e87b..9c02f54d 100644 --- a/app/src/server/api/routers/home.ts +++ b/app/src/server/api/routers/home.ts @@ -1,8 +1,8 @@ import { z } from "zod"; import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; import { baseServerResponse, errorResponse } from "@/server/api/trpc"; -import { eq, gte, and } from "drizzle-orm"; -import { userData } from "@/drizzle/schema"; +import { eq, gte, and, sql } from "drizzle-orm"; +import { userData, userHome, homeType, userHomeStorage } from "@/drizzle/schema"; import { fetchUpdatedUser } from "@/routers/profile"; import { getServerPusher, updateUserOnMap } from "@/libs/pusher"; import { calcIsInVillage } from "@/libs/travel/controls"; @@ -10,6 +10,184 @@ import { fetchSectorVillage } from "@/routers/village"; import type { UserStatus } from "@/drizzle/constants"; export const homeRouter = createTRPCRouter({ + getHome: protectedProcedure + .output( + baseServerResponse.extend({ + home: z.object({ + id: z.string(), + name: z.string(), + regenBonus: z.number(), + storageSlots: z.number(), + cost: z.number(), + }).optional(), + availableHomes: z.array(z.object({ + id: z.string(), + name: z.string(), + regenBonus: z.number(), + storageSlots: z.number(), + cost: z.number(), + })), + storage: z.array(z.object({ + id: z.string(), + slot: z.number(), + itemId: z.string(), + })).optional(), + }), + ) + .query(async ({ ctx }) => { + const { user } = await fetchUpdatedUser({ + client: ctx.drizzle, + userId: ctx.userId, + }); + if (!user) return errorResponse("User not found"); + + const userHomeData = await ctx.drizzle.query.userHome.findFirst({ + where: eq(userHome.userId, ctx.userId), + with: { + homeType: true, + }, + }); + + const availableHomes = await ctx.drizzle.query.homeType.findMany(); + + const storage = userHomeData ? await ctx.drizzle.query.userHomeStorage.findMany({ + where: eq(userHomeStorage.userHomeId, userHomeData.id), + }) : undefined; + + return { + success: true, + message: "Home data retrieved", + home: userHomeData?.homeType, + availableHomes, + storage, + }; + }), + + upgradeHome: protectedProcedure + .input(z.object({ + homeTypeId: z.string(), + })) + .output(baseServerResponse) + .mutation(async ({ ctx, input }) => { + const { user } = await fetchUpdatedUser({ + client: ctx.drizzle, + userId: ctx.userId, + }); + if (!user) return errorResponse("User not found"); + + const selectedHome = await ctx.drizzle.query.homeType.findFirst({ + where: eq(homeType.id, input.homeTypeId), + }); + if (!selectedHome) return errorResponse("Invalid home type"); + + if (user.ryo < selectedHome.cost) { + return errorResponse("Not enough ryo"); + } + + const currentHome = await ctx.drizzle.query.userHome.findFirst({ + where: eq(userHome.userId, ctx.userId), + with: { + homeType: true, + }, + }); + + if (currentHome) { + if (currentHome.homeType.cost >= selectedHome.cost) { + return errorResponse("You already have a better or equal home"); + } + } + + await ctx.drizzle.transaction(async (tx) => { + await tx.update(userData) + .set({ ryo: user.ryo - selectedHome.cost }) + .where(eq(userData.userId, ctx.userId)); + + if (currentHome) { + await tx.update(userHome) + .set({ homeTypeId: selectedHome.id }) + .where(eq(userHome.id, currentHome.id)); + } else { + await tx.insert(userHome).values({ + id: crypto.randomUUID(), + userId: ctx.userId, + homeTypeId: selectedHome.id, + }); + } + }); + + return { + success: true, + message: `Successfully upgraded to ${selectedHome.name}`, + }; + }), + + storeItem: protectedProcedure + .input(z.object({ + itemId: z.string(), + slot: z.number(), + })) + .output(baseServerResponse) + .mutation(async ({ ctx, input }) => { + const userHomeData = await ctx.drizzle.query.userHome.findFirst({ + where: eq(userHome.userId, ctx.userId), + with: { + homeType: true, + }, + }); + if (!userHomeData) return errorResponse("You don't own a home"); + + if (input.slot >= userHomeData.homeType.storageSlots) { + return errorResponse("Invalid storage slot"); + } + + const existingItem = await ctx.drizzle.query.userHomeStorage.findFirst({ + where: and( + eq(userHomeStorage.userHomeId, userHomeData.id), + eq(userHomeStorage.slot, input.slot), + ), + }); + if (existingItem) return errorResponse("Slot already occupied"); + + await ctx.drizzle.insert(userHomeStorage).values({ + id: crypto.randomUUID(), + userHomeId: userHomeData.id, + itemId: input.itemId, + slot: input.slot, + }); + + return { + success: true, + message: "Item stored successfully", + }; + }), + + removeItem: protectedProcedure + .input(z.object({ + slot: z.number(), + })) + .output(baseServerResponse) + .mutation(async ({ ctx, input }) => { + const userHomeData = await ctx.drizzle.query.userHome.findFirst({ + where: eq(userHome.userId, ctx.userId), + }); + if (!userHomeData) return errorResponse("You don't own a home"); + + const result = await ctx.drizzle.delete(userHomeStorage) + .where(and( + eq(userHomeStorage.userHomeId, userHomeData.id), + eq(userHomeStorage.slot, input.slot), + )); + + if (result.rowsAffected === 0) { + return errorResponse("No item found in that slot"); + } + + return { + success: true, + message: "Item removed successfully", + }; + }), + toggleSleep: protectedProcedure .output( baseServerResponse.extend({ diff --git a/app/tests/libs/home.test.ts b/app/tests/libs/home.test.ts new file mode 100644 index 00000000..da80be02 --- /dev/null +++ b/app/tests/libs/home.test.ts @@ -0,0 +1,78 @@ +import { describe, expect, it } from "vitest"; +import { homeType } from "@/drizzle/schema"; + +describe("Home System", () => { + it("should have correct home types", () => { + const homes = [ + { + id: "one-bed-apartment", + name: "One Bed Room Apartment", + regenBonus: 20, + storageSlots: 5, + cost: 3000000n, + }, + { + id: "studio-apartment", + name: "Studio Apartment", + regenBonus: 30, + storageSlots: 10, + cost: 7000000n, + }, + { + id: "two-bed-house", + name: "Two Bed Room House", + regenBonus: 40, + storageSlots: 15, + cost: 13000000n, + }, + { + id: "town-house", + name: "Town House", + regenBonus: 50, + storageSlots: 20, + cost: 30000000n, + }, + { + id: "small-mansion", + name: "Small Mansion", + regenBonus: 60, + storageSlots: 25, + cost: 40000000n, + }, + { + id: "small-estate", + name: "Small Estate", + regenBonus: 70, + storageSlots: 30, + cost: 50000000n, + }, + { + id: "large-estate", + name: "Large Estate", + regenBonus: 100, + storageSlots: 40, + cost: 70000000n, + }, + ]; + + // Verify each home type has the correct properties + homes.forEach((home) => { + expect(home).toHaveProperty("id"); + expect(home).toHaveProperty("name"); + expect(home).toHaveProperty("regenBonus"); + expect(home).toHaveProperty("storageSlots"); + expect(home).toHaveProperty("cost"); + }); + + // Verify homes are ordered by cost + for (let i = 1; i < homes.length; i++) { + expect(homes[i].cost).toBeGreaterThan(homes[i - 1].cost); + } + + // Verify regen bonus and storage slots increase with cost + for (let i = 1; i < homes.length; i++) { + expect(homes[i].regenBonus).toBeGreaterThan(homes[i - 1].regenBonus); + expect(homes[i].storageSlots).toBeGreaterThan(homes[i - 1].storageSlots); + } + }); +}); diff --git a/app/tests/utils/db.ts b/app/tests/utils/db.ts new file mode 100644 index 00000000..e6dc7eb5 --- /dev/null +++ b/app/tests/utils/db.ts @@ -0,0 +1,14 @@ +import { drizzle } from "drizzle-orm/mysql2"; +import mysql from "mysql2/promise"; +import * as schema from "@/drizzle/schema"; + +export async function createTestDatabase() { + const connection = await mysql.createConnection({ + host: "localhost", + user: "root", + password: "root", + database: "theninja", + }); + + return drizzle(connection, { schema, mode: "default" }); +} From 90dcf85e58e9956721adf6384687f6d2c483bad9 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 21 Feb 2025 14:02:55 +0000 Subject: [PATCH 02/27] Fix pr #392: Fix issue #391: Homes --- app/src/app/home/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/app/home/page.tsx b/app/src/app/home/page.tsx index aaf3fa5d..4a654616 100644 --- a/app/src/app/home/page.tsx +++ b/app/src/app/home/page.tsx @@ -30,7 +30,7 @@ export default function Home() { showMutationToast(data); if (data.success) { await refetch(); - await updateUser(); + await updateUser({ home: data.home }); } }, }); From c4ba4c7405f638297c0accf762f02d86317af14f Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 21 Feb 2025 14:11:26 +0000 Subject: [PATCH 03/27] Fix pr #392: Fix issue #391: Homes --- app/drizzle/schema.ts | 4 ++++ app/src/server/api/routers/home.ts | 11 ++++++++++- app/src/server/api/routers/profile.ts | 12 ++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/app/drizzle/schema.ts b/app/drizzle/schema.ts index 2aaed519..86bbeef4 100644 --- a/app/drizzle/schema.ts +++ b/app/drizzle/schema.ts @@ -1601,6 +1601,10 @@ export const userDataRelations = relations(userData, ({ one, many }) => ({ fields: [userData.userId], references: [userNindo.userId], }), + home: one(userHome, { + fields: [userData.userId], + references: [userHome.userId], + }), userQuests: many(questHistory), conversations: many(user2conversation), items: many(userItem), diff --git a/app/src/server/api/routers/home.ts b/app/src/server/api/routers/home.ts index 9c02f54d..0f3b86b5 100644 --- a/app/src/server/api/routers/home.ts +++ b/app/src/server/api/routers/home.ts @@ -67,7 +67,15 @@ export const homeRouter = createTRPCRouter({ .input(z.object({ homeTypeId: z.string(), })) - .output(baseServerResponse) + .output(baseServerResponse.extend({ + home: z.object({ + id: z.string(), + name: z.string(), + regenBonus: z.number(), + storageSlots: z.number(), + cost: z.number(), + }).optional(), + })) .mutation(async ({ ctx, input }) => { const { user } = await fetchUpdatedUser({ client: ctx.drizzle, @@ -118,6 +126,7 @@ export const homeRouter = createTRPCRouter({ return { success: true, message: `Successfully upgraded to ${selectedHome.name}`, + home: selectedHome, }; }), diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index ef89a21b..d902bdde 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1314,6 +1314,11 @@ export const fetchUpdatedUser = async (props: { relationshipB: true, }, }, + home: { + with: { + homeType: true, + }, + }, anbuSquad: { columns: { name: true }, }, @@ -1650,6 +1655,13 @@ export type UserWithRelations = loadout?: { jutsuIds: string[] } | null; userQuests: UserQuest[]; votes?: UserVote | null; + home?: { + id: string; + name: string; + regenBonus: number; + storageSlots: number; + cost: number; + } | null; }) | undefined; From 267f38d21052e3a3a331de7a289ed0ebfb77f757 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Fri, 21 Feb 2025 10:41:51 -0500 Subject: [PATCH 04/27] Change user home to object. Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index d902bdde..cccc9183 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1314,11 +1314,15 @@ export const fetchUpdatedUser = async (props: { relationshipB: true, }, }, - home: { - with: { - homeType: true, - }, - }, + home: user.home + ? { + id: user.home.id, + name: user.home.homeType?.name ?? "Unknown", + regenBonus: user.home.homeType?.regenBonus ?? 0, + storageSlots: user.home.homeType?.storageSlots ?? 0, + cost: user.home.homeType?.cost ?? 0, + } + : null, anbuSquad: { columns: { name: true }, }, From fcc510936c8b0fcb0c6e576e4d0eb973a3ceb205 Mon Sep 17 00:00:00 2001 From: openhands Date: Mon, 24 Feb 2025 21:33:01 +0000 Subject: [PATCH 05/27] Fix pr #392: Fix issue #391: Homes --- app/src/server/api/routers/profile.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index cccc9183..d1d714cf 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1307,6 +1307,7 @@ export const fetchUpdatedUser = async (props: { with: { bloodline: true, clan: true, + userQuests: true, village: { with: { structures: true, From d1ff4a7627efa4fc1a817f969a82d6833012650b Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:55:49 -0500 Subject: [PATCH 06/27] Make userQuests optional Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index 88711de0..c698f173 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1667,7 +1667,7 @@ export type UserWithRelations = }) | null; loadout?: { jutsuIds: string[] } | null; - userQuests: UserQuest[]; + userQuests?: UserQuest[]; votes?: UserVote | null; home?: { id: string; From d9ba9d8b7c8325418880c0e4dc7e563412eac689 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 18:14:39 -0500 Subject: [PATCH 07/27] change userQuests requirement Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index c698f173..3ed96996 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1316,7 +1316,6 @@ export const fetchUpdatedUser = async (props: { with: { bloodline: true, clan: true, - userQuests: true, village: { with: { structures: true, @@ -1667,7 +1666,7 @@ export type UserWithRelations = }) | null; loadout?: { jutsuIds: string[] } | null; - userQuests?: UserQuest[]; + userQuests: UserQuest[]; votes?: UserVote | null; home?: { id: string; From da0a960dc4bdea7be37f96c3ba16dedcd348064c Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 18:33:30 -0500 Subject: [PATCH 08/27] revert profile.ts Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index 3ed96996..ce289d7f 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1323,15 +1323,6 @@ export const fetchUpdatedUser = async (props: { relationshipB: true, }, }, - home: user.home - ? { - id: user.home.id, - name: user.home.homeType?.name ?? "Unknown", - regenBonus: user.home.homeType?.regenBonus ?? 0, - storageSlots: user.home.homeType?.storageSlots ?? 0, - cost: user.home.homeType?.cost ?? 0, - } - : null, anbuSquad: { columns: { name: true }, }, @@ -1668,13 +1659,6 @@ export type UserWithRelations = loadout?: { jutsuIds: string[] } | null; userQuests: UserQuest[]; votes?: UserVote | null; - home?: { - id: string; - name: string; - regenBonus: number; - storageSlots: number; - cost: number; - } | null; }) | undefined; From b2989e7bfa729bbdfc4ad90ddabdb4babc92a5e0 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 18:45:34 -0500 Subject: [PATCH 09/27] Add home to validators/user.ts Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/validators/user.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/validators/user.ts b/app/src/validators/user.ts index 67a3584e..70fdd4a3 100644 --- a/app/src/validators/user.ts +++ b/app/src/validators/user.ts @@ -16,6 +16,13 @@ export const updateUserSchema = z.object({ rank: z.enum(UserRanks), jutsus: z.array(z.string()).optional(), items: z.array(z.string()).optional(), + home: z.object({ + id: z.string(), + name: z.string(), + regenBonus: z.number(), + storageSlots: z.number(), + cost: z.number(), + }).optional(), }); export type UpdateUserSchema = z.infer; From e5701aa231afb1233dd2aa186c590b1cc1ea05a3 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 18:52:24 -0500 Subject: [PATCH 10/27] Add home to profile.ts Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index ce289d7f..3906eb0b 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1659,6 +1659,13 @@ export type UserWithRelations = loadout?: { jutsuIds: string[] } | null; userQuests: UserQuest[]; votes?: UserVote | null; + home?: { + id: string; + name: string; + regenBonus: number; + storageSlots: number; + cost: number; + }; }) | undefined; From 709c99efba99d7e0a91af80392275223abb6a13f Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 19:01:45 -0500 Subject: [PATCH 11/27] made adjustment for if success is false Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/home.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/server/api/routers/home.ts b/app/src/server/api/routers/home.ts index 0f3b86b5..5033e574 100644 --- a/app/src/server/api/routers/home.ts +++ b/app/src/server/api/routers/home.ts @@ -39,7 +39,14 @@ export const homeRouter = createTRPCRouter({ client: ctx.drizzle, userId: ctx.userId, }); - if (!user) return errorResponse("User not found"); + if (!user) { + return { + success: false, + message: "User not found", + availableHomes: [], + storage: [], + }; + } const userHomeData = await ctx.drizzle.query.userHome.findFirst({ where: eq(userHome.userId, ctx.userId), From 63bf556489ec5a02f61805d220b50212b94d4fc0 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 19:09:17 -0500 Subject: [PATCH 12/27] change user.ryo to user.money Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/home.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/server/api/routers/home.ts b/app/src/server/api/routers/home.ts index 5033e574..7b4f57c9 100644 --- a/app/src/server/api/routers/home.ts +++ b/app/src/server/api/routers/home.ts @@ -95,7 +95,7 @@ export const homeRouter = createTRPCRouter({ }); if (!selectedHome) return errorResponse("Invalid home type"); - if (user.ryo < selectedHome.cost) { + if (user.money < selectedHome.cost) { return errorResponse("Not enough ryo"); } @@ -114,7 +114,7 @@ export const homeRouter = createTRPCRouter({ await ctx.drizzle.transaction(async (tx) => { await tx.update(userData) - .set({ ryo: user.ryo - selectedHome.cost }) + .set({ ryo: user.money - selectedHome.cost }) .where(eq(userData.userId, ctx.userId)); if (currentHome) { From 3a2f313b6eadf90efc0639a51cb7a9b9fd6a7b24 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 19:13:34 -0500 Subject: [PATCH 13/27] Changes references from ryo to money Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/home.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/server/api/routers/home.ts b/app/src/server/api/routers/home.ts index 7b4f57c9..093deea2 100644 --- a/app/src/server/api/routers/home.ts +++ b/app/src/server/api/routers/home.ts @@ -96,7 +96,7 @@ export const homeRouter = createTRPCRouter({ if (!selectedHome) return errorResponse("Invalid home type"); if (user.money < selectedHome.cost) { - return errorResponse("Not enough ryo"); + return errorResponse("Not enough money"); } const currentHome = await ctx.drizzle.query.userHome.findFirst({ @@ -114,7 +114,7 @@ export const homeRouter = createTRPCRouter({ await ctx.drizzle.transaction(async (tx) => { await tx.update(userData) - .set({ ryo: user.money - selectedHome.cost }) + .set({ money: user.money - selectedHome.cost }) .where(eq(userData.userId, ctx.userId)); if (currentHome) { From 3a0024452d97d62390b0b144eb03f96bc4db6c19 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 19:18:02 -0500 Subject: [PATCH 14/27] Fix apostrophe causing error Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/app/home/page.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/app/home/page.tsx b/app/src/app/home/page.tsx index 4a654616..20db81e9 100644 --- a/app/src/app/home/page.tsx +++ b/app/src/app/home/page.tsx @@ -144,7 +144,8 @@ export default function Home() {

Storage Slots: {data.home.storageSlots}

) : ( -

You don't own a home yet

+

You don't own a home yet

+ )}
From bc956e0df43b5f8ff1b68dbafc143964de75837a Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 19:53:34 -0500 Subject: [PATCH 15/27] Create tables for Home Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- .../migrations/0195_add_home_types.sql | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/app/drizzle/migrations/0195_add_home_types.sql b/app/drizzle/migrations/0195_add_home_types.sql index 765fb9a0..7da2e2c0 100644 --- a/app/drizzle/migrations/0195_add_home_types.sql +++ b/app/drizzle/migrations/0195_add_home_types.sql @@ -1,3 +1,39 @@ +CREATE TABLE `HomeType` ( + `id` varchar(191) PRIMARY KEY NOT NULL, + `name` varchar(191) NOT NULL, + `regenBonus` int NOT NULL, + `storageSlots` int NOT NULL, + `cost` int NOT NULL, + `createdAt` datetime(3) NOT NULL DEFAULT (CURRENT_TIMESTAMP(3)), + `updatedAt` datetime(3) NOT NULL DEFAULT (CURRENT_TIMESTAMP(3)) +); + +CREATE TABLE `UserHome` ( + `id` varchar(191) PRIMARY KEY NOT NULL, + `userId` varchar(191) NOT NULL, + `homeTypeId` varchar(191) NOT NULL, + `createdAt` datetime(3) NOT NULL DEFAULT (CURRENT_TIMESTAMP(3)), + `updatedAt` datetime(3) NOT NULL DEFAULT (CURRENT_TIMESTAMP(3)), + INDEX `UserHome_userId_idx` (`userId`), + INDEX `UserHome_homeTypeId_idx` (`homeTypeId`) + -- Optionally, add foreign key constraints if desired: + -- FOREIGN KEY (`userId`) REFERENCES `UserData`(`userId`), + -- FOREIGN KEY (`homeTypeId`) REFERENCES `HomeType`(`id`) +); + +CREATE TABLE `UserHomeStorage` ( + `id` varchar(191) PRIMARY KEY NOT NULL, + `userHomeId` varchar(191) NOT NULL, + `itemId` varchar(191) NOT NULL, + `slot` int NOT NULL, + `createdAt` datetime(3) NOT NULL DEFAULT (CURRENT_TIMESTAMP(3)), + `updatedAt` datetime(3) NOT NULL DEFAULT (CURRENT_TIMESTAMP(3)), + INDEX `UserHomeStorage_userHomeId_idx` (`userHomeId`), + INDEX `UserHomeStorage_slot_idx` (`slot`) + -- Optionally, add a foreign key: + -- FOREIGN KEY (`userHomeId`) REFERENCES `UserHome`(`id`) +); + INSERT INTO `HomeType` (`id`, `name`, `regenBonus`, `storageSlots`, `cost`) VALUES ('one-bed-apartment', 'One Bed Room Apartment', 20, 5, 3000000), From 574f96a4a9d3a723a087285143911bc4d5419641 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 21:08:16 -0500 Subject: [PATCH 16/27] Add regenBonus from home Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/libs/profile.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/src/libs/profile.ts b/app/src/libs/profile.ts index 6d12eadf..67153c90 100644 --- a/app/src/libs/profile.ts +++ b/app/src/libs/profile.ts @@ -174,12 +174,19 @@ export const deduceActiveUserRegen = ( clan?: Clan | null; bloodline?: Bloodline | null; village?: (Village & { structures?: VillageStructure[] }) | null; + home?: { + id: string; + name: string; + regenBonus: number; + storageSlots: number; + cost: number; + }; }, settings: GameSetting[], ) => { let regeneration = user.regeneration; - // // Bloodline + // Bloodline if (user.bloodline?.regenIncrease) { regeneration = regeneration + user.bloodline.regenIncrease; } @@ -206,6 +213,11 @@ export const deduceActiveUserRegen = ( regeneration *= 0.5; } + // Home bonus boost + if (user.status === "ASLEEP" && user.home?.regenBonus) { + regeneration = regeneration + user.home.regenBonus; + } + // Increase by event const setting = getGameSettingBoost("regenGainMultiplier", settings); const gameFactor = setting?.value || 1; From 61448ba2e216274c9f038b93cc94ac149b2d2cfb Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 21:23:52 -0500 Subject: [PATCH 17/27] add hometype to fetchupdateduser Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index 3906eb0b..3c62667d 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1343,7 +1343,9 @@ export const fetchUpdatedUser = async (props: { orderBy: sql`FIELD(${questHistory.questType}, 'daily', 'tier') ASC`, }, votes: true, - }, + home: { + with: { homeType: true }, + }, }), ]); From b86e24324d75b1a82924ee7d5b6c4412dd3da4aa Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 21:29:40 -0500 Subject: [PATCH 18/27] Fix bracket Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index 3c62667d..9ee1bcab 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1346,7 +1346,7 @@ export const fetchUpdatedUser = async (props: { home: { with: { homeType: true }, }, - }), + }, ]); // Add votes entry if it doesn't exist From 832d9c2db7eb9ad17f05fc39e60273c7ffe1e0ab Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 21:35:02 -0500 Subject: [PATCH 19/27] Fix another bracket Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index 9ee1bcab..5ccc36ba 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1347,7 +1347,7 @@ export const fetchUpdatedUser = async (props: { with: { homeType: true }, }, }, - ]); + }); // Add votes entry if it doesn't exist if (user && !user.votes) { From d52b52172f33923094c3f550fe70691fbc488ef2 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 21:40:50 -0500 Subject: [PATCH 20/27] Fix bracket - Third times the charm? Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index 5ccc36ba..7ab2017f 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1347,7 +1347,8 @@ export const fetchUpdatedUser = async (props: { with: { homeType: true }, }, }, - }); + }), + ]); // Add votes entry if it doesn't exist if (user && !user.votes) { From 78039a030004c4d5f5c1249c938d2571756eb588 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 21:55:18 -0500 Subject: [PATCH 21/27] Add home to fetch Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index 7ab2017f..5ddbf5ac 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1361,6 +1361,16 @@ export const fetchUpdatedUser = async (props: { }); } + if (user.home) { + user.home = { + id: user.home.id, + name: user.home.homeType?.name ?? "Unknown", // Ensure `name` exists + regenBonus: user.home.homeType?.regenBonus ?? 0, // Default to 0 + storageSlots: user.home.homeType?.storageSlots ?? 0, // Default to 0 + cost: user.home.homeType?.cost ?? 0, // Default to 0 + }; + } + // Add in achievements if (user) { user.userQuests.push(...mockAchievementHistoryEntries(achievements, user)); From 20230359d0c9f525d44064c6970a3e030fa627b0 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 22:00:53 -0500 Subject: [PATCH 22/27] fix home structure Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index 5ddbf5ac..b69b97f6 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1344,7 +1344,17 @@ export const fetchUpdatedUser = async (props: { }, votes: true, home: { - with: { homeType: true }, + select: { + id: true, + homeType: { + select: { + name: true, + regenBonus: true, + storageSlots: true, + cost: true, + }, + }, + }, }, }, }), From b6ee965abda53bb683cd5b2f2e305d5ea2787a70 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 22:07:44 -0500 Subject: [PATCH 23/27] add userQuests Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index b69b97f6..781ee878 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1314,6 +1314,11 @@ export const fetchUpdatedUser = async (props: { client.query.userData.findFirst({ where: eq(userData.userId, userId), with: { + userQuests: { + with: { + quest: true + } + }, bloodline: true, clan: true, village: { From 0ccfa04ae13d281fd8eeac75e0405b1826cce32c Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 22:18:11 -0500 Subject: [PATCH 24/27] add userquest handling Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/anbu.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/server/api/routers/anbu.ts b/app/src/server/api/routers/anbu.ts index 1dd206b3..799547a5 100644 --- a/app/src/server/api/routers/anbu.ts +++ b/app/src/server/api/routers/anbu.ts @@ -45,6 +45,7 @@ export const anbuRouter = createTRPCRouter({ ]); // Derived const { user } = updatedUser; + if (!user.userQuests) user.userQuests = []; const { isKage, isElder, inSquad } = getConvenienceStatus(user, squad); // Hide orders if not kage or elder if (squad && !isKage && !isElder && !inSquad) { From 6558c81792c811a3562b0c7c1aa269521432b104 Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 22:22:57 -0500 Subject: [PATCH 25/27] return if user not found Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/anbu.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/server/api/routers/anbu.ts b/app/src/server/api/routers/anbu.ts index 799547a5..39591dbe 100644 --- a/app/src/server/api/routers/anbu.ts +++ b/app/src/server/api/routers/anbu.ts @@ -45,6 +45,7 @@ export const anbuRouter = createTRPCRouter({ ]); // Derived const { user } = updatedUser; + if (!user) return errorResponse("User not found"); if (!user.userQuests) user.userQuests = []; const { isKage, isElder, inSquad } = getConvenienceStatus(user, squad); // Hide orders if not kage or elder From 4c3a5ecac9943264c2c8e685994bb43b9d31fcde Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 22:35:57 -0500 Subject: [PATCH 26/27] revert profile.ts to working state Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/profile.ts | 28 --------------------------- 1 file changed, 28 deletions(-) diff --git a/app/src/server/api/routers/profile.ts b/app/src/server/api/routers/profile.ts index 781ee878..3906eb0b 100644 --- a/app/src/server/api/routers/profile.ts +++ b/app/src/server/api/routers/profile.ts @@ -1314,11 +1314,6 @@ export const fetchUpdatedUser = async (props: { client.query.userData.findFirst({ where: eq(userData.userId, userId), with: { - userQuests: { - with: { - quest: true - } - }, bloodline: true, clan: true, village: { @@ -1348,19 +1343,6 @@ export const fetchUpdatedUser = async (props: { orderBy: sql`FIELD(${questHistory.questType}, 'daily', 'tier') ASC`, }, votes: true, - home: { - select: { - id: true, - homeType: { - select: { - name: true, - regenBonus: true, - storageSlots: true, - cost: true, - }, - }, - }, - }, }, }), ]); @@ -1376,16 +1358,6 @@ export const fetchUpdatedUser = async (props: { }); } - if (user.home) { - user.home = { - id: user.home.id, - name: user.home.homeType?.name ?? "Unknown", // Ensure `name` exists - regenBonus: user.home.homeType?.regenBonus ?? 0, // Default to 0 - storageSlots: user.home.homeType?.storageSlots ?? 0, // Default to 0 - cost: user.home.homeType?.cost ?? 0, // Default to 0 - }; - } - // Add in achievements if (user) { user.userQuests.push(...mockAchievementHistoryEntries(achievements, user)); From e05241f049792827da3aec47e69250d29f605a5a Mon Sep 17 00:00:00 2001 From: Phrosfire <65364337+Phrosfire@users.noreply.github.com> Date: Mon, 24 Feb 2025 22:36:57 -0500 Subject: [PATCH 27/27] Revert anbu.ts to default Signed-off-by: Phrosfire <65364337+Phrosfire@users.noreply.github.com> --- app/src/server/api/routers/anbu.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/server/api/routers/anbu.ts b/app/src/server/api/routers/anbu.ts index 39591dbe..1dd206b3 100644 --- a/app/src/server/api/routers/anbu.ts +++ b/app/src/server/api/routers/anbu.ts @@ -45,8 +45,6 @@ export const anbuRouter = createTRPCRouter({ ]); // Derived const { user } = updatedUser; - if (!user) return errorResponse("User not found"); - if (!user.userQuests) user.userQuests = []; const { isKage, isElder, inSquad } = getConvenienceStatus(user, squad); // Hide orders if not kage or elder if (squad && !isKage && !isElder && !inSquad) {