feat: start of monorepo

This commit is contained in:
TrèsAbhi committed 2024-09-06 21:45:58 -05:00
1 parent 14f39d71ac
commit 73c7bdf0c0
260 files changed
+1236 -1235

No files matched your search

@@ -0,0 +1 @@
export const CURRENT_POLICIES_AGREEMENT_INDEX = 0;
+41
View File
@@ -0,0 +1,41 @@
'use client';
import { createNextSafeStore } from '@blitzkit/core';
import { merge } from 'lodash';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface WargamingLogin {
id: number;
token: string;
expires: number;
}
interface PatreonLogin {
token: string;
refreshToken: string;
expires: number;
}
export interface App {
developerMode: boolean;
logins: {
wargaming?: WargamingLogin;
patreon?: PatreonLogin;
};
policiesAgreementIndex: number;
}
export const { Provider, use, useMutation, useStore, useDeferred } =
createNextSafeStore(() =>
create<App>()(
persist(
(set) => ({
developerMode: false,
policiesAgreementIndex: -1,
logins: {},
}),
{ name: 'app', merge: (a, b) => merge(b, a) },
),
),
);
@@ -0,0 +1,26 @@
'use client';
import { createNextSafeStore } from '@blitzkit/core/src/zustand/createNextSafeStore';
import { create } from 'zustand';
import { DuelMember } from './duel';
export interface CompareMember extends DuelMember {
key: string;
}
export interface CompareEphemeral {
crewSkills: Record<string, number>;
members: CompareMember[];
sorting?: {
direction: 'ascending' | 'descending';
by: string;
};
}
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
() =>
create<CompareEphemeral>()(() => ({
crewSkills: {},
members: [],
})),
);
@@ -0,0 +1,26 @@
'use client';
import { merge } from 'lodash';
import { create } from 'zustand';
import { persist, subscribeWithSelector } from 'zustand/middleware';
import { createNextSafeStore } from '../core/zustand/createNextSafeStore';
export type DeltaMode = 'none' | 'percentage' | 'absolute';
export interface ComparePersistent {
deltaMode: DeltaMode;
}
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
() =>
create<ComparePersistent>()(
persist(
subscribeWithSelector<ComparePersistent>(() => ({
deltaMode: 'none',
})),
{
name: 'compare',
merge: (a, b) => merge(b, a),
},
),
),
);
@@ -0,0 +1,7 @@
import { EquipmentMatrix } from '.';
export const genericDefaultEquipmentMatrix: EquipmentMatrix = [
[-1, 1, -1],
[0, 0, 0],
[0, 0, 0],
];
+68
View File
@@ -0,0 +1,68 @@
'use client';
import { createNextSafeStore } from '@blitzkit/core/src/zustand/createNextSafeStore';
import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
import { ProvisionDefinitions } from '../../../../../src/core/blitzkit/provisionDefinitions';
import {
EngineDefinition,
GunDefinition,
ShellDefinition,
TankDefinition,
TrackDefinition,
TurretDefinition,
} from '../../../../../src/core/blitzkit/tankDefinitions';
import { tankToDuelMember } from '../../../../../src/core/blitzkit/tankToDuelMember';
type EquipmentMatrixItem = -1 | 0 | 1;
type EquipmentMatrixRow = [
EquipmentMatrixItem,
EquipmentMatrixItem,
EquipmentMatrixItem,
];
export type EquipmentMatrix = [
EquipmentMatrixRow,
EquipmentMatrixRow,
EquipmentMatrixRow,
];
export interface DuelMember {
tank: TankDefinition;
engine: EngineDefinition;
turret: TurretDefinition;
gun: GunDefinition;
shell: ShellDefinition;
track: TrackDefinition;
equipmentMatrix: EquipmentMatrix;
pitch: number;
yaw: number;
consumables: number[];
crewMastery: number;
provisions: number[];
camouflage: boolean;
cooldownBooster: number;
}
export interface Duel {
protagonist: DuelMember;
antagonist: DuelMember;
}
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
({
tank,
provisionDefinitions,
}: {
tank: TankDefinition;
provisionDefinitions: ProvisionDefinitions;
}) => {
const protagonist = tankToDuelMember(tank, provisionDefinitions);
return create<Duel>()(
subscribeWithSelector<Duel>(() => ({
protagonist,
antagonist: protagonist,
})),
);
},
);
@@ -0,0 +1,27 @@
import { EmbedConfigItem } from '.';
export enum EmbedItemType {
Radius,
Size,
SizeWithout0,
Color,
String,
RichText,
Boolean,
Slider,
Enum,
}
export const radixGrays = [
'gray',
'mauve',
'slate',
'sage',
'olive',
'sand',
] as const;
export const radixTextWeights = ['light', 'regular', 'medium', 'bold'] as const;
export type EmbedConfigItemType<Type extends EmbedItemType> =
EmbedConfigItem & { type: Type };
@@ -0,0 +1,100 @@
'use client';
import * as radixColors from '@radix-ui/colors';
import { create } from 'zustand';
import { createNextSafeStore } from '../../core/zustand/createNextSafeStore';
import {
EmbedConfigItemType,
EmbedItemType,
radixGrays,
radixTextWeights,
} from './constants';
export type RadixSize = `${0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}`;
export type RadixSizeWithout0 = Exclude<RadixSize, '0'>;
export type RadixRadius = `${1 | 2 | 3 | 4}` | 'full';
export type RadixTextWeight = (typeof radixTextWeights)[number];
export type RadixColorCompound = {
base: RadixColor;
variant: RadixColorVariant;
};
export type RadixTextColor =
| Exclude<RadixColor, RadixColorGrays>
| 'gray'
| undefined;
export type RadixColorVariantRaw =
`${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12}`;
export type RadixColorVariant = `${'' | 'a'}${RadixColorVariantRaw}`;
export type RadixColor = Exclude<
keyof typeof radixColors,
`${string}${'A' | 'P3' | 'Dark'}`
>;
export type RadixColorGrays = (typeof radixGrays)[number];
export type ExtractEmbedConfigTypes<Config extends EmbedConfig> = {
[Key in keyof Config]: ({
type: Config[Key]['type'];
} & EmbedConfigItem)['default'];
};
export type EmbedConfig = {
width: EmbedConfigItemType<EmbedItemType.Slider>;
height: EmbedConfigItemType<EmbedItemType.Slider>;
} & Record<string, EmbedConfigItem>;
export type EmbedConfigItem = (
| {
type: EmbedItemType.Slider;
default: number;
min: number;
max: number;
}
| {
type: EmbedItemType.Boolean;
default: boolean;
}
| {
type: EmbedItemType.String;
default: string;
}
| {
type: EmbedItemType.Radius;
default: RadixRadius;
}
| {
type: EmbedItemType.Size;
default: RadixSize;
}
| {
type: EmbedItemType.SizeWithout0;
default: RadixSizeWithout0;
}
| {
type: EmbedItemType.Color;
default: string;
}
| {
type: EmbedItemType.RichText;
default: {
color: string;
size: RadixSizeWithout0;
weight: RadixTextWeight;
};
}
| {
type: EmbedItemType.Enum;
default: string;
options: {
label: string;
value: string;
}[];
}
) & {
pad?: boolean;
};
export type EmbedState = Record<string, EmbedConfigItem['default']>;
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
(init: EmbedState) => create<EmbedState>()(() => init),
);
@@ -0,0 +1,31 @@
import { TextProps } from '@radix-ui/themes';
import { EmbedConfig } from '.';
import * as EmbedState from './';
import { EmbedConfigItemType, EmbedItemType } from './constants';
export function useEmbedStateCurry<Config extends EmbedConfig>() {
function useState<Key extends keyof Config>(key: Key) {
return EmbedState.use((state) => {
return (state as EmbedState.ExtractEmbedConfigTypes<Config>)[key];
});
}
function useRichText<
Key extends {
[K in keyof Config]: Config[K] extends { type: EmbedItemType.RichText }
? K
: never;
}[keyof Config],
>(key: Key) {
const { color, ...state } = useState(
key,
) as EmbedConfigItemType<EmbedItemType.RichText>['default'];
return {
style: { color },
...state,
} satisfies TextProps;
}
return { useState, useRichText };
}
+42
View File
@@ -0,0 +1,42 @@
'use client';
import { merge } from 'lodash';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { Region } from '../constants/regions';
import { Stat } from '../core/blitz/generateStats';
import { createNextSafeStore } from '../core/zustand/createNextSafeStore';
import { IndividualTankStats } from '../types/tanksStats';
interface SessionBase {
columns: Stat[];
}
export interface SessionTracking extends SessionBase {
tracking: true;
player: {
id: number;
region: Region;
since: number;
stats: IndividualTankStats[];
};
}
interface SessionNotTracking extends SessionBase {
tracking: false;
}
type Session = SessionTracking | SessionNotTracking;
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
() =>
create<Session>()(
persist(
(set) => ({
columns: ['battles', 'winrate', 'wn8', 'averageDamage'],
tracking: false,
}),
{ name: 'session-2', merge: (a, b) => merge(b, a) },
),
),
);
@@ -0,0 +1,29 @@
'use client';
import { create } from 'zustand';
import { TankClass, TreeType } from '../components/Tanks';
import { Tier } from '../core/blitzkit/tankDefinitions';
import { createNextSafeStore } from '../core/zustand/createNextSafeStore';
export interface TankFilters {
tiers: Tier[];
nations: string[];
classes: TankClass[];
types: TreeType[];
testing: 'include' | 'exclude' | 'only';
search?: string;
searching: boolean;
}
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
() =>
create<TankFilters>()(() => ({
tiers: [],
nations: [],
classes: [],
types: [],
testing: 'include',
search: undefined,
searching: false,
})),
);
@@ -0,0 +1,8 @@
export enum PlayerCountPeriod {
Past120Days = 'd_120',
Past90Days = 'd_90',
Past60Days = 'd_60',
ThisMonth = 'd_30',
ThisWeek = 'd_7',
Yesterday = 'd_1',
}
@@ -0,0 +1,23 @@
'use client';
import { merge } from 'lodash';
import { create } from 'zustand';
import { persist, subscribeWithSelector } from 'zustand/middleware';
import { createNextSafeStore } from '../../core/zustand/createNextSafeStore';
import { PlayerCountPeriod } from './constants';
export interface TankPerformancePersistent {
playerCountPeriod: PlayerCountPeriod;
}
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
() =>
create<TankPerformancePersistent>()(
persist(
subscribeWithSelector<TankPerformancePersistent>(() => ({
playerCountPeriod: PlayerCountPeriod.ThisMonth,
})),
{ name: 'tank-performance', merge: (a, b) => merge(b, a) },
),
),
);
@@ -0,0 +1,21 @@
import { TankPerformanceSortType } from '.';
export const TankPerformanceSortTypeNames = {
winrate: 'Winrate',
players: 'Players',
damage: 'Damage',
survival: 'Survival',
xp: 'XP',
kills: 'Kills',
spots: 'Spots',
accuracy: 'Accuracy',
shots: 'Shots',
hits: 'Hits',
damageRatio: 'Dmg. ratio',
damageTaken: 'Dmg. taken',
capturePoints: 'Cap points',
} as const;
export const TankPerformanceSortTypeNamesArray = Object.keys(
TankPerformanceSortTypeNames,
) as TankPerformanceSortType[];
@@ -0,0 +1,20 @@
'use client';
import { create } from 'zustand';
import { createNextSafeStore } from '../../core/zustand/createNextSafeStore';
import { TankPerformanceSortTypeNames } from './constants';
export type TankPerformanceSortType = keyof typeof TankPerformanceSortTypeNames;
export interface TankPerformanceSort {
type: TankPerformanceSortType;
direction: -1 | 1;
}
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
() =>
create<TankPerformanceSort>()(() => ({
type: 'winrate',
direction: -1,
})),
);
@@ -0,0 +1,105 @@
'use client';
import { Vector3 } from 'three';
import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
import { XP_MULTIPLIERS } from '../app/tools/tankopedia/[id]/components/Model/TechTreeSection';
import { ArmorType } from '../components/Armor/components/SpacedArmorScene';
import { ExternalModuleVariant } from '../components/Armor/components/SpacedArmorSceneComponent';
import { ModelDefinition } from '../core/blitzkit/modelDefinitions';
import { createNextSafeStore } from '../core/zustand/createNextSafeStore';
interface TankopediaEphemeral {
shot?: Shot;
skills: Record<string, number>;
controlsEnabled: boolean;
model: ModelDefinition;
editStatic: boolean;
highlightArmor?: {
editingPlate: boolean;
name: string;
point: Vector3;
thickness: number;
color: string;
} & (
| {
type: ArmorType.Primary | ArmorType.Spaced;
thicknessAngled: number;
angle: number;
}
| { type: ArmorType.External }
);
xpMultiplier: (typeof XP_MULTIPLIERS)[number];
}
export interface ShotLayerBase {
index: number;
thickness: number;
point: Vector3;
surfaceNormal: Vector3;
status: 'blocked' | 'penetration' | 'ricochet';
}
interface ShotLayerExternal extends ShotLayerBase {
type: ArmorType.External;
variant: ExternalModuleVariant;
}
export interface ShotLayerNonExternal extends ShotLayerBase {
type: Exclude<ArmorType, ArmorType.External>;
angle: number;
thicknessAngled: number;
}
export interface ShotLayerGap {
type: null;
status: 'penetration' | 'blocked';
distance: number;
}
export type ShotLayer = ShotLayerExternal | ShotLayerNonExternal | ShotLayerGap;
export type Shot = {
containsGaps: boolean;
damage: number;
splashRadius?: number;
in: {
surfaceNormal: Vector3;
status: ShotStatus;
layers: ShotLayer[];
};
out?: {
surfaceNormal: Vector3;
status: ShotStatus;
layers: ShotLayer[];
};
};
export type ShotStatus = 'penetration' | 'blocked' | 'ricochet' | 'splash';
export type ArmorPiercingLayer =
| {
distance: number;
nominal: number;
angled: number;
ricochet: boolean;
type: 'core' | 'spaced' | 'external';
}
| {
type: 'gap';
gap: number;
};
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
(model: ModelDefinition) =>
create<TankopediaEphemeral>()(
subscribeWithSelector<TankopediaEphemeral>(() => ({
editStatic: false,
skills: {},
model,
controlsEnabled: true,
xpMultiplier: 1,
})),
),
);
@@ -0,0 +1,65 @@
import { TankopediaSortBy } from '.';
export const SORT_UNITS: Record<TankopediaSortBy, string | undefined> = {
'meta.none': undefined,
'survivability.health': 'hp',
'fire.aimTime': 's',
'fire.caliber': 'mm',
'fire.damage': 'hp',
'fire.dispersionMoving': 'm',
'fire.dispersionStill': 'm',
'fire.dpm': undefined,
'fire.dpmPremium': undefined,
'fire.gunDepression': '°',
'fire.gunElevation': '°',
'fire.premiumPenetration': 'mm',
'fire.reload': 's',
'fire.shellVelocity': 'm/s',
'fire.standardPenetration': 'mm',
'maneuverability.backwardsSpeed': 'kph',
'maneuverability.forwardsSpeed': 'kph',
'maneuverability.power': 'hp',
'maneuverability.powerToWeight': 'hp/tn',
'maneuverability.traverseSpeed': '°/s',
'maneuverability.weight': 'tn',
'survivability.camouflageMoving': '%',
'survivability.camouflageShooting': '%',
'survivability.camouflageStill': '%',
'survivability.length': 'm',
'survivability.viewRange': 'm',
'survivability.volume': 'm^3',
};
export const SORT_NAMES = {
'meta.none': 'none',
'survivability.health': 'health',
'survivability.viewRange': 'view range',
'survivability.camouflageStill': 'camouflage still',
'survivability.camouflageMoving': 'camouflage moving',
'survivability.camouflageShooting': 'camouflage shooting',
'survivability.volume': 'volume',
'survivability.length': 'length',
'fire.dpm': 'standard DPM',
'fire.dpmPremium': 'premium DPM',
'fire.reload': 'reload',
'fire.caliber': 'caliber',
'fire.standardPenetration': 'standard penetration',
'fire.premiumPenetration': 'premium penetration',
'fire.damage': 'damage',
'fire.shellVelocity': 'shell velocity',
'fire.aimTime': 'aim time',
'fire.dispersionStill': 'dispersion still',
'fire.dispersionMoving': 'dispersion moving',
'fire.gunDepression': 'gun depression',
'fire.gunElevation': 'gun elevation',
'maneuverability.forwardsSpeed': 'forwards speed',
'maneuverability.backwardsSpeed': 'backwards speed',
'maneuverability.power': 'power',
'maneuverability.powerToWeight': 'power to weight',
'maneuverability.weight': 'weight',
'maneuverability.traverseSpeed': 'traverse speed',
} as const;
export enum TankopediaDisplay {
Model,
DynamicArmor,
StaticArmor,
}
@@ -0,0 +1,79 @@
'use client';
import { merge } from 'lodash';
import { create } from 'zustand';
import { persist, subscribeWithSelector } from 'zustand/middleware';
import { ENVIRONMENTS } from '../../app/tools/tankopedia/[id]/components/Lighting';
import { TankClass, TreeType } from '../../components/Tanks';
import { Tier } from '../../core/blitzkit/tankDefinitions';
import { createNextSafeStore } from '../../core/zustand/createNextSafeStore';
import { SORT_NAMES, TankopediaDisplay } from './constants';
export type TankopediaSortBy = keyof typeof SORT_NAMES;
export type TankopediaSortDirection = 'ascending' | 'descending';
export type TankopediaTestTankDisplay = 'include' | 'exclude' | 'only';
export interface TankopediaPersistent {
model: {
visual: {
wireframe: boolean;
opaque: boolean;
environment: (typeof ENVIRONMENTS)[number];
showGrid: boolean;
greenPenetration: boolean;
showEnvironment: boolean;
showSpacedArmor: boolean;
showExternalModules: boolean;
showPrimaryArmor: boolean;
};
};
sort: {
by: TankopediaSortBy;
direction: TankopediaSortDirection;
};
filters: {
tiers: Tier[];
types: TankClass[];
treeTypes: TreeType[];
nations: string[];
test: TankopediaTestTankDisplay;
page: number;
};
display: TankopediaDisplay;
}
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
() =>
create<TankopediaPersistent>()(
persist(
subscribeWithSelector<TankopediaPersistent>(() => ({
model: {
visual: {
showSpacedArmor: true,
showExternalModules: true,
showPrimaryArmor: true,
wireframe: false,
opaque: false,
environment: ENVIRONMENTS[0],
showGrid: true,
greenPenetration: false,
showEnvironment: false,
},
},
sort: {
by: 'meta.none',
direction: 'descending',
},
filters: {
tiers: [],
types: [],
treeTypes: [],
nations: [],
test: 'include',
page: 0,
},
display: TankopediaDisplay.Model,
})),
{ name: 'tankopedia', merge: (a, b) => merge(b, a) },
),
),
);
@@ -0,0 +1,21 @@
'use client';
import { create } from 'zustand';
import { createNextSafeStore } from '../core/zustand/createNextSafeStore';
import {
TankopediaSortBy,
TankopediaSortDirection,
} from './tankopediaPersistent';
export interface TankopediaSort {
by: TankopediaSortBy;
direction: TankopediaSortDirection;
}
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
() =>
create<TankopediaSort>()(() => ({
by: 'meta.none',
direction: 'descending',
})),
);