diff --git a/src/broadcast/broadcast_manager.ts b/src/broadcast/broadcast_manager.ts index d022de979..cb36649c7 100644 --- a/src/broadcast/broadcast_manager.ts +++ b/src/broadcast/broadcast_manager.ts @@ -1,7 +1,8 @@ import { Preconditions } from "@common/preconditions"; import { ConnectionEvent, ConnectionStatus, DolphinConnection, DolphinMessageType } from "@slippi/slippi-js"; import { EventEmitter } from "events"; -import _ from "lodash"; +import keyBy from "lodash/keyBy"; +import last from "lodash/last"; import type { connection, Message } from "websocket"; import { client as WebSocketClient } from "websocket"; @@ -229,7 +230,7 @@ export class BroadcastManager extends EventEmitter { switch (message.type) { case "start-broadcast-resp": { if (message.recoveryGameCursor !== undefined) { - const firstIncoming = _.first(this.incomingEvents); + const firstIncoming = this.incomingEvents[0]; let firstCursor: number | null | undefined; if (firstIncoming) { firstCursor = firstIncoming.cursor; @@ -246,24 +247,24 @@ export class BroadcastManager extends EventEmitter { const isNeededByServer = event.cursor > message.recoveryGameCursor; // Make sure we aren't duplicating anything that is already in the incoming events array - const isNotIncoming = _.isNil(firstCursor) || event.cursor < firstCursor; + const isNotIncoming = firstCursor == null || event.cursor < firstCursor; return isNeededByServer && isNotIncoming; } return false; }); - this.incomingEvents = _.concat(backedEventsToUse, this.incomingEvents); + this.incomingEvents = [...backedEventsToUse, ...this.incomingEvents]; - const newFirstEvent = _.first(this.incomingEvents); + const newFirstEvent = this.incomingEvents[0]; if (!newFirstEvent) { this.emit(BroadcastEvent.LOG, "Missing new first event"); return; } const newFirstCursor = newFirstEvent.cursor; - const firstBackupCursor = (_.first(this.backupEvents) || {}).cursor; - const lastBackupCursor = (_.last(this.backupEvents) || {}).cursor; + const firstBackupCursor = (this.backupEvents[0] || {}).cursor; + const lastBackupCursor = (last(this.backupEvents) || {}).cursor; this.emit( BroadcastEvent.LOG, @@ -281,7 +282,7 @@ export class BroadcastManager extends EventEmitter { // Grab broadcastId we were currently using if the broadcast still exists, would happen // in the case of a reconnect if (this.broadcastId) { - const broadcastsById = _.keyBy(broadcasts, "id"); + const broadcastsById = keyBy(broadcasts, "id"); const prevBroadcast = broadcastsById[this.broadcastId]; if (prevBroadcast) { @@ -397,7 +398,7 @@ export class BroadcastManager extends EventEmitter { return; } - while (!_.isEmpty(this.incomingEvents)) { + while (this.incomingEvents.length > 0) { const event = this.incomingEvents.shift(); if (!event) { this.emit(BroadcastEvent.LOG, "No incoming events"); diff --git a/src/broadcast/spectate_manager.ts b/src/broadcast/spectate_manager.ts index 51a8730e6..314a1a62e 100644 --- a/src/broadcast/spectate_manager.ts +++ b/src/broadcast/spectate_manager.ts @@ -2,7 +2,6 @@ import { Preconditions } from "@common/preconditions"; import { SlpFileWriter, SlpFileWriterEvent } from "@slippi/slippi-js"; import { EventEmitter } from "events"; import * as fs from "fs-extra"; -import _ from "lodash"; import type { connection, Message } from "websocket"; import { client as WebSocketClient } from "websocket"; diff --git a/src/dolphin/instance.ts b/src/dolphin/instance.ts index f12ac72ad..158a75c2a 100644 --- a/src/dolphin/instance.ts +++ b/src/dolphin/instance.ts @@ -5,7 +5,7 @@ import { app } from "electron"; import electronLog from "electron-log"; import { EventEmitter } from "events"; import * as fs from "fs-extra"; -import { debounce } from "lodash"; +import debounce from "lodash/debounce"; import path from "path"; import { fileExists } from "utils/file_exists"; diff --git a/src/dolphin/setup.ts b/src/dolphin/setup.ts index 0da7ce60a..5b517cf43 100644 --- a/src/dolphin/setup.ts +++ b/src/dolphin/setup.ts @@ -1,7 +1,7 @@ import { app, shell } from "electron"; import log from "electron-log"; import * as fs from "fs-extra"; -import { isEqual } from "lodash"; +import isEqual from "lodash/isEqual"; import path from "path"; import { fileExists } from "utils/file_exists"; diff --git a/src/renderer/app/header/header.tsx b/src/renderer/app/header/header.tsx index 9dab7e869..6d8dc91ea 100644 --- a/src/renderer/app/header/header.tsx +++ b/src/renderer/app/header/header.tsx @@ -6,7 +6,7 @@ import Button from "@mui/material/Button"; import IconButton from "@mui/material/IconButton"; import Tooltip from "@mui/material/Tooltip"; import log from "electron-log"; -import { debounce } from "lodash"; +import debounce from "lodash/debounce"; import React, { useCallback, useMemo } from "react"; import { useDolphinActions } from "@/lib/dolphin/use_dolphin_actions"; diff --git a/src/renderer/components/dual_pane.tsx b/src/renderer/components/dual_pane.tsx index 1b413eb0e..576d217d5 100644 --- a/src/renderer/components/dual_pane.tsx +++ b/src/renderer/components/dual_pane.tsx @@ -1,5 +1,5 @@ import styled from "@emotion/styled"; -import { debounce } from "lodash"; +import debounce from "lodash/debounce"; import React from "react"; import { colors } from "@/styles/colors"; diff --git a/src/renderer/pages/replays/replay_browser/file_list.tsx b/src/renderer/pages/replays/replay_browser/file_list.tsx index 3bfa80379..509c874a0 100644 --- a/src/renderer/pages/replays/replay_browser/file_list.tsx +++ b/src/renderer/pages/replays/replay_browser/file_list.tsx @@ -1,7 +1,7 @@ import DeleteIcon from "@mui/icons-material/Delete"; import FolderIcon from "@mui/icons-material/Folder"; import type { FileResult } from "@replays/types"; -import { debounce } from "lodash"; +import debounce from "lodash/debounce"; import React from "react"; import AutoSizer from "react-virtualized-auto-sizer"; import { FixedSizeList as List } from "react-window"; diff --git a/src/renderer/pages/replays/replay_browser/replay_file/replay_file.container.tsx b/src/renderer/pages/replays/replay_browser/replay_file/replay_file.container.tsx index a4da9c2c2..a803576ff 100644 --- a/src/renderer/pages/replays/replay_browser/replay_file/replay_file.container.tsx +++ b/src/renderer/pages/replays/replay_browser/replay_file/replay_file.container.tsx @@ -10,7 +10,7 @@ import TimerIcon from "@mui/icons-material/Timer"; import TrackChangesIcon from "@mui/icons-material/TrackChanges"; import type { FileResult } from "@replays/types"; import { frameToGameTimer, GameMode, stages as stageUtils } from "@slippi/slippi-js"; -import { groupBy } from "lodash"; +import groupBy from "lodash/groupBy"; import moment from "moment"; import React, { useCallback, useMemo } from "react"; diff --git a/src/renderer/pages/replays/replay_file_stats/game_profile.tsx b/src/renderer/pages/replays/replay_file_stats/game_profile.tsx index bde354ccd..a78e1d9ee 100644 --- a/src/renderer/pages/replays/replay_file_stats/game_profile.tsx +++ b/src/renderer/pages/replays/replay_file_stats/game_profile.tsx @@ -2,7 +2,6 @@ import styled from "@emotion/styled"; import Typography from "@mui/material/Typography"; import type { FileResult } from "@replays/types"; import type { StatsType } from "@slippi/slippi-js"; -import _ from "lodash"; import React from "react"; import { ErrorBoundary } from "@/components/error_boundary"; diff --git a/src/renderer/pages/replays/replay_file_stats/game_profile_header.tsx b/src/renderer/pages/replays/replay_file_stats/game_profile_header.tsx index 13a63b93e..8d94af8bc 100644 --- a/src/renderer/pages/replays/replay_file_stats/game_profile_header.tsx +++ b/src/renderer/pages/replays/replay_file_stats/game_profile_header.tsx @@ -17,7 +17,8 @@ import Tooltip from "@mui/material/Tooltip"; import type { FileResult, PlayerInfo as PlayerInfoType } from "@replays/types"; import type { StadiumStatsType, StatsType } from "@slippi/slippi-js"; import { frameToGameTimer, GameMode, stages as stageUtils } from "@slippi/slippi-js"; -import { get, groupBy } from "lodash"; +import get from "lodash/get"; +import groupBy from "lodash/groupBy"; import moment from "moment"; import React from "react"; diff --git a/src/renderer/pages/replays/replay_file_stats/kill_table.tsx b/src/renderer/pages/replays/replay_file_stats/kill_table.tsx index ed9896884..94f77bad9 100644 --- a/src/renderer/pages/replays/replay_file_stats/kill_table.tsx +++ b/src/renderer/pages/replays/replay_file_stats/kill_table.tsx @@ -7,7 +7,10 @@ import Tooltip from "@mui/material/Tooltip"; import type { FileResult, PlayerInfo } from "@replays/types"; import type { StatsType, StockType } from "@slippi/slippi-js"; import { animations as animationUtils, Frames, moves as moveUtils } from "@slippi/slippi-js"; -import _ from "lodash"; +import get from "lodash/get"; +import groupBy from "lodash/groupBy"; +import keyBy from "lodash/keyBy"; +import last from "lodash/last"; import { convertFrameCountToDurationString } from "@/lib/time"; import { getCharacterIcon } from "@/lib/utils"; @@ -97,13 +100,13 @@ export const KillTable = ({ file, stats, player, opp, onPlay }: KillTableProps) const renderKilledBy = (stock: StockType) => { // Here we are going to grab the opponent's punishes and see if one of them was // responsible for ending this stock, if so show the kill move, otherwise assume SD - const punishes = _.get(stats, "conversions") || []; - const punishesByPlayer = _.groupBy(punishes, "playerIndex"); + const punishes = get(stats, "conversions") || []; + const punishesByPlayer = groupBy(punishes, "playerIndex"); const playerPunishes = punishesByPlayer[opp.playerIndex] || []; // Only get punishes that killed - const killingPunishes = _.filter(playerPunishes, "didKill"); - const killingPunishesByEndFrame = _.keyBy(killingPunishes, "endFrame"); + const killingPunishes = playerPunishes.filter((punish) => punish.didKill); + const killingPunishesByEndFrame = keyBy(killingPunishes, "endFrame"); const punishThatEndedStock = stock.endFrame !== null && stock.endFrame !== undefined ? killingPunishesByEndFrame[stock.endFrame] : null; @@ -112,7 +115,7 @@ export const KillTable = ({ file, stats, player, opp, onPlay }: KillTableProps) return Self Destruct; } - const lastMove = _.last(punishThatEndedStock.moves); + const lastMove = last(punishThatEndedStock.moves); if (!lastMove) { return Grab Release; } @@ -160,8 +163,8 @@ export const KillTable = ({ file, stats, player, opp, onPlay }: KillTableProps) }; const renderStocksRows = () => { - const stocks = _.get(stats, "stocks") || []; - const stocksByOpponent = _.groupBy(stocks, "playerIndex"); + const stocks = get(stats, "stocks") || []; + const stocksByOpponent = groupBy(stocks, "playerIndex"); const opponentStocks = stocksByOpponent[opp.playerIndex] || []; return opponentStocks.map(generateStockRow); diff --git a/src/renderer/pages/replays/replay_file_stats/overall_table.tsx b/src/renderer/pages/replays/replay_file_stats/overall_table.tsx index 16dab96da..bb8d98f12 100644 --- a/src/renderer/pages/replays/replay_file_stats/overall_table.tsx +++ b/src/renderer/pages/replays/replay_file_stats/overall_table.tsx @@ -1,6 +1,8 @@ import type { FileResult } from "@replays/types"; import type { RatioType, StatsType } from "@slippi/slippi-js"; -import _ from "lodash"; +import get from "lodash/get"; +import pick from "lodash/pick"; +import toArray from "lodash/toArray"; import { getCharacterIcon } from "@/lib/utils"; @@ -55,8 +57,8 @@ export const OverallTable = ({ file, stats }: OverallTableProps) => { ) => { const key = `standard-field-${header}`; - const arr = _.get(stats, arrPath) || []; - const itemsByPlayer = arr; // _.keyBy(arr, "playerIndex"); + const arr = get(stats, arrPath) || []; + const itemsByPlayer = arr; // keyBy(arr, "playerIndex"); if (!arr || arr.length === 0) { return ( @@ -66,15 +68,11 @@ export const OverallTable = ({ file, stats }: OverallTableProps) => { ); } - const player1Item = arrPathExtension ? _.get(itemsByPlayer[0], arrPathExtension) : itemsByPlayer[0] || {}; - const player2Item = arrPathExtension ? _.get(itemsByPlayer[1], arrPathExtension) : itemsByPlayer[1] || {}; + const player1Item = arrPathExtension ? get(itemsByPlayer[0], arrPathExtension) : itemsByPlayer[0] || {}; + const player2Item = arrPathExtension ? get(itemsByPlayer[1], arrPathExtension) : itemsByPlayer[1] || {}; const generateValues = (item: any) => { if (fieldPaths !== null) { - return _.chain(item) - .pick(fieldPaths) - .toArray() - .map((v) => (valueMapper ? valueMapper(v) : v)) - .value(); + return toArray(pick(item, fieldPaths)).map((v) => (valueMapper ? valueMapper(v) : v)); } if (valueMapper) { @@ -106,8 +104,8 @@ export const OverallTable = ({ file, stats }: OverallTableProps) => { fieldPath: string, ratioRenderer: (ratio: RatioType, oppRatio: RatioType) => JSX.Element, ) => { - const arr = _.get(stats, arrPath) || []; - const itemsByPlayer = arr; // _.keyBy(arr, "playerIndex"); + const arr = get(stats, arrPath) || []; + const itemsByPlayer = arr; // keyBy(arr, "playerIndex"); const player1Item = itemsByPlayer[0] || {}; const player2Item = itemsByPlayer[1] || {}; @@ -116,8 +114,8 @@ export const OverallTable = ({ file, stats }: OverallTableProps) => { const item = firstPlayer ? player1Item : player2Item; const oppItem = firstPlayer ? player2Item : player1Item; - const ratio = _.get(item, fieldPath); - const oppRatio = _.get(oppItem, fieldPath); + const ratio = get(item, fieldPath); + const oppRatio = get(oppItem, fieldPath); return ratioRenderer(ratio, oppRatio); }; @@ -139,8 +137,8 @@ export const OverallTable = ({ file, stats }: OverallTableProps) => { highlightCondition: (a: number, b: number) => boolean, ) => { return renderRatioStatField(header, arrPath, fieldPath, (ratio: RatioType, oppRatio: RatioType) => { - const playerRatio = _.get(ratio, "ratio", null); - const oppRatioType = _.get(oppRatio, "ratio", null); + const playerRatio = get(ratio, "ratio", null); + const oppRatioType = get(oppRatio, "ratio", null); if (playerRatio === null) { return ( @@ -166,8 +164,8 @@ export const OverallTable = ({ file, stats }: OverallTableProps) => { highlightCondition: (a: number, b: number) => boolean, ) => { return renderRatioStatField(header, arrPath, fieldPath, (ratio, oppRatio) => { - const playerRatio = _.get(ratio, "ratio", null); - const oppRatioType = _.get(oppRatio, "ratio", null); + const playerRatio = get(ratio, "ratio", null); + const oppRatioType = get(oppRatio, "ratio", null); if (playerRatio === null || oppRatioType === null) { return ( @@ -179,8 +177,8 @@ export const OverallTable = ({ file, stats }: OverallTableProps) => { const fixedPlayerRatio = playerRatio.toFixed(3); const fixedOppRatio = oppRatioType.toFixed(3); - const playerCount = _.get(ratio, "count"); - const playerTotal = _.get(ratio, "total"); + const playerCount = get(ratio, "count"); + const playerTotal = get(ratio, "total"); return ( @@ -226,10 +224,10 @@ export const OverallTable = ({ file, stats }: OverallTableProps) => { highlightCondition: (a: number, b: number) => boolean, ) => { return renderRatioStatField(header, arrPath, fieldPath, (ratio: RatioType, oppRatio: RatioType) => { - const playerCount = _.get(ratio, "count") || 0; - const playerRatio = _.get(ratio, "ratio"); + const playerCount = get(ratio, "count") || 0; + const playerRatio = get(ratio, "ratio"); - const oppCount = _.get(oppRatio, "count") || 0; + const oppCount = get(oppRatio, "count") || 0; let secondaryDisplay = null; if (playerRatio !== null) { diff --git a/src/renderer/pages/replays/replay_file_stats/punish_table.tsx b/src/renderer/pages/replays/replay_file_stats/punish_table.tsx index 7d2583b8c..b3c60c933 100644 --- a/src/renderer/pages/replays/replay_file_stats/punish_table.tsx +++ b/src/renderer/pages/replays/replay_file_stats/punish_table.tsx @@ -2,7 +2,10 @@ import { css } from "@emotion/react"; import Tooltip from "@mui/material/Tooltip"; import type { FileResult, PlayerInfo } from "@replays/types"; import type { ConversionType, StatsType, StockType } from "@slippi/slippi-js"; -import _ from "lodash"; +import get from "lodash/get"; +import groupBy from "lodash/groupBy"; +import keyBy from "lodash/keyBy"; +import range from "lodash/range"; import { convertFrameCountToDurationString } from "@/lib/time"; import { getCharacterIcon, toOrdinal } from "@/lib/utils"; @@ -99,7 +102,7 @@ export const PunishTable = ({ file, stats, player, opp, onPlay }: PunishTablePro const totalStocks = player.startStocks; const currentStocks = stock.count - 1; - const stockIcons = _.range(1, totalStocks != null ? totalStocks + 1 : 1).map((stockNum) => { + const stockIcons = range(1, totalStocks != null ? totalStocks + 1 : 1).map((stockNum) => { return ( { const players = file.game.players || []; - const playersByIndex = _.keyBy(players, "playerIndex"); + const playersByIndex = keyBy(players, "playerIndex"); return playersByIndex[playerIndex]; }; @@ -177,12 +180,12 @@ export const PunishTable = ({ file, stats, player, opp, onPlay }: PunishTablePro }; const renderPunishRows = () => { - const punishes = _.get(stats, "conversions") || []; - const punishesByPlayer = _.groupBy(punishes, "playerIndex"); + const punishes = get(stats, "conversions") || []; + const punishesByPlayer = groupBy(punishes, "playerIndex"); const playerPunishes = punishesByPlayer[opp.playerIndex] || []; - const stocks = _.get(stats, "stocks") || []; - const stocksTakenFromPlayer = _.groupBy(stocks, "playerIndex"); + const stocks = get(stats, "stocks") || []; + const stocksTakenFromPlayer = groupBy(stocks, "playerIndex"); const opponentStocks = stocksTakenFromPlayer[opp.playerIndex] || []; const elements: JSX.Element[] = []; @@ -190,8 +193,8 @@ export const PunishTable = ({ file, stats, player, opp, onPlay }: PunishTablePro const addStockRows = (punish?: ConversionType) => { const shouldDisplayStockLoss = () => { // Calculates whether we should display a stock loss row in this position - const currentStock = _.first(opponentStocks); - if (!currentStock || currentStock.endFrame === null || currentStock.endFrame === undefined) { + const currentStock = opponentStocks[0]; + if (!currentStock || currentStock.endFrame == null) { return false; } @@ -208,7 +211,7 @@ export const PunishTable = ({ file, stats, player, opp, onPlay }: PunishTablePro // rendered one after another. but will initialize to true if we are considering // the very first punish, this is the handle the case where someone SD's on first // stock - let shouldAddEmptyState = punish === _.first(playerPunishes); + let shouldAddEmptyState = punish === playerPunishes[0]; while (shouldDisplayStockLoss()) { const stock = opponentStocks.shift(); @@ -231,7 +234,7 @@ export const PunishTable = ({ file, stats, player, opp, onPlay }: PunishTablePro // Special case handling when a player finishes their opponent without getting hit // on their last stock. Still want to show an empty state - const stock = _.first(opponentStocks); + const stock = opponentStocks[0]; if (stock && addedStockRow && !punish) { const emptyPunishes = generateEmptyRow(stock); elements.push(emptyPunishes); diff --git a/src/renderer/pages/replays/replay_file_stats/replay_file_stats.tsx b/src/renderer/pages/replays/replay_file_stats/replay_file_stats.tsx index 3b1baa474..c6fd31f21 100644 --- a/src/renderer/pages/replays/replay_file_stats/replay_file_stats.tsx +++ b/src/renderer/pages/replays/replay_file_stats/replay_file_stats.tsx @@ -8,7 +8,6 @@ import IconButton from "@mui/material/IconButton"; import Tooltip from "@mui/material/Tooltip"; import type { FileResult } from "@replays/types"; import { GameMode } from "@slippi/slippi-js"; -import _ from "lodash"; import { useQuery } from "react-query"; import { BasicFooter } from "@/components/footer/footer"; diff --git a/src/renderer/pages/settings/chat_settings/chat_messages_input.tsx b/src/renderer/pages/settings/chat_settings/chat_messages_input.tsx index 522629520..86c7432ad 100644 --- a/src/renderer/pages/settings/chat_settings/chat_messages_input.tsx +++ b/src/renderer/pages/settings/chat_settings/chat_messages_input.tsx @@ -9,7 +9,8 @@ import type { SelectChangeEvent } from "@mui/material/Select"; import Select from "@mui/material/Select"; import Typography from "@mui/material/Typography"; import log from "electron-log"; -import { capitalize, chain } from "lodash"; +import capitalize from "lodash/capitalize"; +import orderBy from "lodash/orderBy"; import type { MouseEventHandler } from "react"; import React, { useState } from "react"; @@ -165,45 +166,46 @@ const ChatMessageSelector = ({ })); }; - const isLockedByMessage = chain(availableMessages) - .keyBy("text") - .mapValues((am) => { - return am.isPaid && user.subLevel === "NONE"; - }) - .value(); + const isPaidMessage = React.useMemo(() => { + return availableMessages.reduce((acc, current) => { + acc[current.text] = current.isPaid; + return acc; + }, {} as Record); + }, [availableMessages]); - const items = chain(availableMessages) - .orderBy(["isPaid", "text"]) - .filter((am) => am.text !== defaultMessage) - .map((am) => + const items = React.useMemo(() => { + const messageItems = orderBy(availableMessages, ["isPaid", "text"]) + .filter((am) => am.text !== defaultMessage) + .map((am) => + genChatMessageItem( + `${groupDirection}-${direction}-${am.text}`, + am.text, + am.isPaid, + false, + hoverStates[am.text] ?? false, + updateHoverState(am.text), + user, + ), + ); + + // Add default message to the top of the list + messageItems.unshift( genChatMessageItem( - `${groupDirection}-${direction}-${am.text}`, - am.text, - am.isPaid, + `${groupDirection}-${direction}-${defaultMessage}`, + defaultMessage, false, - hoverStates[am.text] ?? false, - updateHoverState(am.text), + true, + hoverStates[defaultMessage], + updateHoverState(defaultMessage), user, ), - ) - .value(); + ); - // Add default message to the top of the list - items.unshift( - genChatMessageItem( - `${groupDirection}-${direction}-${defaultMessage}`, - defaultMessage, - false, - true, - hoverStates[defaultMessage], - updateHoverState(defaultMessage), - user, - ), - ); + return messageItems; + }, [availableMessages, defaultMessage, direction, groupDirection, hoverStates, user]); const onChange = (event: SelectChangeEvent) => { - console.log(`Updating message to ${event.target.value}. isLocked: ${isLockedByMessage[event.target.value]}`); - if (isLockedByMessage[event.target.value]) { + if (isPaidMessage[event.target.value] && user.subLevel === "NONE") { // Don't allow change to locked item return; } diff --git a/src/renderer/pages/settings/chat_settings/use_chat_messages.ts b/src/renderer/pages/settings/chat_settings/use_chat_messages.ts index 4038cf9ab..037ffbb0e 100644 --- a/src/renderer/pages/settings/chat_settings/use_chat_messages.ts +++ b/src/renderer/pages/settings/chat_settings/use_chat_messages.ts @@ -1,4 +1,5 @@ -import { isEqual, keyBy } from "lodash"; +import isEqual from "lodash/isEqual"; +import keyBy from "lodash/keyBy"; import { useCallback, useEffect, useState } from "react"; import { useToasts } from "@/lib/hooks/use_toasts"; diff --git a/src/replays/file_system_replay_provider/replays.worker.ts b/src/replays/file_system_replay_provider/replays.worker.ts index b04d3087b..632b7e9fb 100644 --- a/src/replays/file_system_replay_provider/replays.worker.ts +++ b/src/replays/file_system_replay_provider/replays.worker.ts @@ -5,7 +5,6 @@ // TODO: Make electron-log work somehow import type { StadiumStatsType, StatsType } from "@slippi/slippi-js"; import { SlippiGame } from "@slippi/slippi-js"; -import _ from "lodash"; import type { ModuleMethods } from "threads/dist/types/master"; import { Observable, Subject } from "threads/observable"; import { expose } from "threads/worker"; @@ -54,7 +53,7 @@ const methods: WorkerSpec = { // For a valid SLP game, at the very least we should have valid settings const game = new SlippiGame(fullPath); const settings = game.getSettings(); - if (!settings || _.isEmpty(settings.players)) { + if (!settings || settings.players.length === 0) { throw new Error("Game settings could not be properly loaded."); }