Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: add new message types and handlers, refactor client and server code #2264

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 136 additions & 24 deletions misc/git-hooks/clang-format-hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ const simpleGit = require("simple-git");
const fs = require("fs");
const path = require("path");

const extensions = [".cpp", ".h", ".hpp", ".cxx", ".cc"];

/**
* Utility: Recursively find all files in a directory.
*/
const findFiles = (dir, fileList = []) => {
const files = fs.readdirSync(dir);
files.forEach((file) => {
Expand All @@ -18,48 +19,159 @@ const findFiles = (dir, fileList = []) => {
return fileList;
};

const formatFiles = (files) => {
const filesToFormat = files.filter((file) =>
extensions.some((ext) => file.endsWith(ext))
/**
* Check Registry: Define custom checks here.
* Each check should implement `lint` and `fix` methods.
*/
const checks = [
{
name: "Clang Format",
appliesTo: (file) => [".cpp", ".h", ".hpp", ".cxx", ".cc"].some((ext) => file.endsWith(ext)),
lint: (file) => {
// Example: Use clang-format to lint
const lintCommand = `clang-format --dry-run --Werror ${file}`;
try {
execSync(lintCommand, { stdio: "inherit" });
console.log(`[PASS] ${file}`);
return true;
} catch (error) {
console.error(`[FAIL] ${file}`);
return false;
}
},
fix: (file) => {
// Use clang-format to autofix
const fixCommand = `clang-format -i ${file}`;
execSync(fixCommand, { stdio: "inherit" });
console.log(`[FIXED] ${file}`);
},
},
{
name: "Header/TypeScript Pair Check",
// Applies to files that reside in the specified parent directories
appliesTo: (file) => {
const serverDir = "skymp5-server/cpp/messages";
const clientDir = "skymp5-client/src/services/messages";
const validDirs = [serverDir, clientDir];

// Check if the file belongs to one of the valid parent directories
return validDirs.some((dir) => file.includes(path.sep + dir + path.sep))
&& !file.endsWith(path.sep + "anyMessage.ts")
&& !file.endsWith(path.sep + "refrIdMessageBase.ts")
&& !file.endsWith(path.sep + "MessageBase.h")
&& !file.endsWith(path.sep + "MessageSerializerFactory.cpp")
&& !file.endsWith(path.sep + "MessageSerializerFactory.h")
&& !file.endsWith(path.sep + "Messages.h")
&& !file.endsWith(path.sep + "MinPacketId.h")
&& !file.endsWith(path.sep + "MsgType.h");
},
lint: (file) => {
const serverDir = "skymp5-server/cpp/messages";
const clientDir = "skymp5-client/src/services/messages";
const ext = path.extname(file);
const baseName = path.basename(file, ext);

// Determine the pair file's extension and directory
const pairExt = ext === ".h" ? ".ts" : ".h";
const pairDir = file.includes(path.sep + serverDir + path.sep)
? clientDir
: serverDir;

const pairFiles = fs.readdirSync(pairDir);

// Find a case-insensitive match
const pairFile = pairFiles.find(
(candidate) => candidate.toLowerCase() === `${baseName}${pairExt}`.toLowerCase()
);

if (!pairFile) {
console.error(`[FAIL] Pair file not found for ${file}: ${pairFile}`);
return false;
} else {
console.log(`[PASS] Pair file found for ${file}: ${pairFile}`);
return true;
}
},
fix() { }
}
];

/**
* Core: Run checks (lint or fix) on given files.
*/
const runChecks = (files, { lintOnly = false }) => {
const filesToCheck = files.filter((file) =>
checks.some((check) => check.appliesTo(file))
);

if (filesToFormat.length === 0) {
console.log("No files to format.");
if (filesToCheck.length === 0) {
console.log("No matching files found for checks.");
return;
}

console.log("Formatting files:");
filesToFormat.forEach((file) => {
console.log(` - ${file}`);
execSync(`clang-format -i ${file}`, { stdio: "inherit" });
console.log(`${lintOnly ? "Linting" : "Fixing"} files:`);

let fail = false;

filesToCheck.forEach((file) => {
checks.forEach((check) => {
if (check.appliesTo(file)) {
try {
const res = lintOnly ? check.lint(file) : check.fix(file);
if (res === false) {
fail = true;
}
} catch (err) {
if (lintOnly) {
console.error(`Error in ${check.name}:`, err);
process.exit(1);
}
else {
throw err;
}
}
}
});
});

if (fail) {
process.exit(1);
}

console.log(`${lintOnly ? "Linting" : "Fixing"} completed.`);
};

/**
* CLI Entry Point
*/
(async () => {
const args = process.argv.slice(2);
const lintOnly = args.includes("--lint");
const allFiles = args.includes("--all");

try {
if (args.includes("--all")) {
console.log("Formatting all files in the repository...");
const allFiles = findFiles(process.cwd());
formatFiles(allFiles);
let files = [];

if (allFiles) {
console.log("Processing all files in the repository...");
files = findFiles(process.cwd());
} else {
console.log("Formatting staged files...");
console.log("Processing staged files...");
const git = simpleGit();
const changedFiles = await git.diff(["--name-only", "--cached"]);

const filesToFormat = changedFiles
files = changedFiles
.split("\n")
.filter((file) => file.trim() !== "")
.filter((file) => fs.existsSync(file)); // Do not try validate deleted files
formatFiles(filesToFormat);

filesToFormat.forEach((file) => execSync(`git add ${file}`));
.filter((file) => fs.existsSync(file)); // Exclude deleted files
}

console.log("Formatting completed.");
runChecks(files, { lintOnly });

if (!lintOnly && !allFiles) {
files.forEach((file) => execSync(`git add ${file}`));
}
} catch (err) {
console.error("Error during formatting:", err.message);
console.error("Error during processing:", err.message);
process.exit(1);
}
})();
11 changes: 11 additions & 0 deletions skymp5-client/src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,15 @@ export enum MsgType {
PlayerBowShot = 22,
SpellCast = 23,
UpdateAnimVariables = 24,

// ex-strings
DestroyActor = 25,
HostStart = 26,
HostStop = 27,
SetInventory = 28,
SetRaceMenuOpen = 29,
SpSnippet = 30,
Teleport2 = 31,
UpdateGamemodeData = 32,
CreateActor = 33
}
2 changes: 1 addition & 1 deletion skymp5-client/src/services/events/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { HostStartMessage } from "../messages/hostStartMessage";
import { HostStopMessage } from "../messages/hostStopMessage";
import { SetInventoryMessage } from "../messages/setInventoryMessage";
import { OpenContainerMessage } from "../messages/openContainerMessage";
import { ChangeValuesMessage } from "../messages/changeValues";
import { ChangeValuesMessage } from "../messages/changeValuesMessage";
import { CreateActorMessage } from "../messages/createActorMessage";
import { CustomPacketMessage2 } from "../messages/customPacketMessage2";
import { DestroyActorMessage } from "../messages/destroyActorMessage";
Expand Down
4 changes: 1 addition & 3 deletions skymp5-client/src/services/messages/anyMessage.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@

import { ActivateMessage } from "./activateMessage";
import { ChangeValuesMessage } from "./changeValues";
import { ChangeValuesMessage } from "./changeValuesMessage";
import { ConsoleCommandMessage } from "./consoleCommandMessage";
import { CraftItemMessage } from "./craftItemMessage";
import { CreateActorMessage } from "./createActorMessage";
import { CustomEventMessage } from "./customEventMessage";
import { CustomPacketMessage } from "./customPacketMessage";
import { CustomPacketMessage2 } from "./customPacketMessage2";
import { DeathStateContainerMessage } from "./deathStateContainerMessage";
import { DestroyActorMessage } from "./destroyActorMessage";
import { DropItemMessage } from "./dropItemMessage";
Expand Down Expand Up @@ -59,7 +58,6 @@ export type AnyMessage = ActivateMessage
| HostStopMessage
| SetInventoryMessage
| CreateActorMessage
| CustomPacketMessage2
| DestroyActorMessage
| SetRaceMenuOpenMessage
| SpSnippetMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ export interface ConsoleCommandMessage {

interface ConsoleCommandMessageData {
commandName: string;
args: unknown[];
args: Array<number | string>;
}
5 changes: 3 additions & 2 deletions skymp5-client/src/services/messages/createActorMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { Equipment } from "../../sync/equipment";
import { Inventory } from "../../sync/inventory";
import { Transform } from "../../sync/movement";
import { Animation } from "../../sync/animation";
import { MsgType } from "src/messages";

export interface CreateActorMessage extends CreateActorMessageMainProps {
type: "createActor";
t: MsgType.CreateActor,
idx: number;
baseRecordType: "DOOR" | undefined; // see PartOne.cpp
baseRecordType?: "DOOR"; // see PartOne.cpp
transform: Transform;
isMe: boolean;
props?: CreateActorMessageAdditionalProps;
Expand Down
2 changes: 1 addition & 1 deletion skymp5-client/src/services/messages/customEventMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { MsgType } from "../../messages";

export interface CustomEventMessage {
t: MsgType.CustomEvent,
args: unknown[],
argsJsonDumps: string[],
eventName: string
}
7 changes: 1 addition & 6 deletions skymp5-client/src/services/messages/customPacketMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,5 @@ import { MsgType } from "../../messages";

export interface CustomPacketMessage {
t: MsgType.CustomPacket,
content: CustomPacketMessageContent
}

interface CustomPacketMessageContent {
customPacketType: string,
gameData: Record<string, unknown>
contentJsonDump: string
}
4 changes: 0 additions & 4 deletions skymp5-client/src/services/messages/customPacketMessage2.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MsgType } from "../../messages";
import { ChangeValuesMessage } from "./changeValues";
import { ChangeValuesMessage } from "./changeValuesMessage";
import { TeleportMessage } from "./teleportMessage";
import { UpdatePropertyMessage } from "./updatePropertyMessage";

Expand Down
4 changes: 3 additions & 1 deletion skymp5-client/src/services/messages/destroyActorMessage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { MsgType } from "../../messages";

export interface DestroyActorMessage {
type: "destroyActor";
t: MsgType.DestroyActor,
idx: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { MsgType } from "../../messages"

export interface FinishSpSnippetMessage {
t: MsgType.FinishSpSnippet,
returnValue: unknown, // TODO: improve type: there should union of possible Papyrus values
returnValue?: boolean | number | string;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The returnValue in FinishSpSnippetMessage is defined as boolean | number | string in TypeScript, but in C++ it's defined as std::optional<std::variant<bool, double, std::string>>. The use of double in C++ might lead to precision issues if the number is an integer in TypeScript. Consider aligning the types to avoid potential issues.

snippetIdx: number,
}
4 changes: 3 additions & 1 deletion skymp5-client/src/services/messages/hostStartMessage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { MsgType } from "../../messages";

export interface HostStartMessage {
type: "hostStart";
t: MsgType.HostStart;
target: number;
}
4 changes: 3 additions & 1 deletion skymp5-client/src/services/messages/hostStopMessage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { MsgType } from "../../messages";

export interface HostStopMessage {
type: "hostStop";
t: MsgType.HostStop;
target: number;
}
1 change: 1 addition & 0 deletions skymp5-client/src/services/messages/putItemMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { MsgType } from "../../messages";

export interface PutItemMessage extends Extra {
t: MsgType.PutItem,
baseId: number;
count: number;
target: number;
};
3 changes: 2 additions & 1 deletion skymp5-client/src/services/messages/setInventoryMessage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Inventory } from "skyrimPlatform";
import { MsgType } from "../../messages";

export interface SetInventoryMessage {
type: "setInventory";
t: MsgType.SetInventory;
inventory: Inventory;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { MsgType } from "../../messages";

export interface SetRaceMenuOpenMessage {
type: "setRaceMenuOpen";
t: MsgType.SetRaceMenuOpen;
open: boolean;
}
4 changes: 3 additions & 1 deletion skymp5-client/src/services/messages/spSnippetMessage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { MsgType } from "../../messages";

export interface SpSnippetMessage {
type: "spSnippet";
t: MsgType.SpSnippet;
class: string;
function: string;
arguments: any[];
Expand Down
8 changes: 5 additions & 3 deletions skymp5-client/src/services/messages/spellCastMessage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { MsgType } from "../../messages";
// @ts-expect-error (TODO: Remove in 2.10.0)
import { ActorAnimationVariables } from 'skyrimPlatform';

export interface SpellCastMsgData {
caster: number
Expand All @@ -11,7 +9,11 @@ export interface SpellCastMsgData {
castingSource: number
aimAngle: number,
aimHeading: number,
actorAnimationVariables: ActorAnimationVariables
actorAnimationVariables: {
booleans: number[]
floats: number[]
integers: number[]
}
}

export interface SpellCastMessage {
Expand Down
1 change: 1 addition & 0 deletions skymp5-client/src/services/messages/takeItemMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { MsgType } from "../../messages";

export interface TakeItemMessage extends Extra {
t: MsgType.TakeItem,
baseId: number;
count: number;
target: number;
};
4 changes: 3 additions & 1 deletion skymp5-client/src/services/messages/teleportMessage2.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { MsgType } from "../../messages";

export interface TeleportMessage2 {
type: "teleport";
t: MsgType.Teleport2;
pos: number[];
rot: number[];
worldOrCell: number;
Expand Down
Loading
Loading