Skip to content

Commit

Permalink
hideexp
Browse files Browse the repository at this point in the history
  • Loading branch information
Pospelove committed Dec 8, 2023
1 parent 729ec27 commit 9c43a5d
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 107 deletions.
4 changes: 3 additions & 1 deletion skymp5-client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { DeathService } from "./services/services/deathService";
import { ContainersService } from "./services/services/containersService";
import { NetworkingService } from "./services/services/networkingService";
import { RemoteServer } from "./services/services/remoteServer";
import { SpSnippetService } from "./services/services/spSnippetService";

browser.main();

Expand Down Expand Up @@ -112,7 +113,8 @@ const main = () => {
new DeathService(sp, controller),
new ContainersService(sp, controller),
new NetworkingService(sp, controller),
new RemoteServer(sp, controller)
new RemoteServer(sp, controller),
new SpSnippetService(sp, controller)
];
SpApiInteractor.setup(listeners);
listeners.forEach(listener => SpApiInteractor.registerListenerForLookup(listener.constructor.name, listener));
Expand Down
9 changes: 6 additions & 3 deletions skymp5-client/src/services/messages/spSnippetMessage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Snippet } from "../../spSnippet";

export type SpSnippetMessage = {
type: "spSnippet";
} & Snippet;
class: string;
function: string;
arguments: any[];
selfId: number;
snippetIdx: number;
};
42 changes: 8 additions & 34 deletions skymp5-client/src/services/services/remoteServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import * as updateOwner from '../../gamemodeApi/updateOwner';
import * as messages from '../../messages';

/* eslint-disable @typescript-eslint/no-empty-function */
import * as networking from './networkingService';
import * as spSnippet from '../../spSnippet';
import { ObjectReferenceEx } from '../../extensions/objectReferenceEx';
import { AuthGameData } from '../../features/authModel';
import { IdManager } from '../../lib/idManager';
Expand All @@ -32,12 +30,6 @@ import { Inventory, applyInventory } from '../../sync/inventory';
import { Movement } from '../../sync/movement';
import { learnSpells, removeAllSpells } from '../../sync/spell';
import { ModelApplyUtils } from '../../view/modelApplyUtils';
import {
getObjectReference,
getViewFromStorage,
localIdToRemoteId,
remoteIdToLocalId,
} from '../../view/worldViewMisc';
import { FormModel, WorldModel } from '../../modelSource/model';
import { ModelSource } from '../../modelSource/modelSource';
import { SpApiInteractor } from '../spApiInteractor';
Expand All @@ -48,7 +40,6 @@ import { UpdateAnimationMessage } from '../messages/updateAnimationMessage';
import { UpdateEquipmentMessage } from '../messages/updateEquipmentMessage';
import { CustomPacketMessage } from '../messages/customPacketMessage';
import { CustomEventMessage } from '../messages/customEventMessage';
import { FinishSpSnippetMessage } from '../messages/finishSpSnippetMessage';
import { RagdollService } from './ragdollService';
import { UpdateAppearanceMessage } from '../messages/updateAppearanceMessage';
import { TeleportMessage } from '../messages/teleportMessage';
Expand All @@ -64,13 +55,20 @@ import { ConnectionMessage } from '../events/connectionMessage';
import { SetInventoryMessage } from '../messages/setInventoryMessage';
import { CreateActorMessage } from '../messages/createActorMessage';
import { UpdateGamemodeDataMessage } from '../messages/updateGameModeDataMessage';
import { SpSnippetMessage } from '../messages/spSnippetMessage';
import { CustomPacketMessage2 } from '../messages/customPacketMessage2';
import { DestroyActorMessage } from '../messages/destroyActorMessage';
import { SetRaceMenuOpenMessage } from '../messages/setRaceMenuOpenMessage';
import { UpdatePropertyMessage } from '../messages/updatePropertyMessage';
import { TeleportMessage2 } from '../messages/teleportMessage2';

// TODO: refactor worldViewMisc into service
import {
getObjectReference,
getViewFromStorage,
localIdToRemoteId,
remoteIdToLocalId,
} from '../../view/worldViewMisc';

const onceLoad = (
refrId: number,
callback: (refr: ObjectReference) => void,
Expand Down Expand Up @@ -243,7 +241,6 @@ export class RemoteServer extends ClientListener implements ModelSource {
this.controller.emitter.on("customPacketMessage2", (e) => this.onCustomPacketMessage2(e));
this.controller.emitter.on("destroyActorMessage", (e) => this.onDestroyActorMessage(e));
this.controller.emitter.on("setRaceMenuOpenMessage", (e) => this.onSetRaceMenuOpenMessage(e));
this.controller.emitter.on("spSnippetMessage", (e) => this.onSpSnippetMessage(e));
this.controller.emitter.on("updateGamemodeDataMessage", (e) => this.onUpdateGamemodeDataMessage(e));
this.controller.emitter.on("updatePropertyMessage", (e) => this.onUpdatePropertyMessage(e));
this.controller.emitter.on("deathStateContainerMessage", (e) => this.onDeathStateContainerMessage(e));
Expand Down Expand Up @@ -811,29 +808,6 @@ export class RemoteServer extends ClientListener implements ModelSource {
}
}

private onSpSnippetMessage(event: ConnectionMessage<SpSnippetMessage>): void {
const msg = event.message;

once('update', async () => {
spSnippet
.run(msg)
.then((res) => {
if (res === undefined) res = null;
const message: FinishSpSnippetMessage = {
t: messages.MsgType.FinishSpSnippet,
returnValue: res,
snippetIdx: msg.snippetIdx,
}

SpApiInteractor.makeController().emitter.emit("sendMessage", {
message: message,
reliability: "reliable"
});
})
.catch((e) => printConsole('!!! SpSnippet ' + msg.class + ' ' + msg.function + ' failed', e));
});
}

private updateGamemodeUpdateFunctions(
storageVar: string,
functionSources: Record<string, string>,
Expand Down
128 changes: 128 additions & 0 deletions skymp5-client/src/services/services/spSnippetService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { MsgType } from "../../messages";
import { ConnectionMessage } from "../events/connectionMessage";
import { FinishSpSnippetMessage } from "../messages/finishSpSnippetMessage";
import { SpSnippetMessage } from "../messages/spSnippetMessage";
import { ClientListener, CombinedController, Sp } from "./clientListener";

// TODO: refactor worldViewMisc into service
import { remoteIdToLocalId } from '../../view/worldViewMisc';

export class SpSnippetService extends ClientListener {
constructor(private sp: Sp, private controller: CombinedController) {
super();
this.controller.emitter.on("spSnippetMessage", (e) => this.onSpSnippetMessage(e));
this.spAny = sp as Record<string, any>;
}

private onSpSnippetMessage(event: ConnectionMessage<SpSnippetMessage>): void {
const msg = event.message;

this.controller.once('update', async () => {
this.run(msg)
.then((res) => {
if (res === undefined) {
res = null;
}

const message: FinishSpSnippetMessage = {
t: MsgType.FinishSpSnippet,
returnValue: res,
snippetIdx: msg.snippetIdx,
}

this.controller.emitter.emit("sendMessage", {
message: message,
reliability: "reliable"
});
})
.catch((e) => this.logError('SpSnippet ' + msg.class + ' ' + msg.function + ' failed ' + e));
});
}

private async run(snippet: SpSnippetMessage): Promise<any> {
if (snippet.class === "SkympHacks") {
if (snippet.function === "AddItem" || snippet.function === "RemoveItem") {
const form = this.sp.Form.from(this.deserializeArg(snippet.arguments[0]));
if (form === null) {
return this.logError("Unable to find form with id " + snippet.arguments[0].formId.toString(16));
}

const sign = snippet.function === "AddItem" ? "+" : "-";
const count = snippet.arguments[1];

let soundId = 0x334ab;
if (form.getFormID() !== 0xf) {
soundId = 0x14115;
}

const sound = this.sp.Sound.from(this.sp.Game.getFormEx(soundId));
if (sound !== null) {
const name = form.getName();
if (name.trim() === "") {
this.logTrace("Sound will not be played because item has no name")
}
else {
sound.play(this.sp.Game.getPlayer());
}
}
else {
this.logError("Unable to find sound with id " + soundId.toString(16));
}

if (count <= 0) {
this.logError("Positive count expected, got " + count.toString());
}
else {
const name = form.getName();
if (name.trim() === "") {
this.logTrace("Notification will not be shown because item has no name")
}
else {
this.sp.Debug.notification(sign + " " + name + " (" + count + ")");
}
this.logTrace(sign + " " + name + " (" + count + ")");
}
} else throw new Error("Unknown SkympHack - " + snippet.function);
return;
}
return snippet.selfId ? this.runMethod(snippet) : this.runStatic(snippet);
};

private deserializeArg(arg: any) {
if (typeof arg === "object") {
const formId = remoteIdToLocalId(arg.formId);
const form = this.sp.Game.getFormEx(formId);
const gameObject = this.spAny[arg.type].from(form);
return gameObject;
}
return arg;
};

private async runMethod(snippet: SpSnippetMessage): Promise<any> {
const selfId = remoteIdToLocalId(snippet.selfId);
const self = this.sp.Game.getFormEx(selfId);
if (!self)
throw new Error(
`Unable to find form with id ${selfId.toString(16)}`
);
const selfCasted = this.spAny[snippet.class].from(self);
if (!selfCasted)
throw new Error(
`Form ${selfId.toString(16)} is not instance of ${snippet.class}, form type is ${self.getType()}`
);
const f = selfCasted[snippet.function];
return await f.apply(
selfCasted,
snippet.arguments.map((arg) => this.deserializeArg(arg))
);
};

private async runStatic(snippet: SpSnippetMessage): Promise<any> {
const papyrusClass = this.spAny[snippet.class];
return await papyrusClass[snippet.function](
...snippet.arguments.map((arg) => this.deserializeArg(arg))
);
};

private spAny: Record<string, any>;
};
69 changes: 0 additions & 69 deletions skymp5-client/src/spSnippet.ts

This file was deleted.

0 comments on commit 9c43a5d

Please sign in to comment.