Skip to content

Fix Issue# 365: PVP Rank #424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 285 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
285 commits
Select commit Hold shift + click to select a range
97668fc
add undefined handling
Phrosfire Mar 10, 2025
bf8f6e8
prevent undefined logic from being passed
Phrosfire Mar 10, 2025
f61bf70
Merge branch 'main' into Phrosfire-patch-6
Phrosfire Mar 18, 2025
79b0c20
Adjust constants
Phrosfire Mar 18, 2025
520bb51
Update Schema
Phrosfire Mar 18, 2025
72c07ba
Add ranked logic to combat.ts
Phrosfire Mar 18, 2025
a6f27d7
Remove level and set stats at cap
Phrosfire Mar 18, 2025
b63aee3
Change RANKED_PVP to RANKED
Phrosfire Mar 18, 2025
a3276e5
Add ranked to BA
Phrosfire Mar 18, 2025
64d1fcf
No longer use unused components
Phrosfire Mar 18, 2025
7a070ec
Adjust queue const
Phrosfire Mar 18, 2025
6c8433f
Readjust BA page
Phrosfire Mar 18, 2025
8acde07
Adjust BA to account for queue
Phrosfire Mar 18, 2025
daae3f2
Adjust combat router to manage queue
Phrosfire Mar 18, 2025
c28ef58
Fix syntax errors
Phrosfire Mar 18, 2025
c6631c2
Add missing battleId
Phrosfire Mar 18, 2025
01014e1
Add missing battleId in second const
Phrosfire Mar 18, 2025
f9a4289
Prevent undefined opponent
Phrosfire Mar 18, 2025
1c88237
Require defined player
Phrosfire Mar 18, 2025
31e5633
Switch from for loop to for-of loop
Phrosfire Mar 18, 2025
bc9e9ea
Fix queue logic
Phrosfire Mar 18, 2025
54eebd6
Additional queue logic
Phrosfire Mar 18, 2025
0f58195
More ranked queue adjustments
Phrosfire Mar 18, 2025
a95e74b
Update SQL
Phrosfire Mar 18, 2025
7219c42
Add logic to change lp after battle
Phrosfire Mar 19, 2025
230adb9
Fix LP loss
Phrosfire Mar 19, 2025
a4061b6
Add ranked.ts to libs
Phrosfire Mar 19, 2025
d4ff4e7
Make changes to prevent undefined
Phrosfire Mar 19, 2025
19a5117
Adjust database.ts for new rankedLp changes
Phrosfire Mar 19, 2025
776df84
Add queue timer to ranked.ts
Phrosfire Mar 19, 2025
95683f5
Adjust schema to track queue start time
Phrosfire Mar 19, 2025
ef79a0e
Add timer and queue expansion to rankedpvp.ts
Phrosfire Mar 19, 2025
f55e656
Remove moved logic
Phrosfire Mar 19, 2025
093574b
Add queue timer to front end
Phrosfire Mar 19, 2025
5b95373
Fix errors
Phrosfire Mar 19, 2025
d9891a4
Prevent potential undefined timer
Phrosfire Mar 19, 2025
e49862d
Prevent potential undefined timer
Phrosfire Mar 19, 2025
32b7f8e
Fix bad import
Phrosfire Mar 19, 2025
f6b9edd
Add null check
Phrosfire Mar 19, 2025
1a708d3
Return required message
Phrosfire Mar 19, 2025
dc83bdc
Fix potentional undefined
Phrosfire Mar 19, 2025
6708614
Adjust timer for proper time format
Phrosfire Mar 19, 2025
6bf292f
Fix starting lp range and timer setting
Phrosfire Mar 19, 2025
157f689
Reattempt deploy
Phrosfire Mar 19, 2025
b7eceb9
Fix starting range
Phrosfire Mar 19, 2025
3b06e2f
Fix players being put into initiatebattle
Phrosfire Mar 19, 2025
cf664b9
Fix initiatebattle
Phrosfire Mar 19, 2025
1f80c7e
Update rankedpvp.ts
Phrosfire Mar 19, 2025
4016080
Fix profile page
Phrosfire Mar 19, 2025
cd1206c
Fix BA page
Phrosfire Mar 19, 2025
9946b03
fix return
Phrosfire Mar 19, 2025
520e92a
Fix errors
Phrosfire Mar 19, 2025
f626f7d
Fix initiateBattle again
Phrosfire Mar 19, 2025
c36ba37
Use correct import
Phrosfire Mar 19, 2025
863a260
Change rankedpvp logic
Phrosfire Mar 19, 2025
16df01c
Fix in-game error
Phrosfire Mar 19, 2025
cf66f3a
update queue logic
Phrosfire Mar 19, 2025
5b48f36
Remove ranked logic from combat.ts
Phrosfire Mar 19, 2025
8e955f4
Add rankedqueue to rankedpvp.ts
Phrosfire Mar 19, 2025
515efa3
change api calls for ranked
Phrosfire Mar 19, 2025
944b425
Add missing endpoint
Phrosfire Mar 19, 2025
883e08f
Update page.tsx
Phrosfire Mar 19, 2025
8934cec
Adjust rankedpvp.ts
Phrosfire Mar 19, 2025
3fc77a3
prevent potential undefined
Phrosfire Mar 20, 2025
f693746
Update BA page queue logic
Phrosfire Mar 20, 2025
5dbd9b5
Add some logging to queue
Phrosfire Mar 20, 2025
b90f079
Update page.tsx
Phrosfire Mar 20, 2025
9ccb349
Fix warning and error
Phrosfire Mar 20, 2025
2e3d115
Add void
Phrosfire Mar 20, 2025
1b3c006
Update page.tsx
Phrosfire Mar 20, 2025
05cd94b
Adjust logic
Phrosfire Mar 20, 2025
24f84f3
Fix interval
Phrosfire Mar 20, 2025
eca85be
Adjust queue strictness
Phrosfire Mar 20, 2025
fd5800c
Fix queue query method
Phrosfire Mar 20, 2025
2e5977a
Adjust logic
Phrosfire Mar 20, 2025
b6b7a40
Move ranked endpoints back to combat.ts
Phrosfire Mar 20, 2025
cdd7d0d
Move api calls back to combat.ts
Phrosfire Mar 20, 2025
74b12c7
Fix bad api call
Phrosfire Mar 20, 2025
ab2ddb8
Update combat.ts
Phrosfire Mar 20, 2025
e95fc8f
Update combat.ts
Phrosfire Mar 20, 2025
65f1e5d
Comment unused code for test
Phrosfire Mar 21, 2025
e1d1372
Add queue logic
Phrosfire Mar 21, 2025
3db8165
Attempt revert to working
Phrosfire Mar 21, 2025
3508909
Revert BA page
Phrosfire Mar 21, 2025
1e3d471
Set max pools
Phrosfire Mar 21, 2025
006bfc2
Remove pool changes from combat.ts
Phrosfire Mar 21, 2025
92d745f
Add pool adjustment for ranked
Phrosfire Mar 21, 2025
139e952
Have util manage stats for ranked
Phrosfire Mar 21, 2025
63a594c
Don't give BL boost in ranked
Phrosfire Mar 21, 2025
2bc31b1
Don't trigger armor or accessories boost
Phrosfire Mar 21, 2025
7b15d1b
Changed POWER_SCALING for ranked testing
Phrosfire Mar 21, 2025
c076be9
Update rankedpvp.ts to handle multiuser rank
Phrosfire Mar 21, 2025
205f78f
Add ranked option to user list
Phrosfire Mar 21, 2025
fdb6aa8
Add ranked to routers profile
Phrosfire Mar 21, 2025
bbb57f2
Add rank to user validator
Phrosfire Mar 21, 2025
127b681
bring lp into profile
Phrosfire Mar 21, 2025
235a911
Allow items to work
Phrosfire Mar 21, 2025
ef0fd5d
Prevent ranked queue during battle
Phrosfire Mar 21, 2025
24b5809
Set level, experience, and no bloodline in ranked
Phrosfire Mar 21, 2025
8ae152e
Don't allow ranked lp to go negative
Phrosfire Mar 21, 2025
592cebf
Armor and accessories do not trigger for ranked pvp
Phrosfire Mar 21, 2025
7d65c47
Fix pvp queue range
Phrosfire Mar 21, 2025
6bb1b0e
Add statDistribution
Phrosfire Mar 21, 2025
2b9a454
Update SQL
Phrosfire Mar 21, 2025
34540f2
Increase RankedLp range based on time
Phrosfire Mar 21, 2025
f9ce0bf
Add queue timer for ranked
Phrosfire Mar 21, 2025
ac30614
Change RankedLp range increase rate
Phrosfire Mar 21, 2025
1fbe971
Remove duplicate logic. Add safeguards
Phrosfire Mar 22, 2025
6a957d7
Don't bring armor or accessories into combat
Phrosfire Mar 22, 2025
cb84d31
adjust logic for armor and accessories
Phrosfire Mar 22, 2025
3f4cc73
Fix naming
Phrosfire Mar 22, 2025
84795a0
Fix type
Phrosfire Mar 22, 2025
21ca847
Revert to known good
Phrosfire Mar 22, 2025
f2fc82e
Adjust item push
Phrosfire Mar 22, 2025
0ac5899
Revert so weapons enter battle
Phrosfire Mar 22, 2025
e878361
Don't push armor to actions
Phrosfire Mar 22, 2025
499e512
Don't put accessories in ranked actions
Phrosfire Mar 22, 2025
309f97d
(Temporary) Add home fields to schema
Phrosfire Mar 23, 2025
72eb7d4
Merge branch 'main' into Phrosfire-patch-6
Phrosfire Mar 23, 2025
4bc547e
Removed housing
Phrosfire Mar 23, 2025
5ebfaaa
Revert powerscaling to non tourny
Phrosfire Mar 23, 2025
07ba822
Ranked Test - Give Jonin and CA at account creation
Phrosfire Mar 23, 2025
9e472f5
combat.ts - Queue counter
Phrosfire Mar 23, 2025
ea13ba1
BA page.tsx - Add Queue Counter
Phrosfire Mar 23, 2025
f993cc8
Correct count logic
Phrosfire Mar 23, 2025
81211e1
Add ranked battles, wins, and streaks to UserData
Phrosfire Mar 23, 2025
3efa7ea
Display ranked battles, wins, streak, and winrate on profile
Phrosfire Mar 23, 2025
d4e025c
Display ranked battles, wins, streak, and winrate on public profile
Phrosfire Mar 23, 2025
70d86fd
Fix accidental rankedLp default value change
Phrosfire Mar 23, 2025
edf3982
Removed extra createdat
Phrosfire Mar 23, 2025
489af5e
remove duplicate effects
Phrosfire Mar 23, 2025
d1cb196
Revert to default
Phrosfire Mar 23, 2025
6adc694
Revert public user
Phrosfire Mar 23, 2025
1fa086d
Revert page.tsx
Phrosfire Mar 24, 2025
1a61f6f
Revert schema
Phrosfire Mar 24, 2025
d7fc057
Readd missing items
Phrosfire Mar 24, 2025
62b865f
Readd ranked stats
Phrosfire Mar 24, 2025
26e3643
Update battle stats
Phrosfire Mar 24, 2025
bd3f9b1
Add ranked stats to profile
Phrosfire Mar 24, 2025
4bef1d0
Add ranked stats to public user
Phrosfire Mar 24, 2025
85ac4d0
Add ranked stats to get
Phrosfire Mar 24, 2025
60e5163
Remove ranked stats from public
Phrosfire Mar 24, 2025
0128bc5
Fix audio & tutorial
Phrosfire Mar 24, 2025
64433bc
Fix return
Phrosfire Mar 24, 2025
729c9c4
Remove ranked stats from public
Phrosfire Mar 24, 2025
fe4ad61
Show rank instead of LP
Phrosfire Mar 24, 2025
9cb7df2
Fix api call
Phrosfire Mar 24, 2025
e6ce757
Update PublicUser.tsx
Phrosfire Mar 24, 2025
0c627d8
Fix rank load
Phrosfire Mar 24, 2025
42be07a
Readd accidently removed clan battle
Phrosfire Mar 24, 2025
5ceb3d1
Add med exp to ranked
Phrosfire Mar 24, 2025
ff1b8e5
Ranked - No LP loss on draw
Phrosfire Mar 24, 2025
f6bd765
Ranked Streak now effects lp gain
Phrosfire Mar 24, 2025
e7dd55a
Give ranked a standalone page
Phrosfire Mar 24, 2025
5e4b075
Fix ranked page
Phrosfire Mar 24, 2025
f584d09
Set max equipped shields to 2
Phrosfire Mar 24, 2025
dbefb1a
set max shield limit
Phrosfire Mar 24, 2025
86b8dd5
Fix max shields
Phrosfire Mar 24, 2025
a108ff4
Add ranked page to menu
Phrosfire Mar 24, 2025
926d69a
Fix import
Phrosfire Mar 24, 2025
af3bee1
Adjust menu
Phrosfire Mar 24, 2025
97e36ff
Readd missing id
Phrosfire Mar 24, 2025
1af26f9
Revert BA to default
Phrosfire Mar 24, 2025
8ed9fd2
Readd missing tutorial ID
Phrosfire Mar 25, 2025
3ba7f4c
Add additional sql
Phrosfire Mar 25, 2025
49861d5
Fix query
Phrosfire Mar 25, 2025
de7bc08
Add ranked loadout to schema
Phrosfire Mar 25, 2025
c4e4670
Add more sql
Phrosfire Mar 25, 2025
a64b62b
Remove ranked loadout
Phrosfire Mar 25, 2025
a485401
Merge branch 'main' into Phrosfire-patch-6
Phrosfire Mar 25, 2025
3b87add
Remove duplicate
Phrosfire Mar 25, 2025
72cbfea
Readd missing schema items
Phrosfire Mar 25, 2025
263ee9f
Update Schema for ranked loadout
Phrosfire Mar 25, 2025
06f7416
Change lp range time
Phrosfire Mar 25, 2025
dddd5d1
Add ground tag for easier limits
Phrosfire Mar 25, 2025
58e937a
Add limits
Phrosfire Mar 26, 2025
a51e2fa
Update limits in constants
Phrosfire Mar 26, 2025
637c5d8
Readjust ground limit
Phrosfire Mar 26, 2025
ee8e923
Adjust limit logic
Phrosfire Mar 26, 2025
d60b8cc
Add advanced admin section
Phrosfire Mar 26, 2025
cf7c4d7
Fix button
Phrosfire Mar 26, 2025
88cbc43
Add jutsu selection to ranked page
Phrosfire Mar 26, 2025
96aa9ce
Adjust jutsu selector
Phrosfire Mar 26, 2025
506c676
Update page.tsx
Phrosfire Mar 26, 2025
b8f34b1
Adjust ranked jutsu select
Phrosfire Mar 26, 2025
ecfbf80
Use bool for equip check
Phrosfire Mar 26, 2025
1cf09d8
Separate regular loadout from ranked
Phrosfire Mar 26, 2025
2873051
Ranked - Don
Phrosfire Mar 26, 2025
1cae767
Reattempt filter
Phrosfire Mar 26, 2025
a5c68d3
Fix jutsu equip
Phrosfire Mar 26, 2025
4a4d1af
Set highlight to boolean
Phrosfire Mar 26, 2025
9174c6d
Adjust ranked equip logic
Phrosfire Mar 26, 2025
68d9342
More sql
Phrosfire Mar 26, 2025
8ff073b
Add rankedUserJutsu to schema
Phrosfire Mar 26, 2025
b9299f2
Use correct field
Phrosfire Mar 26, 2025
37e26a9
Potential fix for rankedUserJutsu
Phrosfire Mar 26, 2025
d9c6096
Comment ranked loadout from schema
Phrosfire Mar 26, 2025
346397f
Comment rankedJutsuLoadout from UserData
Phrosfire Mar 26, 2025
ee29512
Comment out remaining ranked loadout
Phrosfire Mar 26, 2025
47fe455
Revert Schema
Phrosfire Mar 26, 2025
2f7128b
Finish Schema Revert
Phrosfire Mar 26, 2025
3a9a65f
Change UserJutsu to userJutsu
Phrosfire Mar 26, 2025
8aa548e
Add rankedUserJutsu to schema
Phrosfire Mar 26, 2025
2077da3
Ranked gives 0 jutsu exp
Phrosfire Mar 26, 2025
926e15e
Add ranked jutsu equip logic
Phrosfire Mar 26, 2025
e679c95
Fix ranked jutsu insert
Phrosfire Mar 26, 2025
9400b6b
Fix ranked equip query
Phrosfire Mar 26, 2025
94451b3
Highlight equipped ranked jutsu
Phrosfire Mar 26, 2025
79c81f3
Use ranked user jutsu in list
Phrosfire Mar 26, 2025
4b46df3
Get ranked jutsu
Phrosfire Mar 26, 2025
56b6081
Add getRankedUserJutsus
Phrosfire Mar 26, 2025
9f0716c
Add missing argument
Phrosfire Mar 26, 2025
fd4c0c6
Add fetchRankedUserJutsus
Phrosfire Mar 26, 2025
9d610ca
Add Equipped Sort/Max Equip Limit/Equipped Tracker
Phrosfire Mar 27, 2025
c5695bb
Move equipped to front
Phrosfire Mar 27, 2025
09dcfec
Add equip limits for ranked
Phrosfire Mar 27, 2025
5c5adcf
Add limits on ranked loadout
Phrosfire Mar 27, 2025
670a7ef
Fix value
Phrosfire Mar 27, 2025
5552be5
change false to 0
Phrosfire Mar 27, 2025
73e76fd
More bool fixes
Phrosfire Mar 27, 2025
2699962
Hide QUEUED status
Phrosfire Mar 27, 2025
bc5d9d2
Split Ranked and Unranked for mass unequip
Phrosfire Mar 27, 2025
7087608
Add mass unequip ranked
Phrosfire Mar 27, 2025
0e07a20
Fix indent
Phrosfire Mar 27, 2025
c53f5f1
Adjust jutsu.ts for ranked equipped/unequipped logic
Phrosfire Mar 27, 2025
7ba2d8d
Adjust jutsu counting logic
Phrosfire Mar 27, 2025
0b78936
Properly sort equipped
Phrosfire Mar 27, 2025
c6d1aaa
Fix mapping
Phrosfire Mar 27, 2025
7177e3c
Change grouping logic
Phrosfire Mar 27, 2025
64a2d71
Fix highlight
Phrosfire Mar 27, 2025
c618c6b
Change sorting setup
Phrosfire Mar 27, 2025
847f6dd
Add use effect
Phrosfire Mar 27, 2025
8530ed9
Add void
Phrosfire Mar 27, 2025
db85130
Use ranked loadout in ranked battles
Phrosfire Mar 27, 2025
0057485
Pull rankedUserJutsu
Phrosfire Mar 27, 2025
78b0338
import rankedUserJutsu
Phrosfire Mar 27, 2025
8b5e02e
Adjust jutsu pull
Phrosfire Mar 27, 2025
cc850f2
Revert combat router
Phrosfire Mar 27, 2025
137fe30
Update query list
Phrosfire Mar 28, 2025
51fb41a
Fix schema
Phrosfire Mar 28, 2025
3f7f61a
if else for ranked battle
Phrosfire Mar 28, 2025
08fc20d
Fix formatting
Phrosfire Mar 28, 2025
01d59ce
Adjust queue logic
Phrosfire Mar 28, 2025
0e607b0
Use optional chaining
Phrosfire Mar 28, 2025
fd64d36
Better logging
Phrosfire Mar 28, 2025
7655516
Add more logs
Phrosfire Mar 28, 2025
431d450
Remove attempt to use ranked jutsu
Phrosfire Mar 28, 2025
15089dc
Always bring in ranked jutsu
Phrosfire Mar 28, 2025
5d158d8
Another attempt to pull in ranked jutsu
Phrosfire Mar 28, 2025
56d3c43
Comment ranked jutsu
Phrosfire Mar 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions app/drizzle/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,19 @@ export const UserRanks = [
] as const;
export type UserRank = (typeof UserRanks)[number];

export const RankedDivisions = [
{ key: "UNRANKED", name: "Unranked", rankedLp: 0 },
{ key: "WOOD", name: "Wood", rankedLp: 150 },
{ key: "ADEPT", name: "Adept", rankedLp: 300 },
{ key: "MASTER", name: "Master", rankedLp: 600 },
{ key: "LEGEND", name: "Legend", rankedLp: 900 },
{ key: "SANNIN", name: "Sannin", rankedLp: Infinity },
] as const;

// Type Definitions
export type RankedDivision = (typeof RankedDivisions)[number]["name"];
export type RankedDivisionEntry = (typeof RankedDivisions)[number];

export const ItemTypes = [
"WEAPON",
"CONSUMABLE",
Expand Down Expand Up @@ -260,6 +273,7 @@ export const BattleTypes = [
"QUEST",
"VILLAGE_PROTECTOR",
"TRAINING",
"RANKED",
] as const;
export type BattleType = (typeof BattleTypes)[number];

Expand All @@ -268,6 +282,7 @@ export const PvpBattleTypes: BattleType[] = [
"SPARRING",
"CLAN_BATTLE",
"TOURNAMENT",
"RANKED",
];

export const TournamentTypes = ["CLAN"] as const;
Expand Down Expand Up @@ -311,6 +326,9 @@ export const TrainingSpeeds = ["15min", "1hr", "4hrs", "8hrs"] as const;
export type TrainingSpeed = (typeof TrainingSpeeds)[number];

export const JUTSU_MAX_RESIDUAL_EQUIPPED = 4;
export const JUTSU_MAX_SHIELD_EQUIPPED = 2;
export const JUTSU_MAX_GROUND_EQUIPPED = 1;
export const JUTSU_MAX_MOVEPREVENT_EQUIPPED = 1;

export const UserAssociations = ["MARRIAGE", "DIVORCED"] as const;

Expand Down
64 changes: 64 additions & 0 deletions app/drizzle/migrations/0201_dancing_walrus.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
ALTER TABLE `UserData` ADD `rankedLp` INT DEFAULT 150 NOT NULL;
ALTER TABLE `BattleHistory` MODIFY COLUMN `battleType` ENUM('ARENA', 'COMBAT', 'SPARRING', 'KAGE_AI', 'KAGE_PVP', 'CLAN_CHALLENGE', 'CLAN_BATTLE', 'TOURNAMENT', 'QUEST', 'VILLAGE_PROTECTOR', 'TRAINING', 'RANKED') NOT NULL;
CREATE TABLE RankedPvpQueue (
id varchar(191) NOT NULL,
userId varchar(191) NOT NULL,
rankedLp int NOT NULL,
createdAt datetime(3) NOT NULL DEFAULT (CURRENT_TIMESTAMP(3)),
CONSTRAINT RankedPvpQueue_id PRIMARY KEY(id)
);
CREATE INDEX RankedPvpQueue_userId_idx ON RankedPvpQueue (userId);
CREATE INDEX RankedPvpQueue_rankedLp_idx ON RankedPvpQueue (rankedLp);
ALTER TABLE RankedPvpQueue ADD COLUMN queueStartTime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE Battle MODIFY COLUMN battleType ENUM('ARENA', 'COMBAT', 'SPARRING', 'KAGE_AI', 'KAGE_PVP', 'CLAN_CHALLENGE', 'CLAN_BATTLE', 'TOURNAMENT', 'QUEST', 'VILLAGE_PROTECTOR', 'TRAINING', 'RANKED') NOT NULL;
ALTER TABLE DataBattleAction MODIFY COLUMN battleType ENUM('ARENA', 'COMBAT', 'SPARRING', 'KAGE_AI', 'KAGE_PVP', 'CLAN_CHALLENGE', 'CLAN_BATTLE', 'TOURNAMENT', 'QUEST', 'VILLAGE_PROTECTOR', 'TRAINING', 'RANKED') NOT NULL;
ALTER TABLE UserData ADD COLUMN rankedBattles int NOT NULL DEFAULT 0, ADD COLUMN rankedWins int NOT NULL DEFAULT 0, ADD COLUMN rankedStreak int NOT NULL DEFAULT 0;
-- Create the ranked jutsu loadout table
CREATE TABLE `RankedJutsuLoadout` (
`id` varchar(191) NOT NULL,
`userId` varchar(191) NOT NULL,
`jutsuIds` json NOT NULL,
`createdAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
INDEX `RankedJutsuLoadout_userId_idx` (`userId`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Add the ranked jutsu loadout reference to UserData
ALTER TABLE `UserData`
ADD COLUMN `rankedJutsuLoadout` varchar(191),
ADD INDEX `UserData_rankedJutsuLoadout_idx` (`rankedJutsuLoadout`);
ALTER TABLE `UserJutsu` ADD COLUMN `rankedEquipped` tinyint NOT NULL DEFAULT 0;
CREATE INDEX `Jutsu_rankedEquipped_idx` ON `UserJutsu` (`rankedEquipped`);

CREATE TABLE "rankedUserJutsu" (
"id" text PRIMARY KEY,
"userId" text NOT NULL REFERENCES "userData"("userId"),
"jutsuId" text NOT NULL REFERENCES "jutsu"("id"),
"level" integer NOT NULL DEFAULT 1,
"experience" integer NOT NULL DEFAULT 0,
"equipped" integer NOT NULL DEFAULT 0,
"createdAt" timestamp NOT NULL DEFAULT now(),
"updatedAt" timestamp NOT NULL DEFAULT now()
);

-- Create an index on userId for faster lookups
CREATE INDEX "rankedUserJutsu_userId_idx" ON "rankedUserJutsu"("userId");

ALTER TABLE UserJutsu ADD COLUMN rankedEquipped tinyint NOT NULL DEFAULT 0;
CREATE INDEX Jutsu_rankedEquipped_idx ON UserJutsu (rankedEquipped);

-- Create a unique constraint to prevent duplicate jutsu entries for the same user
CREATE UNIQUE INDEX "rankedUserJutsu_userId_jutsuId_unique" ON "rankedUserJutsu"("userId", "jutsuId");
CREATE TABLE RankedUserJutsu (
id varchar(191) PRIMARY KEY NOT NULL,
userId varchar(191) NOT NULL,
jutsuId varchar(191) NOT NULL,
createdAt datetime(3) NOT NULL DEFAULT (CURRENT_TIMESTAMP(3)),
updatedAt datetime(3) NOT NULL DEFAULT (CURRENT_TIMESTAMP(3)),
level int NOT NULL DEFAULT 1,
equipped tinyint NOT NULL DEFAULT 0,
finishTraining datetime(3),
UNIQUE KEY RankedUserJutsu_userId_jutsuId_key (userId, jutsuId),
INDEX RankedUserJutsu_jutsuId_idx (jutsuId),
INDEX RankedUserJutsu_equipped_idx (equipped)
)
103 changes: 101 additions & 2 deletions app/drizzle/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
double,
primaryKey,
unique,
timestamp,
} from "drizzle-orm/mysql-core";
import * as consts from "@/drizzle/constants";
import { createInsertSchema } from "drizzle-zod";
Expand Down Expand Up @@ -1032,6 +1033,23 @@ export const jutsuLoadout = mysqlTable(
},
);

export const rankedJutsuLoadout = mysqlTable(
"RankedJutsuLoadout",
{
id: varchar("id", { length: 191 }).primaryKey().notNull(),
userId: varchar("userId", { length: 191 }).notNull(),
jutsuIds: json("content").$type<string[]>().notNull(),
createdAt: datetime("createdAt", { mode: "date", fsp: 3 })
.default(sql`(CURRENT_TIMESTAMP(3))`)
.notNull(),
},
(table) => {
return {
userIdIdx: index("RankedJutsuLoadout_userId_idx").on(table.userId),
};
},
);

export const notification = mysqlTable(
"Notification",
{
Expand Down Expand Up @@ -1328,6 +1346,7 @@ export const userData = mysqlTable(
anbuId: varchar("anbuId", { length: 191 }),
clanId: varchar("clanId", { length: 191 }),
jutsuLoadout: varchar("jutsuLoadout", { length: 191 }),
rankedJutsuLoadout: varchar("rankedJutsuLoadout", { length: 191 }),
nRecruited: int("nRecruited").default(0).notNull(),
lastIp: varchar("lastIp", { length: 191 }),
username: varchar("username", { length: 191 }).notNull(),
Expand Down Expand Up @@ -1461,6 +1480,10 @@ export const userData = mysqlTable(
tavernMessages: int("tavernMessages").default(0).notNull(),
audioOn: boolean("audioOn").default(true).notNull(),
tutorialStep: tinyint("tutorialStep", { unsigned: true }).default(0).notNull(),
rankedLp: int("rankedLp").notNull().default(150),
rankedBattles: int("rankedBattles").notNull().default(0),
rankedWins: int("rankedWins").notNull().default(0),
rankedStreak: int("rankedStreak").notNull().default(0),
},
(table) => {
return {
Expand All @@ -1471,6 +1494,7 @@ export const userData = mysqlTable(
clanIdIdx: index("UserData_clanId_idx").on(table.clanId),
anbuIdIdx: index("UserData_anbuId_idx").on(table.anbuId),
jutsuLoadoutIdx: index("UserData_jutsuLoadout_idx").on(table.jutsuLoadout),
rankedJutsuLoadoutIdx: index("UserData_rankedJutsuLoadout_idx").on(table.rankedJutsuLoadout),
levelIdx: index("UserData_level_idx").on(table.level),
usernameKey: uniqueIndex("UserData_username_key").on(table.username),
bloodlineIdIdx: index("UserData_bloodlineId_idx").on(table.bloodlineId),
Expand Down Expand Up @@ -1541,6 +1565,7 @@ export const userDataRelations = relations(userData, ({ one, many }) => ({
conversations: many(user2conversation),
items: many(userItem),
jutsus: many(userJutsu),
rankedUserJutsus: many(rankedUserJutsu),
badges: many(userBadge),
recruitedUsers: many(userData, { relationName: "recruiter" }),
recruiter: one(userData, {
Expand All @@ -1566,6 +1591,10 @@ export const userDataRelations = relations(userData, ({ one, many }) => ({
fields: [userData.jutsuLoadout],
references: [jutsuLoadout.id],
}),
rankedLoadout: one(rankedJutsuLoadout, {
fields: [userData.rankedJutsuLoadout],
references: [rankedJutsuLoadout.id],
}),
creatorBlacklist: many(userBlackList, { relationName: "creatorBlacklist" }),
mpvpBattles: many(mpvpBattleUser),
associations: many(userAssociation),
Expand Down Expand Up @@ -1673,6 +1702,7 @@ export const userJutsu = mysqlTable(
level: int("level").default(1).notNull(),
experience: int("experience").default(0).notNull(),
equipped: tinyint("equipped").default(0).notNull(),
rankedEquipped: tinyint("rankedEquipped").default(0).notNull(),
finishTraining: datetime("finishTraining", { mode: "date", fsp: 3 }),
},
(table) => {
Expand All @@ -1683,11 +1713,41 @@ export const userJutsu = mysqlTable(
),
jutsuIdIdx: index("UserJutsu_jutsuId_idx").on(table.jutsuId),
equippedIdx: index("Jutsu_equipped_idx").on(table.equipped),
rankedEquippedIdx: index("Jutsu_rankedEquipped_idx").on(table.rankedEquipped),
};
},
);
export type UserJutsu = InferSelectModel<typeof userJutsu>;

export const rankedUserJutsu = mysqlTable(
"RankedUserJutsu",
{
id: varchar("id", { length: 191 }).primaryKey().notNull(),
userId: varchar("userId", { length: 191 }).notNull(),
jutsuId: varchar("jutsuId", { 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(),
level: int("level").default(1).notNull(),
equipped: tinyint("equipped").default(0).notNull(),
finishTraining: datetime("finishTraining", { mode: "date", fsp: 3 }),
},
(table) => {
return {
userIdJutsuIdKey: uniqueIndex("RankedUserJutsu_userId_jutsuId_key").on(
table.userId,
table.jutsuId,
),
jutsuIdIdx: index("RankedUserJutsu_jutsuId_idx").on(table.jutsuId),
equippedIdx: index("RankedUserJutsu_equipped_idx").on(table.equipped),
};
},
);
export type RankedUserJutsu = InferSelectModel<typeof rankedUserJutsu>;

export const userJutsuRelations = relations(userJutsu, ({ one }) => ({
jutsu: one(jutsu, {
fields: [userJutsu.jutsuId],
Expand All @@ -1699,6 +1759,17 @@ export const userJutsuRelations = relations(userJutsu, ({ one }) => ({
}),
}));

export const rankedUserJutsuRelations = relations(rankedUserJutsu, ({ one }) => ({
jutsu: one(jutsu, {
fields: [rankedUserJutsu.jutsuId],
references: [jutsu.id],
}),
user: one(userData, {
fields: [rankedUserJutsu.userId],
references: [userData.userId],
}),
}));

export const userReport = mysqlTable(
"UserReport",
{
Expand Down Expand Up @@ -2575,8 +2646,6 @@ export const userPollVote = mysqlTable(
},
);

export type UserPollVote = InferSelectModel<typeof userPollVote>;

export const userPollVoteRelations = relations(userPollVote, ({ one }) => ({
user: one(userData, {
fields: [userPollVote.userId],
Expand All @@ -2592,6 +2661,36 @@ export const userPollVoteRelations = relations(userPollVote, ({ one }) => ({
}),
}));

export type UserPollVote = InferSelectModel<typeof userPollVote>;

export const rankedPvpQueue = mysqlTable(
"RankedPvpQueue",
{
id: varchar("id", { length: 191 }).primaryKey().notNull(),
userId: varchar("userId", { length: 191 })
.notNull()
.references(() => userData.userId),
rankedLp: int("rankedLp").notNull(),
queueStartTime: timestamp("queueStartTime").notNull().defaultNow(),
createdAt: timestamp("createdAt").notNull().defaultNow(),
},
(table) => {
return {
userIdIdx: index("RankedPvpQueue_userId_idx").on(table.userId),
rankedLpIdx: index("RankedPvpQueue_rankedLp_idx").on(table.rankedLp),
};
},
);

export type RankedPvpQueue = InferSelectModel<typeof rankedPvpQueue>;

export const rankedPvpQueueRelations = relations(rankedPvpQueue, ({ one }) => ({
user: one(userData, {
fields: [rankedPvpQueue.userId],
references: [userData.userId],
}),
}));

// User upload schema
export const userUpload = mysqlTable(
"UserUpload",
Expand Down
56 changes: 56 additions & 0 deletions app/src/app/profile/edit/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import { canSwapVillage } from "@/utils/permissions";
import { canSwapBloodline } from "@/utils/permissions";
import { useInfinitePagination } from "@/libs/pagination";
import { capitalizeFirstLetter } from "@/utils/sanitize";
import { canEditPublicUser } from "@/utils/permissions";
import UserSearchSelect from "@/layout/UserSearchSelect";
import UserRequestSystem from "@/layout/UserRequestSystem";
import type { Gender } from "@/validators/register";
Expand Down Expand Up @@ -275,6 +276,16 @@ export default function EditProfile() {
<SwapVillage />
</Accordion>
)}
{canEditPublicUser({ ...userData, role: userData.role }) && (
<Accordion
title="Admin Controls"
selectedTitle={activeElement}
unselectedSubtitle="Advanced admin controls"
onClick={setActiveElement}
>
<AdminControls />
</Accordion>
)}
</div>
</ContentBox>
);
Expand Down Expand Up @@ -1648,3 +1659,48 @@ const ChangeGender: React.FC = () => {
</div>
);
};

const AdminControls: React.FC = () => {
const { mutate: massUnequipAll, isPending: isUnequippingRegular } = api.jutsu.massUnequipAll.useMutation({
onSuccess: (result) => {
showMutationToast(result);
},
});

const { mutate: massUnequipAllRanked, isPending: isUnequippingRanked } = api.jutsu.massUnequipAllRanked.useMutation({
onSuccess: (result) => {
showMutationToast(result);
},
});

const isPending = isUnequippingRegular || isUnequippingRanked;

return (
<div className="flex flex-col gap-4 p-4">
<div className="flex items-center justify-between">
<div>
<h3 className="text-lg font-semibold">Mass Unequip All Jutsu</h3>
<p className="text-sm text-muted-foreground">
This will unequip all jutsu from all users. Use with caution.
</p>
</div>
<div className="flex gap-2">
<Button
variant="destructive"
onClick={() => massUnequipAll()}
disabled={isPending}
>
{isUnequippingRegular ? "Processing..." : "Unequip All Regular"}
</Button>
<Button
variant="destructive"
onClick={() => massUnequipAllRanked()}
disabled={isPending}
>
{isUnequippingRanked ? "Processing..." : "Unequip All Ranked"}
</Button>
</div>
</div>
</div>
);
};
Loading