Compare commits

...

3 Commits
v0.13.7 ... dev

Author SHA1 Message Date
kvan7
95c3c7cfcd fix fracture detection 2025-12-21 19:52:51 -06:00
kvan7
c23d9b5eb3 temp detection for fractured items 2025-12-20 20:29:39 -06:00
kvan7
73cd5a4712 remove split mac 2025-12-20 13:02:50 -06:00
5 changed files with 217 additions and 85 deletions

View File

@@ -26,9 +26,8 @@ if (process.platform !== "darwin") {
app.enableSandbox(); app.enableSandbox();
let tray: AppTray; let tray: AppTray;
// Ensure accessibility permissions on MacOS. (async () => {
if (process.platform === "darwin") { if (process.platform === "darwin") {
(async () => {
async function ensureAccessibilityPermission(): Promise<boolean> { async function ensureAccessibilityPermission(): Promise<boolean> {
if (systemPreferences.isTrustedAccessibilityClient(false)) return true; if (systemPreferences.isTrustedAccessibilityClient(false)) return true;
@@ -60,77 +59,8 @@ if (process.platform === "darwin") {
return; return;
} }
console.log("Accessibility permission granted, starting app"); console.log("Accessibility permission granted, starting app");
app.on("ready", async () => { }
tray = new AppTray(eventPipe);
const logger = new Logger(eventPipe);
const gameLogWatcher = new GameLogWatcher(eventPipe, logger);
const gameConfig = new GameConfig(eventPipe, logger);
const poeWindow = new GameWindow();
const appUpdater = new AppUpdater(eventPipe);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _httpProxy = new HttpProxy(server, logger);
if (process.env.VITE_DEV_SERVER_URL) {
try {
await installExtension(VUEJS_DEVTOOLS);
logger.write("info Vue Devtools installed");
} catch (error) {
logger.write(`error installing Vue Devtools: ${error}`);
console.log(`error installing Vue Devtools: ${error}`);
}
}
process.addListener("uncaughtException", (err) => {
logger.write(`error [uncaughtException] ${err.message}, ${err.stack}`);
});
process.addListener("unhandledRejection", (reason) => {
logger.write(`error [unhandledRejection] ${(reason as Error).stack}`);
});
setTimeout(
async () => {
const overlay = new OverlayWindow(eventPipe, logger, poeWindow);
// eslint-disable-next-line no-new
new OverlayVisibility(eventPipe, overlay, gameConfig);
const shortcuts = await Shortcuts.create(
logger,
overlay,
poeWindow,
gameConfig,
eventPipe,
);
eventPipe.onEventAnyClient(
"CLIENT->MAIN::update-host-config",
(cfg) => {
overlay.updateOpts(cfg.overlayKey, cfg.windowTitle);
shortcuts.updateActions(
cfg.shortcuts,
cfg.stashScroll,
cfg.logKeys,
cfg.restoreClipboard,
cfg.language,
);
gameLogWatcher.restart(cfg.clientLog ?? "", cfg.readClientLog);
gameConfig.readConfig(cfg.gameConfig ?? "");
appUpdater.checkAtStartup();
tray.overlayKey = cfg.overlayKey;
},
);
uIOhook.start();
console.log("uIOhook started");
const port = await startServer(appUpdater, logger);
// TODO: move up (currently crashes)
logger.write(
`info ${os.type()} ${os.release} / v${app.getVersion()}`,
);
overlay.loadAppPage(port);
tray.serverPort = port;
},
// fixes(linux): window is black instead of transparent
process.platform === "linux" ? 1000 : 0,
);
});
})();
} else {
app.on("ready", async () => { app.on("ready", async () => {
tray = new AppTray(eventPipe); tray = new AppTray(eventPipe);
const logger = new Logger(eventPipe); const logger = new Logger(eventPipe);
@@ -150,7 +80,6 @@ if (process.platform === "darwin") {
console.log(`error installing Vue Devtools: ${error}`); console.log(`error installing Vue Devtools: ${error}`);
} }
} }
process.addListener("uncaughtException", (err) => { process.addListener("uncaughtException", (err) => {
logger.write(`error [uncaughtException] ${err.message}, ${err.stack}`); logger.write(`error [uncaughtException] ${err.message}, ${err.stack}`);
}); });
@@ -199,4 +128,4 @@ if (process.platform === "darwin") {
process.platform === "linux" ? 1000 : 0, process.platform === "linux" ? 1000 : 0,
); );
}); });
} })();

View File

@@ -0,0 +1,73 @@
import { __testExports, ParserState } from "@/parser/Parser";
import { beforeEach, describe, expect, it } from "vitest";
import { setupTests } from "@specs/vitest.setup";
import {
FracturedItem,
FracturedItemNoModMarked,
RareItem,
TestItem,
} from "./items";
import { loadForLang } from "@/assets/data";
import { ParsedItem } from "@/parser/ParsedItem";
import { ModifierType } from "@/parser/modifiers";
describe("Parse Fractured Items", () => {
beforeEach(async () => {
setupTests();
await loadForLang("en");
});
it.each([
[FracturedItem, true],
[FracturedItemNoModMarked, true],
[RareItem, undefined],
])(
"%#, Each mod section is recognized",
(item: TestItem, isFractured: boolean | undefined) => {
const sections = __testExports.itemTextToSections(item.rawText);
const parsedItem = {} as ParsedItem;
__testExports.parseFracturedText(
sections[sections.length - 1],
parsedItem,
);
expect(parsedItem.isFractured).toBe(isFractured);
},
);
it("adds fractured if some mod is fractured", () => {
const parsedItem = {
newMods: [
{
info: { type: ModifierType.Fractured, tags: [] },
stats: [],
},
{
info: { type: ModifierType.Explicit, tags: [] },
stats: [],
},
{
info: { type: ModifierType.Explicit, tags: [] },
stats: [],
},
],
} as unknown as ParserState;
__testExports.parseFractured(parsedItem);
expect(parsedItem.isFractured).toBe(true);
});
it("does nothing if no mod is fractured", () => {
const parsedItem = {
newMods: [
{
info: { type: ModifierType.Implicit, tags: [] },
stats: [],
},
{
info: { type: ModifierType.Explicit, tags: [] },
stats: [],
},
],
} as unknown as ParserState;
__testExports.parseFractured(parsedItem);
expect(parsedItem.isFractured).toBeUndefined();
});
});

View File

@@ -686,5 +686,135 @@ RareMapFakeAllProps.mapMagicMonsters = 30;
RareMapFakeAllProps.mapRareMonsters = 71; RareMapFakeAllProps.mapRareMonsters = 71;
RareMapFakeAllProps.mapDropChance = 90; RareMapFakeAllProps.mapDropChance = 90;
RareMapFakeAllProps.mapItemRarity = 17; RareMapFakeAllProps.mapItemRarity = 17;
RareMapFakeAllProps.sectionCount = 5; RareMapFakeAllProps.sectionCount = 6;
// #endregion
// #region FracturedItem
export const FracturedItem = new TestItem(`Item Class: Bows
Rarity: Rare
Miracle Siege
Obliterator Bow
--------
Quality: +25% (augmented)
Physical Damage: 381-705 (augmented)
Critical Hit Chance: 9.40% (augmented)
Attacks per Second: 1.15
--------
Requires: Level 78, 163 (unmet) Dex
--------
Sockets: S S
--------
Item Level: 81
--------
36% increased Physical Damage (rune)
--------
{ Implicit Modifier }
50% reduced Projectile Range
--------
{ Prefix Modifier "Flaring" (Tier: 1) — Damage, Physical, Attack }
Adds 32(26-39) to 59(44-66) Physical Damage (fractured)
{ Prefix Modifier "Bloodthirsty" (Tier: 4) — Damage, Physical, Attack }
134(110-134)% increased Physical Damage
{ Prefix Modifier "Champion's" (Tier: 4) — Damage, Physical, Attack }
54(45-54)% increased Physical Damage
+113(98-123) to Accuracy Rating
{ Suffix Modifier "of the Essence" — Speed }
20(20-25)% chance to gain Onslaught on Killing Hits with this Weapon
{ Suffix Modifier "of the Essence" — Attack }
+3 to Level of all Attack Skills
{ Suffix Modifier "of Ruin" (Tier: 2) — Attack, Critical }
+4.4(3.81-4.4)% to Critical Hit Chance
--------
Fractured Item
`);
FracturedItem.category = ItemCategory.Bow;
FracturedItem.rarity = ItemRarity.Rare;
FracturedItem.quality = 25;
FracturedItem.weaponPHYSICAL = 381.5;
FracturedItem.weaponAS = 1.15;
FracturedItem.weaponCRIT = 9.4;
FracturedItem.itemLevel = 81;
FracturedItem.info.refName = "Obliterator Bow";
FracturedItem.isFractured = true;
FracturedItem.prefixCount = 3;
FracturedItem.suffixCount = 3;
FracturedItem.implicitCount = 1;
FracturedItem.sectionCount = 9;
FracturedItem.runeSockets = {
empty: 0,
current: 2,
normal: 2,
};
// #endregion
// #region FracturedItemNoModMarked
export const FracturedItemNoModMarked = new TestItem(`Item Class: Bows
Rarity: Rare
Miracle Siege
Obliterator Bow
--------
Quality: +25% (augmented)
Physical Damage: 381-705 (augmented)
Critical Hit Chance: 9.40% (augmented)
Attacks per Second: 1.15
--------
Requires: Level 78, 163 (unmet) Dex
--------
Sockets: S S
--------
Item Level: 81
--------
36% increased Physical Damage (rune)
--------
{ Implicit Modifier }
50% reduced Projectile Range
--------
{ Prefix Modifier "Flaring" (Tier: 1) — Damage, Physical, Attack }
Adds 32(26-39) to 59(44-66) Physical Damage
{ Prefix Modifier "Bloodthirsty" (Tier: 4) — Damage, Physical, Attack }
134(110-134)% increased Physical Damage
{ Prefix Modifier "Champion's" (Tier: 4) — Damage, Physical, Attack }
54(45-54)% increased Physical Damage
+113(98-123) to Accuracy Rating
{ Suffix Modifier "of the Essence" — Speed }
20(20-25)% chance to gain Onslaught on Killing Hits with this Weapon
{ Suffix Modifier "of the Essence" — Attack }
+3 to Level of all Attack Skills
{ Suffix Modifier "of Ruin" (Tier: 2) — Attack, Critical }
+4.4(3.81-4.4)% to Critical Hit Chance
--------
Fractured Item
`);
FracturedItemNoModMarked.category = ItemCategory.Bow;
FracturedItemNoModMarked.rarity = ItemRarity.Rare;
FracturedItemNoModMarked.quality = 25;
FracturedItemNoModMarked.weaponPHYSICAL = 381.5;
FracturedItemNoModMarked.weaponAS = 1.15;
FracturedItemNoModMarked.weaponCRIT = 9.4;
FracturedItemNoModMarked.itemLevel = 81;
FracturedItemNoModMarked.info.refName = "Obliterator Bow";
FracturedItemNoModMarked.isFractured = true;
FracturedItemNoModMarked.prefixCount = 3;
FracturedItemNoModMarked.suffixCount = 3;
FracturedItemNoModMarked.implicitCount = 1;
FracturedItemNoModMarked.sectionCount = 9;
FracturedItemNoModMarked.runeSockets = {
empty: 0,
current: 2,
normal: 2,
};
// #endregion // #endregion

View File

@@ -48,7 +48,7 @@ type SectionParseResult =
type ParserFn = (section: string[], item: ParserState) => SectionParseResult; type ParserFn = (section: string[], item: ParserState) => SectionParseResult;
type VirtualParserFn = (item: ParserState) => Result<never, string> | void; type VirtualParserFn = (item: ParserState) => Result<never, string> | void;
interface ParserState extends ParsedItem { export interface ParserState extends ParsedItem {
name: string; name: string;
baseType: string | undefined; baseType: string | undefined;
infoVariants: BaseType[]; infoVariants: BaseType[];
@@ -379,6 +379,7 @@ function parseBlightedMap(item: ParsedItem) {
} }
function parseFractured(item: ParserState) { function parseFractured(item: ParserState) {
// NOTE: partially also controlled by parseFracturedText
if (item.newMods.some((mod) => mod.info.type === ModifierType.Fractured)) { if (item.newMods.some((mod) => mod.info.type === ModifierType.Fractured)) {
item.isFractured = true; item.isFractured = true;
} }
@@ -1222,9 +1223,11 @@ function parsePriceNote(section: string[], item: ParsedItem) {
return "SECTION_SKIPPED"; return "SECTION_SKIPPED";
} }
function parseFracturedText(section: string[], _item: ParsedItem) { function parseFracturedText(section: string[], item: ParsedItem) {
for (const line of section) { for (const line of section) {
if (line === _$.FRACTURED_ITEM) { if (line === _$.FRACTURED_ITEM) {
// HACK: remove once bug is fixed (https://www.pathofexile.com/forum/view-thread/3891367)
item.isFractured = true;
return "SECTION_PARSED"; return "SECTION_PARSED";
} }
} }
@@ -1754,4 +1757,6 @@ export const __testExports = {
parseArmour, parseArmour,
parseModifiers, parseModifiers,
parseWaystone, parseWaystone,
parseFractured,
parseFracturedText,
}; };

View File

@@ -1,10 +1,5 @@
import type { ItemFilters } from "./interfaces"; import type { ItemFilters } from "./interfaces";
import { import { ParsedItem, ItemCategory, ItemRarity } from "@/parser";
ParsedItem,
ItemCategory,
ItemRarity,
itemIsModifiable,
} from "@/parser";
import { tradeTag } from "../trade/common"; import { tradeTag } from "../trade/common";
import { ModifierType } from "@/parser/modifiers"; import { ModifierType } from "@/parser/modifiers";
import { BaseType, ITEM_BY_REF } from "@/assets/data"; import { BaseType, ITEM_BY_REF } from "@/assets/data";
@@ -355,7 +350,7 @@ export function createFilters(
filters.sanctified = { disabled: false }; filters.sanctified = { disabled: false };
} }
if (!item.isFractured && itemIsModifiable(item)) { if (!item.isFractured && opts.exact) {
filters.fractured = { value: false }; filters.fractured = { value: false };
} }