Enforced stricter eslint rules.

This commit is contained in:
Daan Vanden Bosch 2019-07-02 20:56:33 +02:00
parent 3498a10385
commit 19681d69a3
43 changed files with 359 additions and 173 deletions

41
.eslintrc.json Normal file
View File

@ -0,0 +1,41 @@
{
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
"plugins": ["react", "@typescript-eslint", "prettier"],
"env": {
"browser": true,
"es6": true,
"jest": true,
"node": true
},
"rules": {
"@typescript-eslint/array-type": ["warn", "array"],
"@typescript-eslint/camelcase": "off",
"@typescript-eslint/class-name-casing": "warn",
"@typescript-eslint/explicit-function-return-type": ["warn", { "allowExpressions": true }],
"@typescript-eslint/explicit-member-accessibility": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-inferrable-types": "warn",
"@typescript-eslint/no-parameter-properties": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/prefer-interface": "off",
"no-constant-condition": ["warn", { "checkLoops": false }],
"no-empty": "warn",
"prettier/prettier": ["warn"],
"react/no-unescaped-entities": "off",
"@typescript-eslint/no-non-null-assertion": "off"
},
"settings": {
"react": {
"pragma": "React",
"version": "detect"
}
},
"parser": "@typescript-eslint/parser"
}

View File

@ -1,5 +1,8 @@
const CracoAntDesignPlugin = require("craco-antd"); const CracoAntDesignPlugin = require("craco-antd");
module.exports = { module.exports = {
plugins: [{ plugin: CracoAntDesignPlugin }] plugins: [{ plugin: CracoAntDesignPlugin }],
eslint: {
mode: "file"
}
}; };

View File

@ -53,7 +53,12 @@
}, },
"devDependencies": { "devDependencies": {
"@types/cheerio": "^0.22.11", "@types/cheerio": "^0.22.11",
"@typescript-eslint/eslint-plugin": "^1.11.0",
"@typescript-eslint/parser": "^1.11.0",
"cheerio": "^1.0.0-rc.3", "cheerio": "^1.0.0-rc.3",
"eslint-config-prettier": "^6.0.0",
"eslint-config-react": "^1.1.7",
"eslint-plugin-prettier": "^3.1.0",
"prettier": "1.18.2", "prettier": "1.18.2",
"ts-node": "^8.3.0" "ts-node": "^8.3.0"
} }

View File

@ -101,7 +101,7 @@ export class BufferCursor {
* *
* @param offset - if positive, seeks forward by offset bytes, otherwise seeks backward by -offset bytes. * @param offset - if positive, seeks forward by offset bytes, otherwise seeks backward by -offset bytes.
*/ */
seek(offset: number) { seek(offset: number): BufferCursor {
return this.seek_start(this.position + offset); return this.seek_start(this.position + offset);
} }
@ -110,7 +110,7 @@ export class BufferCursor {
* *
* @param offset - greater or equal to 0 and smaller than size * @param offset - greater or equal to 0 and smaller than size
*/ */
seek_start(offset: number) { seek_start(offset: number): BufferCursor {
if (offset < 0 || offset > this.size) { if (offset < 0 || offset > this.size) {
throw new Error(`Offset ${offset} is out of bounds.`); throw new Error(`Offset ${offset} is out of bounds.`);
} }
@ -124,7 +124,7 @@ export class BufferCursor {
* *
* @param offset - greater or equal to 0 and smaller than size * @param offset - greater or equal to 0 and smaller than size
*/ */
seek_end(offset: number) { seek_end(offset: number): BufferCursor {
if (offset < 0 || offset > this.size) { if (offset < 0 || offset > this.size) {
throw new Error(`Offset ${offset} is out of bounds.`); throw new Error(`Offset ${offset} is out of bounds.`);
} }
@ -136,14 +136,14 @@ export class BufferCursor {
/** /**
* Reads an unsigned 8-bit integer and increments position by 1. * Reads an unsigned 8-bit integer and increments position by 1.
*/ */
u8() { u8(): number {
return this.dv.getUint8(this.position++); return this.dv.getUint8(this.position++);
} }
/** /**
* Reads an unsigned 16-bit integer and increments position by 2. * Reads an unsigned 16-bit integer and increments position by 2.
*/ */
u16() { u16(): number {
const r = this.dv.getUint16(this.position, this.little_endian); const r = this.dv.getUint16(this.position, this.little_endian);
this.position += 2; this.position += 2;
return r; return r;
@ -152,7 +152,7 @@ export class BufferCursor {
/** /**
* Reads an unsigned 32-bit integer and increments position by 4. * Reads an unsigned 32-bit integer and increments position by 4.
*/ */
u32() { u32(): number {
const r = this.dv.getUint32(this.position, this.little_endian); const r = this.dv.getUint32(this.position, this.little_endian);
this.position += 4; this.position += 4;
return r; return r;
@ -161,14 +161,14 @@ export class BufferCursor {
/** /**
* Reads an signed 8-bit integer and increments position by 1. * Reads an signed 8-bit integer and increments position by 1.
*/ */
i8() { i8(): number {
return this.dv.getInt8(this.position++); return this.dv.getInt8(this.position++);
} }
/** /**
* Reads a signed 16-bit integer and increments position by 2. * Reads a signed 16-bit integer and increments position by 2.
*/ */
i16() { i16(): number {
const r = this.dv.getInt16(this.position, this.little_endian); const r = this.dv.getInt16(this.position, this.little_endian);
this.position += 2; this.position += 2;
return r; return r;
@ -177,7 +177,7 @@ export class BufferCursor {
/** /**
* Reads a signed 32-bit integer and increments position by 4. * Reads a signed 32-bit integer and increments position by 4.
*/ */
i32() { i32(): number {
const r = this.dv.getInt32(this.position, this.little_endian); const r = this.dv.getInt32(this.position, this.little_endian);
this.position += 4; this.position += 4;
return r; return r;
@ -186,7 +186,7 @@ export class BufferCursor {
/** /**
* Reads a 32-bit floating point number and increments position by 4. * Reads a 32-bit floating point number and increments position by 4.
*/ */
f32() { f32(): number {
const r = this.dv.getFloat32(this.position, this.little_endian); const r = this.dv.getFloat32(this.position, this.little_endian);
this.position += 4; this.position += 4;
return r; return r;
@ -250,7 +250,11 @@ export class BufferCursor {
/** /**
* Consumes up to maxByteLength bytes. * Consumes up to maxByteLength bytes.
*/ */
string_ascii(max_byte_length: number, null_terminated: boolean, drop_remaining: boolean) { string_ascii(
max_byte_length: number,
null_terminated: boolean,
drop_remaining: boolean
): string {
const string_length = null_terminated const string_length = null_terminated
? this.index_of_u8(0, max_byte_length) - this.position ? this.index_of_u8(0, max_byte_length) - this.position
: max_byte_length; : max_byte_length;
@ -265,7 +269,11 @@ export class BufferCursor {
/** /**
* Consumes up to maxByteLength bytes. * Consumes up to maxByteLength bytes.
*/ */
string_utf16(max_byte_length: number, null_terminated: boolean, drop_remaining: boolean) { string_utf16(
max_byte_length: number,
null_terminated: boolean,
drop_remaining: boolean
): string {
const string_length = null_terminated const string_length = null_terminated
? this.index_of_u16(0, max_byte_length) - this.position ? this.index_of_u16(0, max_byte_length) - this.position
: Math.floor(max_byte_length / 2) * 2; : Math.floor(max_byte_length / 2) * 2;
@ -282,7 +290,7 @@ export class BufferCursor {
/** /**
* Writes an unsigned 8-bit integer and increments position by 1. If necessary, grows the cursor and reallocates the underlying buffer. * Writes an unsigned 8-bit integer and increments position by 1. If necessary, grows the cursor and reallocates the underlying buffer.
*/ */
write_u8(value: number) { write_u8(value: number): BufferCursor {
this.ensure_capacity(this.position + 1); this.ensure_capacity(this.position + 1);
this.dv.setUint8(this.position++, value); this.dv.setUint8(this.position++, value);
@ -297,7 +305,7 @@ export class BufferCursor {
/** /**
* Writes an unsigned 16-bit integer and increments position by 2. If necessary, grows the cursor and reallocates the underlying buffer. * Writes an unsigned 16-bit integer and increments position by 2. If necessary, grows the cursor and reallocates the underlying buffer.
*/ */
write_u16(value: number) { write_u16(value: number): BufferCursor {
this.ensure_capacity(this.position + 2); this.ensure_capacity(this.position + 2);
this.dv.setUint16(this.position, value, this.little_endian); this.dv.setUint16(this.position, value, this.little_endian);
@ -313,7 +321,7 @@ export class BufferCursor {
/** /**
* Writes an unsigned 32-bit integer and increments position by 4. If necessary, grows the cursor and reallocates the underlying buffer. * Writes an unsigned 32-bit integer and increments position by 4. If necessary, grows the cursor and reallocates the underlying buffer.
*/ */
write_u32(value: number) { write_u32(value: number): BufferCursor {
this.ensure_capacity(this.position + 4); this.ensure_capacity(this.position + 4);
this.dv.setUint32(this.position, value, this.little_endian); this.dv.setUint32(this.position, value, this.little_endian);
@ -329,7 +337,7 @@ export class BufferCursor {
/** /**
* Writes a signed 32-bit integer and increments position by 4. If necessary, grows the cursor and reallocates the underlying buffer. * Writes a signed 32-bit integer and increments position by 4. If necessary, grows the cursor and reallocates the underlying buffer.
*/ */
write_i32(value: number) { write_i32(value: number): BufferCursor {
this.ensure_capacity(this.position + 4); this.ensure_capacity(this.position + 4);
this.dv.setInt32(this.position, value, this.little_endian); this.dv.setInt32(this.position, value, this.little_endian);
@ -345,7 +353,7 @@ export class BufferCursor {
/** /**
* Writes a 32-bit floating point number and increments position by 4. If necessary, grows the cursor and reallocates the underlying buffer. * Writes a 32-bit floating point number and increments position by 4. If necessary, grows the cursor and reallocates the underlying buffer.
*/ */
write_f32(value: number) { write_f32(value: number): BufferCursor {
this.ensure_capacity(this.position + 4); this.ensure_capacity(this.position + 4);
this.dv.setFloat32(this.position, value, this.little_endian); this.dv.setFloat32(this.position, value, this.little_endian);
@ -361,7 +369,7 @@ export class BufferCursor {
/** /**
* Writes an array of unsigned 8-bit integers and increments position by the array's length. If necessary, grows the cursor and reallocates the underlying buffer. * Writes an array of unsigned 8-bit integers and increments position by the array's length. If necessary, grows the cursor and reallocates the underlying buffer.
*/ */
write_u8_array(array: number[]) { write_u8_array(array: number[]): BufferCursor {
this.ensure_capacity(this.position + array.length); this.ensure_capacity(this.position + array.length);
new Uint8Array(this.buffer, this.position).set(new Uint8Array(array)); new Uint8Array(this.buffer, this.position).set(new Uint8Array(array));
@ -377,7 +385,7 @@ export class BufferCursor {
/** /**
* Writes the contents of other and increments position by the size of other. If necessary, grows the cursor and reallocates the underlying buffer. * Writes the contents of other and increments position by the size of other. If necessary, grows the cursor and reallocates the underlying buffer.
*/ */
write_cursor(other: BufferCursor) { write_cursor(other: BufferCursor): BufferCursor {
this.ensure_capacity(this.position + other.size); this.ensure_capacity(this.position + other.size);
new Uint8Array(this.buffer, this.position).set(new Uint8Array(other.buffer)); new Uint8Array(this.buffer, this.position).set(new Uint8Array(other.buffer));
@ -390,7 +398,7 @@ export class BufferCursor {
return this; return this;
} }
write_string_ascii(str: string, byte_length: number) { write_string_ascii(str: string, byte_length: number): BufferCursor {
let i = 0; let i = 0;
for (const byte of ASCII_ENCODER.encode(str)) { for (const byte of ASCII_ENCODER.encode(str)) {
@ -404,6 +412,8 @@ export class BufferCursor {
this.write_u8(0); this.write_u8(0);
++i; ++i;
} }
return this;
} }
/** /**
@ -413,7 +423,7 @@ export class BufferCursor {
return new Uint8Array(this.buffer, 0, this.size); return new Uint8Array(this.buffer, 0, this.size);
} }
private index_of_u8(value: number, max_byte_length: number) { private index_of_u8(value: number, max_byte_length: number): number {
const max_pos = Math.min(this.position + max_byte_length, this.size); const max_pos = Math.min(this.position + max_byte_length, this.size);
for (let i = this.position; i < max_pos; ++i) { for (let i = this.position; i < max_pos; ++i) {
@ -425,7 +435,7 @@ export class BufferCursor {
return this.position + max_byte_length; return this.position + max_byte_length;
} }
private index_of_u16(value: number, max_byte_length: number) { private index_of_u16(value: number, max_byte_length: number): number {
const max_pos = Math.min(this.position + max_byte_length, this.size); const max_pos = Math.min(this.position + max_byte_length, this.size);
for (let i = this.position; i < max_pos; i += 2) { for (let i = this.position; i < max_pos; i += 2) {
@ -440,7 +450,7 @@ export class BufferCursor {
/** /**
* Increases buffer size if necessary. * Increases buffer size if necessary.
*/ */
private ensure_capacity(min_new_size: number) { private ensure_capacity(min_new_size: number): void {
if (min_new_size > this.capacity) { if (min_new_size > this.capacity) {
let new_size = this.capacity || min_new_size; let new_size = this.capacity || min_new_size;

View File

@ -16,7 +16,7 @@ export class Vec3 {
return this; return this;
} }
clone() { clone(): Vec3 {
return new Vec3(this.x, this.y, this.z); return new Vec3(this.x, this.y, this.z);
} }
} }

View File

@ -260,8 +260,8 @@ class Context {
} }
class HashTable { class HashTable {
hash_to_offset: Array<number | null> = new Array(HASH_SIZE).fill(null); hash_to_offset: (number | null)[] = new Array(HASH_SIZE).fill(null);
masked_offset_to_prev: Array<number | null> = new Array(MAX_WINDOW).fill(null); masked_offset_to_prev: (number | null)[] = new Array(MAX_WINDOW).fill(null);
hash(cursor: BufferCursor): number { hash(cursor: BufferCursor): number {
let hash = cursor.u8(); let hash = cursor.u8();

View File

@ -3,7 +3,7 @@ import Logger from "js-logger";
const logger = Logger.get("data_formats/compression/prs/decompress"); const logger = Logger.get("data_formats/compression/prs/decompress");
export function decompress(cursor: BufferCursor) { export function decompress(cursor: BufferCursor): BufferCursor {
const ctx = new Context(cursor); const ctx = new Context(cursor);
while (true) { while (true) {
@ -65,7 +65,7 @@ class Context {
this.flag_bits_left = 0; this.flag_bits_left = 0;
} }
read_flag_bit() { read_flag_bit(): number {
// Fetch a new flag byte when the previous byte has been processed. // Fetch a new flag byte when the previous byte has been processed.
if (this.flag_bits_left === 0) { if (this.flag_bits_left === 0) {
this.flags = this.read_u8(); this.flags = this.read_u8();
@ -78,19 +78,19 @@ class Context {
return bit; return bit;
} }
copy_u8() { copy_u8(): void {
this.dst.write_u8(this.read_u8()); this.dst.write_u8(this.read_u8());
} }
read_u8() { read_u8(): number {
return this.src.u8(); return this.src.u8();
} }
read_u16() { read_u16(): number {
return this.src.u16(); return this.src.u16();
} }
offset_copy(offset: number, length: number) { offset_copy(offset: number, length: number): void {
if (offset < -8192 || offset > 0) { if (offset < -8192 || offset > 0) {
logger.error(`offset was ${offset}, should be between -8192 and 0.`); logger.error(`offset was ${offset}, should be between -8192 and 0.`);
} }

View File

@ -104,7 +104,7 @@ export function parse_item_pmt(cursor: BufferCursor): ItemPmt {
const compact_table_offsets = cursor.u16_array(main_table_size); const compact_table_offsets = cursor.u16_array(main_table_size);
const table_offsets: { offset: number; size: number }[] = []; const table_offsets: { offset: number; size: number }[] = [];
let expanded_offset: number = 0; let expanded_offset = 0;
for (const compact_offset of compact_table_offsets) { for (const compact_offset of compact_table_offsets) {
expanded_offset = expanded_offset + 4 * compact_offset; expanded_offset = expanded_offset + 4 * compact_offset;

View File

@ -20,26 +20,31 @@ export type NinjaVertex = {
export type NinjaModel = NjModel | XjModel; export type NinjaModel = NjModel | XjModel;
export class NinjaObject<M extends NinjaModel> { export class NinjaObject<M extends NinjaModel> {
evaluation_flags: NinjaEvaluationFlags;
model: M | undefined;
position: Vec3;
rotation: Vec3; // Euler angles in radians.
scale: Vec3;
children: NinjaObject<M>[];
private bone_cache = new Map<number, NinjaObject<M> | null>(); private bone_cache = new Map<number, NinjaObject<M> | null>();
private _bone_count = -1; private _bone_count = -1;
constructor( constructor(
public evaluation_flags: { evaluation_flags: NinjaEvaluationFlags,
no_translate: boolean; model: M | undefined,
no_rotate: boolean; position: Vec3,
no_scale: boolean; rotation: Vec3, // Euler angles in radians.
hidden: boolean; scale: Vec3,
break_child_trace: boolean; children: NinjaObject<M>[]
zxy_rotation_order: boolean; ) {
skip: boolean; this.evaluation_flags = evaluation_flags;
shape_skip: boolean; this.model = model;
}, this.position = position;
public model: M | undefined, this.rotation = rotation;
public position: Vec3, this.scale = scale;
public rotation: Vec3, // Euler angles in radians. this.children = children;
public scale: Vec3, }
public children: NinjaObject<M>[]
) {}
bone_count(): number { bone_count(): number {
if (this._bone_count === -1) { if (this._bone_count === -1) {
@ -86,6 +91,17 @@ export class NinjaObject<M extends NinjaModel> {
} }
} }
export type NinjaEvaluationFlags = {
no_translate: boolean;
no_rotate: boolean;
no_scale: boolean;
hidden: boolean;
break_child_trace: boolean;
zxy_rotation_order: boolean;
skip: boolean;
shape_skip: boolean;
};
export function parse_nj(cursor: BufferCursor): NinjaObject<NjModel>[] { export function parse_nj(cursor: BufferCursor): NinjaObject<NjModel>[] {
return parse_ninja(cursor, parse_nj_model, []); return parse_ninja(cursor, parse_nj_model, []);
} }

View File

@ -224,7 +224,9 @@ function parse_instruction_arguments(
// Strings // Strings
case "s": case "s":
case "S": case "S":
while (cursor.u16()) {} while (cursor.u16()) {
// Eat up the entire string.
}
break; break;
default: default:
@ -235,7 +237,7 @@ function parse_instruction_arguments(
return { args, size: cursor.position - old_pos }; return { args, size: cursor.position - old_pos };
} }
const opcode_list: Array<[number, string, string | null]> = [ const opcode_list: [number, string, string | null][] = [
[0x00, "nop", ""], [0x00, "nop", ""],
[0x01, "ret", ""], [0x01, "ret", ""],
[0x02, "sync", ""], [0x02, "sync", ""],
@ -516,7 +518,7 @@ const opcode_list: Array<[number, string, string | null]> = [
[0xff, "unknownFF", ""], [0xff, "unknownFF", ""],
]; ];
const f8_opcode_list: Array<[number, string, string | null]> = [ const f8_opcode_list: [number, string, string | null][] = [
[0x00, "unknown", null], [0x00, "unknown", null],
[0x01, "set_chat_callback?", "aRs"], [0x01, "set_chat_callback?", "aRs"],
[0x02, "unknown", null], [0x02, "unknown", null],
@ -775,7 +777,7 @@ const f8_opcode_list: Array<[number, string, string | null]> = [
[0xff, "unknown", null], [0xff, "unknown", null],
]; ];
const f9_opcode_list: Array<[number, string, string | null]> = [ const f9_opcode_list: [number, string, string | null][] = [
[0x00, "unknown", null], [0x00, "unknown", null],
[0x01, "dec2float", "RR"], [0x01, "dec2float", "RR"],
[0x02, "float2dec", "RR"], [0x02, "float2dec", "RR"],

View File

@ -10,7 +10,7 @@ export function parse_unitxt(buf: BufferCursor, compressed: boolean = true): Uni
const category_count = buf.u32(); const category_count = buf.u32();
const entry_counts = buf.u32_array(category_count); const entry_counts = buf.u32_array(category_count);
const category_entry_offsets: Array<Array<number>> = []; const category_entry_offsets: number[][] = [];
for (const entry_count of entry_counts) { for (const entry_count of entry_counts) {
category_entry_offsets.push(buf.u32_array(entry_count)); category_entry_offsets.push(buf.u32_array(entry_count));

View File

@ -1104,7 +1104,7 @@ export class NpcType {
NpcType.Shambertin.rare_type = NpcType.Kondrieu; NpcType.Shambertin.rare_type = NpcType.Kondrieu;
})(); })();
export const NpcTypes: Array<NpcType> = [ export const NpcTypes: NpcType[] = [
// //
// Unknown NPCs // Unknown NPCs
// //

View File

@ -29,7 +29,7 @@ export enum Episode {
export const Episodes: Episode[] = enum_values(Episode); export const Episodes: Episode[] = enum_values(Episode);
export function check_episode(episode: Episode) { export function check_episode(episode: Episode): void {
if (!Episode[episode]) { if (!Episode[episode]) {
throw new Error(`Invalid episode ${episode}.`); throw new Error(`Invalid episode ${episode}.`);
} }

View File

@ -27,7 +27,7 @@ export class ModelRenderer extends Renderer {
}); });
} }
set_model(model?: SkinnedMesh) { set_model(model?: SkinnedMesh): void {
if (this.model !== model) { if (this.model !== model) {
if (this.model) { if (this.model) {
this.scene.remove(this.model); this.scene.remove(this.model);
@ -48,7 +48,7 @@ export class ModelRenderer extends Renderer {
} }
} }
protected render() { protected render(): void {
this.controls.update(); this.controls.update();
if (model_viewer_store.animation) { if (model_viewer_store.animation) {

View File

@ -66,7 +66,7 @@ export class QuestRenderer extends Renderer {
this.scene.add(this.npc_geometry); this.scene.add(this.npc_geometry);
} }
set_quest_and_area(quest?: Quest, area?: Area) { set_quest_and_area(quest?: Quest, area?: Area): void {
let update = false; let update = false;
if (this.area !== area) { if (this.area !== area) {
@ -102,13 +102,13 @@ export class QuestRenderer extends Renderer {
} }
} }
protected render() { protected render(): void {
this.controls.update(); this.controls.update();
this.add_loaded_entities(); this.add_loaded_entities();
this.renderer.render(this.scene, this.camera); this.renderer.render(this.scene, this.camera);
} }
private async update_geometry() { private async update_geometry(): Promise<void> {
this.scene.remove(this.obj_geometry); this.scene.remove(this.obj_geometry);
this.scene.remove(this.npc_geometry); this.scene.remove(this.npc_geometry);
this.obj_geometry = new Object3D(); this.obj_geometry = new Object3D();
@ -152,7 +152,7 @@ export class QuestRenderer extends Renderer {
} }
} }
private add_loaded_entities() { private add_loaded_entities(): void {
if (this.quest && this.area && !this.quest_entities_loaded) { if (this.quest && this.area && !this.quest_entities_loaded) {
let loaded = true; let loaded = true;
@ -325,7 +325,7 @@ export class QuestRenderer extends Renderer {
} }
}; };
private pointer_pos_to_device_coords(e: MouseEvent) { private pointer_pos_to_device_coords(e: MouseEvent): Vector2 {
const coords = new Vector2(); const coords = new Vector2();
this.renderer.getSize(coords); this.renderer.getSize(coords);
coords.width = (e.offsetX / coords.width) * 2 - 1; coords.width = (e.offsetX / coords.width) * 2 - 1;
@ -412,7 +412,7 @@ export class QuestRenderer extends Renderer {
return {}; return {};
} }
private get_color(entity: QuestEntity, type: "normal" | "hover" | "selected") { private get_color(entity: QuestEntity, type: "normal" | "hover" | "selected"): number {
const is_npc = entity instanceof QuestNpc; const is_npc = entity instanceof QuestNpc;
switch (type) { switch (type) {

View File

@ -34,19 +34,19 @@ export class Renderer {
return this.renderer.domElement; return this.renderer.domElement;
} }
set_size(width: number, height: number) { set_size(width: number, height: number): void {
this.renderer.setSize(width, height); this.renderer.setSize(width, height);
this.camera.aspect = width / height; this.camera.aspect = width / height;
this.camera.updateProjectionMatrix(); this.camera.updateProjectionMatrix();
} }
protected reset_camera(position: Vector3, look_at: Vector3) { protected reset_camera(position: Vector3, look_at: Vector3): void {
this.controls.reset(); this.controls.reset();
this.camera.position.copy(position); this.camera.position.copy(position);
this.camera.lookAt(look_at); this.camera.lookAt(look_at);
} }
protected render() { protected render(): void {
this.controls.update(); this.controls.update();
this.renderer.render(this.scene, this.camera); this.renderer.render(this.scene, this.camera);
} }

View File

@ -59,7 +59,7 @@ type Vertex = {
class VerticesHolder { class VerticesHolder {
private vertices_stack: Vertex[][] = []; private vertices_stack: Vertex[][] = [];
put(vertices: Vertex[]) { put(vertices: Vertex[]): void {
this.vertices_stack.push(vertices); this.vertices_stack.push(vertices);
} }
@ -79,6 +79,7 @@ class VerticesHolder {
} }
class Object3DCreator { class Object3DCreator {
private material: Material;
private bone_id: number = 0; private bone_id: number = 0;
private vertices = new VerticesHolder(); private vertices = new VerticesHolder();
private positions: number[] = []; private positions: number[] = [];
@ -88,7 +89,9 @@ class Object3DCreator {
private bone_weights: number[] = []; private bone_weights: number[] = [];
private bones: Bone[] = []; private bones: Bone[] = [];
constructor(private material: Material) {} constructor(material: Material) {
this.material = material;
}
create_buffer_geometry(object: NinjaObject<NinjaModel>): BufferGeometry { create_buffer_geometry(object: NinjaObject<NinjaModel>): BufferGeometry {
this.object_to_geometry(object, undefined, new Matrix4()); this.object_to_geometry(object, undefined, new Matrix4());
@ -123,7 +126,7 @@ class Object3DCreator {
object: NinjaObject<NinjaModel>, object: NinjaObject<NinjaModel>,
parent_bone: Bone | undefined, parent_bone: Bone | undefined,
parent_matrix: Matrix4 parent_matrix: Matrix4
) { ): void {
const { const {
no_translate, no_translate,
no_rotate, no_rotate,
@ -179,7 +182,7 @@ class Object3DCreator {
} }
} }
private model_to_geometry(model: NinjaModel, matrix: Matrix4) { private model_to_geometry(model: NinjaModel, matrix: Matrix4): void {
if (model.type === "nj") { if (model.type === "nj") {
this.nj_model_to_geometry(model, matrix); this.nj_model_to_geometry(model, matrix);
} else { } else {
@ -187,7 +190,7 @@ class Object3DCreator {
} }
} }
private nj_model_to_geometry(model: NjModel, matrix: Matrix4) { private nj_model_to_geometry(model: NjModel, matrix: Matrix4): void {
const normal_matrix = new Matrix3().getNormalMatrix(matrix); const normal_matrix = new Matrix3().getNormalMatrix(matrix);
const new_vertices = model.vertices.map(vertex => { const new_vertices = model.vertices.map(vertex => {
@ -250,7 +253,7 @@ class Object3DCreator {
} }
} }
private xj_model_to_geometry(model: XjModel, matrix: Matrix4) { private xj_model_to_geometry(model: XjModel, matrix: Matrix4): void {
const positions = this.positions; const positions = this.positions;
const normals = this.normals; const normals = this.normals;
const indices = this.indices; const indices = this.indices;

View File

@ -9,6 +9,7 @@ const HEAVY_DAMAGE_FACTOR = NORMAL_DAMAGE_FACTOR * 1.89;
// const CRIT_FACTOR = 1.5; // const CRIT_FACTOR = 1.5;
class Weapon { class Weapon {
private readonly store: DpsCalcStore;
readonly item: WeaponItem; readonly item: WeaponItem;
@computed get shifta_atp(): number { @computed get shifta_atp(): number {
@ -71,7 +72,8 @@ class Weapon {
return (this.min_heavy_damage + this.max_heavy_damage) / 2; return (this.min_heavy_damage + this.max_heavy_damage) / 2;
} }
constructor(private store: DpsCalcStore, item: WeaponItem) { constructor(store: DpsCalcStore, item: WeaponItem) {
this.store = store;
this.item = item; this.item = item;
} }
} }

View File

@ -8,7 +8,7 @@ import { ServerMap } from "./ServerMap";
const logger = Logger.get("stores/HuntMethodStore"); const logger = Logger.get("stores/HuntMethodStore");
class HuntMethodStore { class HuntMethodStore {
@observable methods: ServerMap<Loadable<Array<HuntMethod>>> = new ServerMap( @observable methods: ServerMap<Loadable<HuntMethod[]>> = new ServerMap(
server => new Loadable([], () => this.load_hunt_methods(server)) server => new Loadable([], () => this.load_hunt_methods(server))
); );

View File

@ -32,25 +32,42 @@ export class WantedItem {
} }
export class OptimalResult { export class OptimalResult {
constructor( readonly wanted_items: ItemType[];
readonly wanted_items: Array<ItemType>, readonly optimal_methods: OptimalMethod[];
readonly optimal_methods: Array<OptimalMethod>
) {} constructor(wanted_items: ItemType[], optimal_methods: OptimalMethod[]) {
this.wanted_items = wanted_items;
this.optimal_methods = optimal_methods;
}
} }
export class OptimalMethod { export class OptimalMethod {
readonly difficulty: Difficulty;
readonly section_ids: SectionId[];
readonly method_name: string;
readonly method_episode: Episode;
readonly method_time: number;
readonly runs: number;
readonly total_time: number; readonly total_time: number;
readonly item_counts: Map<ItemType, number>;
constructor( constructor(
readonly difficulty: Difficulty, difficulty: Difficulty,
readonly section_ids: Array<SectionId>, section_ids: SectionId[],
readonly method_name: string, method_name: string,
readonly method_episode: Episode, method_episode: Episode,
readonly method_time: number, method_time: number,
readonly runs: number, runs: number,
readonly item_counts: Map<ItemType, number> item_counts: Map<ItemType, number>
) { ) {
this.difficulty = difficulty;
this.section_ids = section_ids;
this.method_name = method_name;
this.method_episode = method_episode;
this.method_time = method_time;
this.runs = runs;
this.total_time = runs * method_time; this.total_time = runs * method_time;
this.item_counts = item_counts;
} }
} }
@ -62,7 +79,7 @@ export class OptimalMethod {
// Can be useful when deciding which item to hunt first. // Can be useful when deciding which item to hunt first.
// TODO: boxes. // TODO: boxes.
class HuntOptimizerStore { class HuntOptimizerStore {
@computed get huntable_item_types(): Array<ItemType> { @computed get huntable_item_types(): ItemType[] {
const item_drop_store = item_drop_stores.current.value; const item_drop_store = item_drop_stores.current.value;
return item_type_stores.current.value.item_types.filter( return item_type_stores.current.value.item_types.filter(
i => item_drop_store.enemy_drops.get_drops_for_item_type(i.id).length i => item_drop_store.enemy_drops.get_drops_for_item_type(i.id).length
@ -148,7 +165,7 @@ class HuntOptimizerStore {
// Create a secondary counts map if there are any pan arms that can be split into // Create a secondary counts map if there are any pan arms that can be split into
// migiums and hidooms. // migiums and hidooms.
const counts_list: Array<Map<NpcType, number>> = [counts]; const counts_list: Map<NpcType, number>[] = [counts];
const pan_arms_count = counts.get(NpcType.PanArms); const pan_arms_count = counts.get(NpcType.PanArms);
if (pan_arms_count) { if (pan_arms_count) {
@ -237,7 +254,7 @@ class HuntOptimizerStore {
return; return;
} }
const optimal_methods: Array<OptimalMethod> = []; const optimal_methods: OptimalMethod[] = [];
// Loop over the entries in result, ignore standard properties that aren't variables. // Loop over the entries in result, ignore standard properties that aren't variables.
for (const [variable_name, runs_or_other] of Object.entries(result)) { for (const [variable_name, runs_or_other] of Object.entries(result)) {
@ -262,7 +279,7 @@ class HuntOptimizerStore {
// Find all section IDs that provide the same items with the same expected amount. // Find all section IDs that provide the same items with the same expected amount.
// E.g. if you need a spread needle and a bringer's right arm, using either // E.g. if you need a spread needle and a bringer's right arm, using either
// purplenum or yellowboze will give you the exact same probabilities. // purplenum or yellowboze will give you the exact same probabilities.
const section_ids: Array<SectionId> = []; const section_ids: SectionId[] = [];
for (const sid of SectionIds) { for (const sid of SectionIds) {
let match_found = true; let match_found = true;

View File

@ -38,7 +38,12 @@ export class EnemyDropTable {
]; ];
} }
set_drop(difficulty: Difficulty, section_id: SectionId, npc_type: NpcType, drop: EnemyDrop) { set_drop(
difficulty: Difficulty,
section_id: SectionId,
npc_type: NpcType,
drop: EnemyDrop
): void {
this.table[ this.table[
difficulty * SectionIds.length * NpcTypes.length + difficulty * SectionIds.length * NpcTypes.length +
section_id * NpcTypes.length + section_id * NpcTypes.length +

View File

@ -13,9 +13,9 @@ import { ServerMap } from "./ServerMap";
import { ItemTypeDto } from "../dto"; import { ItemTypeDto } from "../dto";
export class ItemTypeStore { export class ItemTypeStore {
private id_to_item_type: Array<ItemType> = []; private id_to_item_type: ItemType[] = [];
@observable item_types: Array<ItemType> = []; @observable item_types: ItemType[] = [];
get_by_id(id: number): ItemType | undefined { get_by_id(id: number): ItemType | undefined {
return this.id_to_item_type[id]; return this.id_to_item_type[id];
@ -25,7 +25,7 @@ export class ItemTypeStore {
const response = await fetch( const response = await fetch(
`${process.env.PUBLIC_URL}/itemTypes.${Server[server].toLowerCase()}.json` `${process.env.PUBLIC_URL}/itemTypes.${Server[server].toLowerCase()}.json`
); );
const data: Array<ItemTypeDto> = await response.json(); const data: ItemTypeDto[] = await response.json();
const item_types = new Array<ItemType>(); const item_types = new Array<ItemType>();

View File

@ -135,7 +135,7 @@ class ModelViewerStore {
object: NinjaObject<NinjaModel>, object: NinjaObject<NinjaModel>,
head_part: NinjaObject<NinjaModel>, head_part: NinjaObject<NinjaModel>,
bone_id: number bone_id: number
) { ): void {
const bone = object.get_bone(bone_id); const bone = object.get_bone(bone_id);
if (bone) { if (bone) {

View File

@ -27,7 +27,7 @@ class QuestEditorStore {
} }
}); });
private reset_quest_state() { private reset_quest_state(): void {
this.current_quest = undefined; this.current_quest = undefined;
this.current_area = undefined; this.current_area = undefined;
this.selected_entity = undefined; this.selected_entity = undefined;

View File

@ -1,7 +1,7 @@
import { Menu, Select } from "antd"; import { Menu, Select } from "antd";
import { ClickParam } from "antd/lib/menu"; import { ClickParam } from "antd/lib/menu";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import React from "react"; import React, { ReactNode } from "react";
import "./ApplicationComponent.less"; import "./ApplicationComponent.less";
import { with_error_boundary } from "./ErrorBoundary"; import { with_error_boundary } from "./ErrorBoundary";
import { HuntOptimizerComponent } from "./hunt_optimizer/HuntOptimizerComponent"; import { HuntOptimizerComponent } from "./hunt_optimizer/HuntOptimizerComponent";
@ -19,7 +19,7 @@ const DpsCalc = with_error_boundary(DpsCalcComponent);
export class ApplicationComponent extends React.Component { export class ApplicationComponent extends React.Component {
state = { tool: this.init_tool() }; state = { tool: this.init_tool() };
render() { render(): ReactNode {
let tool_component; let tool_component;
switch (this.state.tool) { switch (this.state.tool) {

View File

@ -1,4 +1,4 @@
import React, { PureComponent } from "react"; import React, { PureComponent, ReactNode } from "react";
import { import {
OptionValues, OptionValues,
ReactAsyncSelectProps, ReactAsyncSelectProps,
@ -14,7 +14,7 @@ import "./BigSelect.less";
export class BigSelect<TValue = OptionValues> extends PureComponent< export class BigSelect<TValue = OptionValues> extends PureComponent<
VirtualizedSelectProps<TValue> VirtualizedSelectProps<TValue>
> { > {
render() { render(): ReactNode {
return <VirtualizedSelect className="BigSelect" {...this.props} />; return <VirtualizedSelect className="BigSelect" {...this.props} />;
} }
} }

View File

@ -1,4 +1,4 @@
import React, { ReactNode } from "react"; import React, { ReactNode, Component } from "react";
import { import {
GridCellRenderer, GridCellRenderer,
Index, Index,
@ -8,7 +8,7 @@ import {
} from "react-virtualized"; } from "react-virtualized";
import "./BigTable.less"; import "./BigTable.less";
export type Column<T> = { export interface Column<T> {
key?: string; key?: string;
name: string; name: string;
width: number; width: number;
@ -21,7 +21,7 @@ export type Column<T> = {
*/ */
class_name?: string; class_name?: string;
sortable?: boolean; sortable?: boolean;
}; }
export type ColumnSort<T> = { column: Column<T>; direction: SortDirectionType }; export type ColumnSort<T> = { column: Column<T>; direction: SortDirectionType };
@ -30,12 +30,12 @@ export type ColumnSort<T> = { column: Column<T>; direction: SortDirectionType };
* Uses windowing to support large amounts of rows and columns. * Uses windowing to support large amounts of rows and columns.
* TODO: no-content message. * TODO: no-content message.
*/ */
export class BigTable<T> extends React.Component<{ export class BigTable<T> extends Component<{
width: number; width: number;
height: number; height: number;
row_count: number; row_count: number;
overscan_row_count?: number; overscan_row_count?: number;
columns: Array<Column<T>>; columns: Column<T>[];
fixed_column_count?: number; fixed_column_count?: number;
overscan_column_count?: number; overscan_column_count?: number;
record: (index: Index) => T; record: (index: Index) => T;
@ -44,11 +44,11 @@ export class BigTable<T> extends React.Component<{
* When this changes, the DataTable will re-render. * When this changes, the DataTable will re-render.
*/ */
update_trigger?: any; update_trigger?: any;
sort?: (sort_columns: Array<ColumnSort<T>>) => void; sort?: (sort_columns: ColumnSort<T>[]) => void;
}> { }> {
private sort_columns = new Array<ColumnSort<T>>(); private sort_columns = new Array<ColumnSort<T>>();
render() { render(): ReactNode {
return ( return (
<div <div
className="DataTable" className="DataTable"
@ -78,7 +78,7 @@ export class BigTable<T> extends React.Component<{
return this.props.columns[index].width; return this.props.columns[index].width;
}; };
private cell_renderer: GridCellRenderer = ({ columnIndex, rowIndex, style }) => { private cell_renderer: GridCellRenderer = ({ columnIndex, rowIndex, style }): ReactNode => {
const column = this.props.columns[columnIndex]; const column = this.props.columns[columnIndex];
let cell: ReactNode; let cell: ReactNode;
let sort_indicator: ReactNode; let sort_indicator: ReactNode;
@ -174,12 +174,12 @@ export class BigTable<T> extends React.Component<{
); );
}; };
private header_clicked = (column: Column<T>) => { private header_clicked = (column: Column<T>): void => {
const old_index = this.sort_columns.findIndex(sc => sc.column === column); const old_index = this.sort_columns.findIndex(sc => sc.column === column);
let old = old_index === -1 ? undefined : this.sort_columns.splice(old_index, 1)[0]; let old = old_index === -1 ? undefined : this.sort_columns.splice(old_index, 1)[0];
const direction = const direction =
old_index === 0 && old!.direction === SortDirection.ASC old_index === 0 && old && old.direction === SortDirection.ASC
? SortDirection.DESC ? SortDirection.DESC
: SortDirection.ASC; : SortDirection.ASC;

View File

@ -1,13 +1,15 @@
import { Alert } from "antd"; import { Alert } from "antd";
import React from "react"; import React, { ReactNode, Component, ComponentType } from "react";
import "./ErrorBoundary.css"; import "./ErrorBoundary.css";
export class ErrorBoundary extends React.Component { type State = { has_error: boolean };
export class ErrorBoundary extends Component<{}, State> {
state = { state = {
has_error: false, has_error: false,
}; };
render() { render(): ReactNode {
if (this.state.has_error) { if (this.state.has_error) {
return ( return (
<div className="ErrorBoundary-error"> <div className="ErrorBoundary-error">
@ -21,15 +23,17 @@ export class ErrorBoundary extends React.Component {
} }
} }
static getDerivedStateFromError(_error: any) { static getDerivedStateFromError(): State {
return { hasError: true }; return { has_error: true };
} }
} }
export function with_error_boundary(Component: React.ComponentType) { export function with_error_boundary(Component: ComponentType): ComponentType {
return () => ( const ComponentErrorBoundary = (): JSX.Element => (
<ErrorBoundary> <ErrorBoundary>
<Component /> <Component />
</ErrorBoundary> </ErrorBoundary>
); );
ComponentErrorBoundary.displayName = `${Component.displayName}ErrorBoundary`;
return ComponentErrorBoundary;
} }

View File

@ -9,7 +9,7 @@ export function SectionIdIcon({
section_id: SectionId; section_id: SectionId;
size?: number; size?: number;
title?: string; title?: string;
}) { }): JSX.Element {
return ( return (
<div <div
title={title} title={title}

View File

@ -1,14 +1,14 @@
import { InputNumber } from "antd"; import { InputNumber } from "antd";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import React from "react"; import React, { ReactNode, Component } from "react";
import { WeaponItemType, ArmorItemType, ShieldItemType } from "../../domain"; import { WeaponItemType, ArmorItemType, ShieldItemType } from "../../domain";
import { dps_calc_store } from "../../stores/DpsCalcStore"; import { dps_calc_store } from "../../stores/DpsCalcStore";
import { item_type_stores } from "../../stores/ItemTypeStore"; import { item_type_stores } from "../../stores/ItemTypeStore";
import { BigSelect } from "../BigSelect"; import { BigSelect } from "../BigSelect";
@observer @observer
export class DpsCalcComponent extends React.Component { export class DpsCalcComponent extends Component {
render() { render(): ReactNode {
return ( return (
<section> <section>
<section> <section>

View File

@ -6,7 +6,7 @@ import { MethodsComponent } from "./MethodsComponent";
const TabPane = Tabs.TabPane; const TabPane = Tabs.TabPane;
export function HuntOptimizerComponent() { export function HuntOptimizerComponent(): JSX.Element {
return ( return (
<section className="ho-HuntOptimizerComponent"> <section className="ho-HuntOptimizerComponent">
<Tabs type="card"> <Tabs type="card">

View File

@ -1,7 +1,7 @@
import { TimePicker } from "antd"; import { TimePicker } from "antd";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import moment, { Moment } from "moment"; import moment, { Moment } from "moment";
import React from "react"; import React, { ReactNode, Component } from "react";
import { AutoSizer, Index, SortDirection } from "react-virtualized"; import { AutoSizer, Index, SortDirection } from "react-virtualized";
import { Episode, HuntMethod } from "../../domain"; import { Episode, HuntMethod } from "../../domain";
import { EnemyNpcTypes, NpcType } from "../../domain/NpcType"; import { EnemyNpcTypes, NpcType } from "../../domain/NpcType";
@ -10,8 +10,8 @@ import { BigTable, Column, ColumnSort } from "../BigTable";
import "./MethodsComponent.css"; import "./MethodsComponent.css";
@observer @observer
export class MethodsComponent extends React.Component { export class MethodsComponent extends Component {
static columns: Array<Column<HuntMethod>> = (() => { static columns: Column<HuntMethod>[] = (() => {
// Standard columns. // Standard columns.
const columns: Column<HuntMethod>[] = [ const columns: Column<HuntMethod>[] = [
{ {
@ -56,7 +56,7 @@ export class MethodsComponent extends React.Component {
return columns; return columns;
})(); })();
render() { render(): ReactNode {
const methods = hunt_method_store.methods.current.value; const methods = hunt_method_store.methods.current.value;
return ( return (
@ -118,7 +118,7 @@ export class MethodsComponent extends React.Component {
@observer @observer
class TimeComponent extends React.Component<{ method: HuntMethod }> { class TimeComponent extends React.Component<{ method: HuntMethod }> {
render() { render(): ReactNode {
const time = this.props.method.time; const time = this.props.method.time;
const hour = Math.floor(time); const hour = Math.floor(time);
const minute = Math.round(60 * (time - hour)); const minute = Math.round(60 * (time - hour));

View File

@ -1,6 +1,6 @@
import { computed } from "mobx"; import { computed } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import React from "react"; import React, { Component, ReactNode } from "react";
import { AutoSizer, Index } from "react-virtualized"; import { AutoSizer, Index } from "react-virtualized";
import { Difficulty, Episode, SectionId } from "../../domain"; import { Difficulty, Episode, SectionId } from "../../domain";
import { hunt_optimizer_store, OptimalMethod } from "../../stores/HuntOptimizerStore"; import { hunt_optimizer_store, OptimalMethod } from "../../stores/HuntOptimizerStore";
@ -10,7 +10,7 @@ import { hours_to_string } from "../time";
import "./OptimizationResultComponent.less"; import "./OptimizationResultComponent.less";
@observer @observer
export class OptimizationResultComponent extends React.Component { export class OptimizationResultComponent extends Component {
@computed private get columns(): Column<OptimalMethod>[] { @computed private get columns(): Column<OptimalMethod>[] {
// Standard columns. // Standard columns.
const result = hunt_optimizer_store.result; const result = hunt_optimizer_store.result;
@ -110,11 +110,11 @@ export class OptimizationResultComponent extends React.Component {
} }
// Make sure render is called when result changes. // Make sure render is called when result changes.
@computed private get update_trigger() { @computed private get update_trigger(): any {
return hunt_optimizer_store.result; return hunt_optimizer_store.result;
} }
render() { render(): ReactNode {
this.update_trigger; // eslint-disable-line this.update_trigger; // eslint-disable-line
const result = hunt_optimizer_store.result; const result = hunt_optimizer_store.result;

View File

@ -3,7 +3,7 @@ import { WantedItemsComponent } from "./WantedItemsComponent";
import { OptimizationResultComponent } from "./OptimizationResultComponent"; import { OptimizationResultComponent } from "./OptimizationResultComponent";
import "./OptimizerComponent.css"; import "./OptimizerComponent.css";
export function OptimizerComponent() { export function OptimizerComponent(): JSX.Element {
return ( return (
<section className="ho-OptimizerComponent"> <section className="ho-OptimizerComponent">
<WantedItemsComponent /> <WantedItemsComponent />

View File

@ -1,6 +1,6 @@
import { Button, InputNumber, Popover } from "antd"; import { Button, InputNumber, Popover } from "antd";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import React from "react"; import React, { ReactNode, Component } from "react";
import { AutoSizer, Column, Table, TableCellRenderer } from "react-virtualized"; import { AutoSizer, Column, Table, TableCellRenderer } from "react-virtualized";
import { hunt_optimizer_store, WantedItem } from "../../stores/HuntOptimizerStore"; import { hunt_optimizer_store, WantedItem } from "../../stores/HuntOptimizerStore";
import { item_type_stores } from "../../stores/ItemTypeStore"; import { item_type_stores } from "../../stores/ItemTypeStore";
@ -8,12 +8,12 @@ import { BigSelect } from "../BigSelect";
import "./WantedItemsComponent.less"; import "./WantedItemsComponent.less";
@observer @observer
export class WantedItemsComponent extends React.Component { export class WantedItemsComponent extends Component {
state = { state = {
help_visible: false, help_visible: false,
}; };
render() { render(): ReactNode {
// Make sure render is called on updates. // Make sure render is called on updates.
hunt_optimizer_store.wanted_items.slice(0, 0); hunt_optimizer_store.wanted_items.slice(0, 0);
@ -128,7 +128,7 @@ export class WantedItemsComponent extends React.Component {
}; };
} }
function Help() { function Help(): JSX.Element {
return ( return (
<div className="ho-WantedItemsComponent-help"> <div className="ho-WantedItemsComponent-help">
<p> <p>
@ -151,8 +151,8 @@ function Help() {
} }
@observer @observer
class WantedAmountCell extends React.Component<{ wantedItem: WantedItem }> { class WantedAmountCell extends Component<{ wantedItem: WantedItem }> {
render() { render(): ReactNode {
const wanted = this.props.wantedItem; const wanted = this.props.wantedItem;
return ( return (

View File

@ -1,10 +1,10 @@
import { List } from "antd"; import { List } from "antd";
import React, { Component } from "react"; import React, { Component, ReactNode } from "react";
import { model_viewer_store } from "../../stores/ModelViewerStore"; import { model_viewer_store } from "../../stores/ModelViewerStore";
import "./ModelSelectionComponent.less"; import "./ModelSelectionComponent.less";
export class ModelSelectionComponent extends Component { export class ModelSelectionComponent extends Component {
render() { render(): ReactNode {
return ( return (
<section className="mv-ModelSelectionComponent"> <section className="mv-ModelSelectionComponent">
<List <List

View File

@ -2,21 +2,21 @@ import { Button, InputNumber, Upload, Switch } from "antd";
import { UploadChangeParam } from "antd/lib/upload"; import { UploadChangeParam } from "antd/lib/upload";
import { UploadFile } from "antd/lib/upload/interface"; import { UploadFile } from "antd/lib/upload/interface";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import React from "react"; import React, { ReactNode, Component } from "react";
import { model_viewer_store } from "../../stores/ModelViewerStore"; import { model_viewer_store } from "../../stores/ModelViewerStore";
import { ModelSelectionComponent } from "./ModelSelectionComponent"; import { ModelSelectionComponent } from "./ModelSelectionComponent";
import "./ModelViewerComponent.less"; import "./ModelViewerComponent.less";
import { RendererComponent } from "./RendererComponent"; import { RendererComponent } from "./RendererComponent";
@observer @observer
export class ModelViewerComponent extends React.Component { export class ModelViewerComponent extends Component {
componentDidMount() { componentDidMount(): void {
if (!model_viewer_store.current_model) { if (!model_viewer_store.current_model) {
model_viewer_store.load_model(model_viewer_store.models[5]); model_viewer_store.load_model(model_viewer_store.models[5]);
} }
} }
render() { render(): ReactNode {
return ( return (
<div className="mv-ModelViewerComponent"> <div className="mv-ModelViewerComponent">
<Toolbar /> <Toolbar />
@ -30,12 +30,12 @@ export class ModelViewerComponent extends React.Component {
} }
@observer @observer
class Toolbar extends React.Component { class Toolbar extends Component {
state = { state = {
filename: undefined, filename: undefined,
}; };
render() { render(): ReactNode {
return ( return (
<div className="mv-ModelViewerComponent-toolbar"> <div className="mv-ModelViewerComponent-toolbar">
<Upload <Upload

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { ReactNode, Component } from "react";
import { SkinnedMesh } from "three"; import { SkinnedMesh } from "three";
import { get_model_renderer } from "../../rendering/ModelRenderer"; import { get_model_renderer } from "../../rendering/ModelRenderer";
@ -6,26 +6,26 @@ type Props = {
model?: SkinnedMesh; model?: SkinnedMesh;
}; };
export class RendererComponent extends React.Component<Props> { export class RendererComponent extends Component<Props> {
private renderer = get_model_renderer(); private renderer = get_model_renderer();
render() { render(): ReactNode {
return <div style={{ overflow: "hidden" }} ref={this.modifyDom} />; return <div style={{ overflow: "hidden" }} ref={this.modifyDom} />;
} }
componentDidMount() { componentDidMount(): void {
window.addEventListener("resize", this.onResize); window.addEventListener("resize", this.onResize);
} }
componentWillUnmount() { componentWillUnmount(): void {
window.removeEventListener("resize", this.onResize); window.removeEventListener("resize", this.onResize);
} }
componentWillReceiveProps({ model }: Props) { componentWillReceiveProps({ model }: Props): void {
this.renderer.set_model(model); this.renderer.set_model(model);
} }
shouldComponentUpdate() { shouldComponentUpdate(): boolean {
return false; return false;
} }

View File

@ -1,6 +1,6 @@
import { InputNumber } from "antd"; import { InputNumber } from "antd";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import React from "react"; import React, { ReactNode, Component } from "react";
import { QuestNpc, QuestObject, QuestEntity } from "../../domain"; import { QuestNpc, QuestObject, QuestEntity } from "../../domain";
import "./EntityInfoComponent.css"; import "./EntityInfoComponent.css";
@ -9,8 +9,8 @@ export type Props = {
}; };
@observer @observer
export class EntityInfoComponent extends React.Component<Props> { export class EntityInfoComponent extends Component<Props> {
render() { render(): ReactNode {
const entity = this.props.entity; const entity = this.props.entity;
if (entity) { if (entity) {
@ -105,12 +105,12 @@ export class EntityInfoComponent extends React.Component<Props> {
} }
@observer @observer
class CoordRow extends React.Component<{ class CoordRow extends Component<{
entity: QuestEntity; entity: QuestEntity;
position_type: "position" | "section_position"; position_type: "position" | "section_position";
coord: "x" | "y" | "z"; coord: "x" | "y" | "z";
}> { }> {
render() { render(): ReactNode {
const entity = this.props.entity; const entity = this.props.entity;
const value = entity[this.props.position_type][this.props.coord]; const value = entity[this.props.position_type][this.props.coord];
return ( return (

View File

@ -2,7 +2,7 @@ import { Button, Form, Icon, Input, Modal, Select, Upload } from "antd";
import { UploadChangeParam } from "antd/lib/upload"; import { UploadChangeParam } from "antd/lib/upload";
import { UploadFile } from "antd/lib/upload/interface"; import { UploadFile } from "antd/lib/upload/interface";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import React, { ChangeEvent } from "react"; import React, { ChangeEvent, ReactNode, Component } from "react";
import { quest_editor_store } from "../../stores/QuestEditorStore"; import { quest_editor_store } from "../../stores/QuestEditorStore";
import { EntityInfoComponent } from "./EntityInfoComponent"; import { EntityInfoComponent } from "./EntityInfoComponent";
import "./QuestEditorComponent.css"; import "./QuestEditorComponent.css";
@ -10,7 +10,7 @@ import { QuestInfoComponent } from "./QuestInfoComponent";
import { RendererComponent } from "./RendererComponent"; import { RendererComponent } from "./RendererComponent";
@observer @observer
export class QuestEditorComponent extends React.Component< export class QuestEditorComponent extends Component<
{}, {},
{ {
filename?: string; filename?: string;
@ -23,7 +23,7 @@ export class QuestEditorComponent extends React.Component<
save_dialog_filename: "Untitled", save_dialog_filename: "Untitled",
}; };
render() { render(): ReactNode {
const quest = quest_editor_store.current_quest; const quest = quest_editor_store.current_quest;
return ( return (
@ -73,12 +73,12 @@ export class QuestEditorComponent extends React.Component<
} }
@observer @observer
class Toolbar extends React.Component<{ onSaveAsClicked: (filename?: string) => void }> { class Toolbar extends Component<{ onSaveAsClicked: (filename?: string) => void }> {
state = { state = {
filename: undefined, filename: undefined,
}; };
render() { render(): ReactNode {
const quest = quest_editor_store.current_quest; const quest = quest_editor_store.current_quest;
const areas = quest && Array.from(quest.area_variants).map(a => a.area); const areas = quest && Array.from(quest.area_variants).map(a => a.area);
const area = quest_editor_store.current_area; const area = quest_editor_store.current_area;
@ -136,7 +136,7 @@ class SaveAsForm extends React.Component<{
on_ok: () => void; on_ok: () => void;
on_cancel: () => void; on_cancel: () => void;
}> { }> {
render() { render(): ReactNode {
return ( return (
<Modal <Modal
title={ title={

View File

@ -2,7 +2,7 @@ import React from "react";
import { NpcType, Quest } from "../../domain"; import { NpcType, Quest } from "../../domain";
import "./QuestInfoComponent.css"; import "./QuestInfoComponent.css";
export function QuestInfoComponent({ quest }: { quest?: Quest }) { export function QuestInfoComponent({ quest }: { quest?: Quest }): JSX.Element {
if (quest) { if (quest) {
const episode = quest.episode === 4 ? "IV" : quest.episode === 2 ? "II" : "I"; const episode = quest.episode === 4 ? "IV" : quest.episode === 2 ? "II" : "I";
const npc_counts = new Map<NpcType, number>(); const npc_counts = new Map<NpcType, number>();

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { ReactNode, Component } from "react";
import { Area, Quest } from "../../domain"; import { Area, Quest } from "../../domain";
import { get_quest_renderer } from "../../rendering/QuestRenderer"; import { get_quest_renderer } from "../../rendering/QuestRenderer";
@ -7,26 +7,26 @@ type Props = {
area?: Area; area?: Area;
}; };
export class RendererComponent extends React.Component<Props> { export class RendererComponent extends Component<Props> {
private renderer = get_quest_renderer(); private renderer = get_quest_renderer();
render() { render(): ReactNode {
return <div style={{ overflow: "hidden" }} ref={this.modifyDom} />; return <div style={{ overflow: "hidden" }} ref={this.modifyDom} />;
} }
componentDidMount() { componentDidMount(): void {
window.addEventListener("resize", this.onResize); window.addEventListener("resize", this.onResize);
} }
componentWillUnmount() { componentWillUnmount(): void {
window.removeEventListener("resize", this.onResize); window.removeEventListener("resize", this.onResize);
} }
componentWillReceiveProps({ quest, area }: Props) { componentWillReceiveProps({ quest, area }: Props): void {
this.renderer.set_quest_and_area(quest, area); this.renderer.set_quest_and_area(quest, area);
} }
shouldComponentUpdate() { shouldComponentUpdate(): boolean {
return false; return false;
} }

View File

@ -1277,6 +1277,11 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/eslint-visitor-keys@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
@ -1422,6 +1427,25 @@
requireindex "^1.2.0" requireindex "^1.2.0"
tsutils "^3.7.0" tsutils "^3.7.0"
"@typescript-eslint/eslint-plugin@^1.11.0":
version "1.11.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.11.0.tgz#870f752c520db04db6d3668af7479026a6f2fb9a"
integrity sha512-mXv9ccCou89C8/4avKHuPB2WkSZyY/XcTQUXd5LFZAcLw1I3mWYVjUu6eS9Ja0QkP/ClolbcW9tb3Ov/pMdcqw==
dependencies:
"@typescript-eslint/experimental-utils" "1.11.0"
eslint-utils "^1.3.1"
functional-red-black-tree "^1.0.1"
regexpp "^2.0.1"
tsutils "^3.7.0"
"@typescript-eslint/experimental-utils@1.11.0":
version "1.11.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-1.11.0.tgz#594abe47091cbeabac1d6f9cfed06d0ad99eb7e3"
integrity sha512-7LbfaqF6B8oa8cp/315zxKk8FFzosRzzhF8Kn/ZRsRsnpm7Qcu25cR/9RnAQo5utZ2KIWVgaALr+ZmcbG47ruw==
dependencies:
"@typescript-eslint/typescript-estree" "1.11.0"
eslint-scope "^4.0.0"
"@typescript-eslint/parser@1.6.0": "@typescript-eslint/parser@1.6.0":
version "1.6.0" version "1.6.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-1.6.0.tgz#f01189c8b90848e3b8e45a6cdad27870529d1804" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-1.6.0.tgz#f01189c8b90848e3b8e45a6cdad27870529d1804"
@ -1431,6 +1455,24 @@
eslint-scope "^4.0.0" eslint-scope "^4.0.0"
eslint-visitor-keys "^1.0.0" eslint-visitor-keys "^1.0.0"
"@typescript-eslint/parser@^1.11.0":
version "1.11.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-1.11.0.tgz#2f6d4f7e64eeb1e7c25b422f8df14d0c9e508e36"
integrity sha512-5xBExyXaxVyczrZvbRKEXvaTUFFq7gIM9BynXukXZE0zF3IQP/FxF4mPmmh3gJ9egafZFqByCpPTFm3dk4SY7Q==
dependencies:
"@types/eslint-visitor-keys" "^1.0.0"
"@typescript-eslint/experimental-utils" "1.11.0"
"@typescript-eslint/typescript-estree" "1.11.0"
eslint-visitor-keys "^1.0.0"
"@typescript-eslint/typescript-estree@1.11.0":
version "1.11.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.11.0.tgz#b7b5782aab22e4b3b6d84633652c9f41e62d37d5"
integrity sha512-fquUHF5tAx1sM2OeRCC7wVxFd1iMELWMGCzOSmJ3pLzArj9+kRixdlC4d5MncuzXpjEqc6045p3KwM0o/3FuUA==
dependencies:
lodash.unescape "4.0.1"
semver "5.5.0"
"@typescript-eslint/typescript-estree@1.6.0": "@typescript-eslint/typescript-estree@1.6.0":
version "1.6.0" version "1.6.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.6.0.tgz#6cf43a07fee08b8eb52e4513b428c8cdc9751ef0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.6.0.tgz#6cf43a07fee08b8eb52e4513b428c8cdc9751ef0"
@ -3819,6 +3861,13 @@ escodegen@^1.11.0, escodegen@^1.9.1:
optionalDependencies: optionalDependencies:
source-map "~0.6.1" source-map "~0.6.1"
eslint-config-prettier@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz#f429a53bde9fc7660e6353910fd996d6284d3c25"
integrity sha512-vDrcCFE3+2ixNT5H83g28bO/uYAwibJxerXPj+E7op4qzBCsAV36QfvdAyVOoNxKAH2Os/e01T/2x++V0LPukA==
dependencies:
get-stdin "^6.0.0"
eslint-config-react-app@^4.0.1: eslint-config-react-app@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-4.0.1.tgz#23fd0fd7ea89442ef1e733f66a7207674b23c8db" resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-4.0.1.tgz#23fd0fd7ea89442ef1e733f66a7207674b23c8db"
@ -3826,6 +3875,11 @@ eslint-config-react-app@^4.0.1:
dependencies: dependencies:
confusing-browser-globals "^1.0.7" confusing-browser-globals "^1.0.7"
eslint-config-react@^1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/eslint-config-react/-/eslint-config-react-1.1.7.tgz#a0918d0fc47d0e9bd161a47308021da85d2585b3"
integrity sha1-oJGND8R9DpvRYaRzCAIdqF0lhbM=
eslint-import-resolver-node@^0.3.2: eslint-import-resolver-node@^0.3.2:
version "0.3.2" version "0.3.2"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a"
@ -3890,6 +3944,13 @@ eslint-plugin-jsx-a11y@6.2.1:
has "^1.0.3" has "^1.0.3"
jsx-ast-utils "^2.0.1" jsx-ast-utils "^2.0.1"
eslint-plugin-prettier@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz#8695188f95daa93b0dc54b249347ca3b79c4686d"
integrity sha512-XWX2yVuwVNLOUhQijAkXz+rMPPoCr7WFiAl8ig6I7Xn+pPVhDhzg4DxHpmbeb0iqjO9UronEA3Tb09ChnFVHHA==
dependencies:
prettier-linter-helpers "^1.0.0"
eslint-plugin-react-hooks@^1.5.0: eslint-plugin-react-hooks@^1.5.0:
version "1.6.0" version "1.6.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.6.0.tgz#348efcda8fb426399ac7b8609607c7b4025a6f5f" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.6.0.tgz#348efcda8fb426399ac7b8609607c7b4025a6f5f"
@ -4196,6 +4257,11 @@ fast-deep-equal@^2.0.1:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
fast-diff@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
fast-glob@^2.0.2: fast-glob@^2.0.2:
version "2.2.7" version "2.2.7"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
@ -4545,6 +4611,11 @@ get-own-enumerable-property-symbols@^3.0.0:
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203"
integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg== integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==
get-stdin@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
get-stream@^4.0.0: get-stream@^4.0.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
@ -8169,6 +8240,13 @@ prelude-ls@~1.1.2:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
prettier-linter-helpers@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
dependencies:
fast-diff "^1.1.2"
prettier@1.18.2: prettier@1.18.2:
version "1.18.2" version "1.18.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea"