Skip to content

Commit

Permalink
Merge pull request #64 from project-fika/headless-3.9
Browse files Browse the repository at this point in the history
Headless
  • Loading branch information
Lacyway authored Jul 26, 2024
2 parents 625ed69 + 89f633e commit 5200d00
Show file tree
Hide file tree
Showing 26 changed files with 637 additions and 12 deletions.
9 changes: 9 additions & 0 deletions assets/configs/fika.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,14 @@
"enable": false,
"port": 6790,
"natIntroduceAmount": 1
},
"dedicated": {
"profiles": {
"amount": 0
},
"scripts": {
"generate": true,
"forceIp": ""
}
}
}
9 changes: 9 additions & 0 deletions src/Fika.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@ import { Overrider } from "./overrides/Overrider";
import { FikaServerTools } from "./utils/FikaServerTools";
import { FikaConfig } from "./utils/FikaConfig";
import { IFikaConfigNatPunchServer } from "./models/fika/config/IFikaConfigNatPunchServer";
import { FikaDedicatedProfileService } from "./services/dedicated/FikaDedicatedProfileService";
import { IFikaConfigDedicated } from "./models/fika/config/IFikaConfigDedicated";

@injectable()
export class Fika {
protected natPunchServerConfig: IFikaConfigNatPunchServer;
protected dedicatedConfig: IFikaConfigDedicated;

constructor(
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
@inject("Overrider") protected overrider: Overrider,
@inject("FikaServerTools") protected fikaServerTools: FikaServerTools,
@inject("FikaConfig") protected fikaConfig: FikaConfig,
@inject("FikaDedicatedProfileService") protected fikaDedicatedProfileService: FikaDedicatedProfileService,
) {
this.natPunchServerConfig = fikaConfig.getConfig().natPunchServer;
this.dedicatedConfig = fikaConfig.getConfig().dedicated;
}

public async preSptLoad(container: DependencyContainer): Promise<void> {
Expand All @@ -26,5 +31,9 @@ export class Fika {
if(this.natPunchServerConfig.enable) {
this.fikaServerTools.startService("NatPunchServer");
}

if(this.dedicatedConfig.profiles.amount > 0) {
this.fikaDedicatedProfileService.init();
}
}
}
2 changes: 1 addition & 1 deletion src/callbacks/FikaClientCallbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class FikaClientCallbacks {
}

/** Handle /fika/profile/download */
public handleProfileDownload(_url: string, info: any, sessionID: string): any {
public handleProfileDownload(_url: string, _info: any, sessionID: string): any {
return this.httpResponseUtil.noBody(this.fikaClientController.handleProfileDownload(sessionID));
}
}
19 changes: 19 additions & 0 deletions src/callbacks/FikaRaidCallbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { IFikaRaidServerIdRequestData } from "../models/fika/routes/raid/IFikaRa
import { IFikaRaidCreateRequestData } from "../models/fika/routes/raid/create/IFikaRaidCreateRequestData";
import { IFikaRaidJoinRequestData } from "../models/fika/routes/raid/join/IFikaRaidJoinRequestData";
import { IFikaRaidLeaveRequestData } from "../models/fika/routes/raid/leave/IFikaRaidLeaveRequestData";
import { IStartDedicatedResponse } from "../models/fika/routes/raid/dedicated/IStartDedicatedResponse";
import { IStartDedicatedRequest } from "../models/fika/routes/raid/dedicated/IStartDedicatedRequest";
import { IStatusDedicatedRequest } from "../models/fika/routes/raid/dedicated/IStatusDedicatedRequest";
import { IStatusDedicatedResponse } from "../models/fika/routes/raid/dedicated/IStatusDedicatedResponse";

@injectable()
export class FikaRaidCallbacks {
Expand Down Expand Up @@ -44,4 +48,19 @@ export class FikaRaidCallbacks {
public handleRaidGetSettings(_url: string, info: IFikaRaidServerIdRequestData, _sessionID: string): string {
return this.httpResponseUtil.noBody(this.fikaRaidController.handleRaidGetSettings(info));
}

/** Handle /fika/raid/dedicated/start */
public handleRaidStartDedicated(_url: string, info: IStartDedicatedRequest, sessionID: string): string {
return this.httpResponseUtil.noBody(this.fikaRaidController.handleRaidStartDedicated(sessionID, info));
}

/** Handle /fika/raid/dedicated/status */
public handleRaidStatusDedicated(_url: string, info: IStatusDedicatedRequest, sessionID: string): string {
return this.httpResponseUtil.noBody(this.fikaRaidController.handleRaidStatusDedicated(sessionID, info));
}

/** Handle /fika/raid/dedicated/getstatus */
public handleRaidGetStatusDedicated(_url: string, _info: any, _sessionID: string): string {
return this.httpResponseUtil.noBody(this.fikaRaidController.handleRaidGetStatusDedicated());
}
}
116 changes: 112 additions & 4 deletions src/controllers/FikaRaidController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,24 @@ import { IFikaRaidJoinRequestData } from "../models/fika/routes/raid/join/IFikaR
import { IFikaRaidJoinResponse } from "../models/fika/routes/raid/join/IFikaRaidJoinResponse";
import { IFikaRaidLeaveRequestData } from "../models/fika/routes/raid/leave/IFikaRaidLeaveRequestData";
import { FikaMatchService } from "../services/FikaMatchService";
import { FikaDedicatedRaidService } from "../services/dedicated/FikaDedicatedRaidService";
import { IStartDedicatedRequest } from "../models/fika/routes/raid/dedicated/IStartDedicatedRequest";
import { IStartDedicatedResponse } from "../models/fika/routes/raid/dedicated/IStartDedicatedResponse";
import { WebSocket } from "ws";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { IStatusDedicatedRequest } from "../models/fika/routes/raid/dedicated/IStatusDedicatedRequest";
import { IStatusDedicatedResponse } from "../models/fika/routes/raid/dedicated/IStatusDedicatedResponse";
import { IGetStatusDedicatedResponse } from "../models/fika/routes/raid/dedicated/IGetStatusDedicatedResponse";
import { FikaDedicatedRaidWebSocket } from "../websockets/FikaDedicatedRaidWebSocket";

@injectable()
export class FikaRaidController {
constructor(@inject("FikaMatchService") protected fikaMatchService: FikaMatchService) {
constructor(
@inject("FikaMatchService") protected fikaMatchService: FikaMatchService,
@inject("FikaDedicatedRaidService") protected fikaDedicatedRaidService: FikaDedicatedRaidService,
@inject("FikaDedicatedRaidWebSocket") protected fikaDedicatedRaidWebSocket: FikaDedicatedRaidWebSocket,
@inject("WinstonLogger") protected logger: ILogger,
) {
// empty
}

Expand All @@ -40,9 +54,9 @@ export class FikaRaidController {
expectedNumberOfPlayers: match.expectedNumberOfPlayers,
gameVersion: match.gameVersion,
fikaVersion: match.fikaVersion,
raidCode: match.raidCode
raidCode: match.raidCode,
};
}
}

/**
* Handle /fika/raid/leave
Expand Down Expand Up @@ -71,6 +85,7 @@ export class FikaRaidController {
ips: match.ips,
port: match.port,
natPunch: match.natPunch,
isDedicated: match.isDedicated,
};
}

Expand All @@ -86,7 +101,100 @@ export class FikaRaidController {

return {
metabolismDisabled: match.raidConfig.metabolismDisabled,
playersSpawnPlace: match.raidConfig.playersSpawnPlace
playersSpawnPlace: match.raidConfig.playersSpawnPlace,
};
}

/** Handle /fika/raid/dedicated/start */
handleRaidStartDedicated(sessionID: string, info: IStartDedicatedRequest): IStartDedicatedResponse {
if (!this.fikaDedicatedRaidService.isDedicatedClientAvailable()) {
return {
matchId: null,
error: "No dedicated clients available.",
};
}

if (sessionID in this.fikaDedicatedRaidService.dedicatedClients) {
return {
matchId: null,
error: "A dedicated client is trying to use a dedicated client?",
};
}

let dedicatedClient: string | undefined = undefined;
let dedicatedClientWs: WebSocket | undefined = undefined;

for (const dedicatedSessionId in this.fikaDedicatedRaidService.dedicatedClients) {
const dedicatedClientInfo = this.fikaDedicatedRaidService.dedicatedClients[dedicatedSessionId];

if (dedicatedClientInfo.state != "ready") {
continue;
}

dedicatedClientWs = this.fikaDedicatedRaidWebSocket.clientWebSockets[dedicatedSessionId];

if (!dedicatedClientWs) {
continue;
}

dedicatedClient = dedicatedSessionId;
break;
}

if (!dedicatedClient) {
return {
matchId: null,
error: "No dedicated clients available at this time",
};
}

this.fikaDedicatedRaidService.requestedSessions[dedicatedClient] = sessionID;

dedicatedClientWs.send(
JSON.stringify({
type: "fikaDedicatedStartRaid",
...info,
}),
);

this.logger.info(`Sent WS to ${dedicatedClient}`);

return {
// This really isn't required, I just want to make sure on the client
matchId: dedicatedClient,
error: null,
};
}

/** Handle /fika/raid/dedicated/status */
public handleRaidStatusDedicated(sessionId: string, info: IStatusDedicatedRequest): IStatusDedicatedResponse {
if (info.status == "ready" && !this.fikaDedicatedRaidService.isDedicatedClientAvailable()) {
if (this.fikaDedicatedRaidService.onDedicatedClientAvailable) {
this.fikaDedicatedRaidService.onDedicatedClientAvailable();
}
}

this.fikaDedicatedRaidService.dedicatedClients[sessionId] = {
state: info.status,
lastPing: Date.now(),
};

return {
sessionId: info.sessionId,
status: info.status,
};
}

/** Handle /fika/raid/dedicated/getstatus */
public handleRaidGetStatusDedicated(): IGetStatusDedicatedResponse {
if (!this.fikaDedicatedRaidService.isDedicatedClientAvailable()) {
return {
available: false
};
} else {
return {
available: true
};
}
}
}
5 changes: 3 additions & 2 deletions src/controllers/FikaSendItemController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,10 @@ export class FikaSendItemController {
for (const profile of Object.values(profiles)) {
//Uninitialized profiles can cause this to error out, skip these.
if (!profile.characters?.pmc?.Info)
{
continue;
}

if (profile.info.password === "fika-dedicated")
continue;

const nickname = profile.characters.pmc.Info.Nickname;
if (!(nickname in result) && nickname !== sender.characters.pmc.Info.Nickname) {
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/FikaUpdateController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class FikaUpdateController {
* @param request
*/
public handleSethost(request: IFikaUpdateSethostRequestData): void {
this.fikaMatchService.setMatchHost(request.serverId, request.ips, request.port, request.natPunch);
this.fikaMatchService.setMatchHost(request.serverId, request.ips, request.port, request.natPunch, request.isDedicated);
}

/**
Expand Down
20 changes: 19 additions & 1 deletion src/di/Container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { DatabaseServiceOverride } from "../overrides/services/FikaDatabaseServi
import { FikaMatchService } from "../services/FikaMatchService";
import { FikaFriendRequestsCacheService } from "../services/cache/FikaFriendRequestsCacheService";
import { FikaPlayerRelationsCacheService } from "../services/cache/FikaPlayerRelationsCacheService";
import { FikaDedicatedRaidService } from "../services/dedicated/FikaDedicatedRaidService";

import { FikaClientModHashesHelper } from "../helpers/FikaClientModHashesHelper";
import { FikaFriendRequestsHelper } from "../helpers/FikaFriendRequestsHelper";
Expand All @@ -40,11 +41,16 @@ import { FikaLocationStaticRouter } from "../routers/static/FikaLocationStaticRo
import { FikaRaidStaticRouter } from "../routers/static/FikaRaidStaticRouter";
import { FikaSendItemStaticRouter } from "../routers/static/FikaSendItemStaticRouter";
import { FikaUpdateStaticRouter } from "../routers/static/FikaUpdateStaticRouter";

import { FikaItemEventRouter } from "../routers/item_events/FikaItemEventRouter";

import { FikaDedicatedRaidWebSocket } from "../websockets/FikaDedicatedRaidWebSocket";
import { IWebSocketConnectionHandler } from "@spt/servers/ws/IWebSocketConnectionHandler";

import { Fika } from "../Fika";
import { FikaServerTools } from "../utils/FikaServerTools";
import { FikaDedicatedProfileService } from "../services/dedicated/FikaDedicatedProfileService";
import { BotControllerOverride } from "../overrides/controllers/BotController";


export class Container {
public static register(container: DependencyContainer): void {
Expand All @@ -62,6 +68,8 @@ export class Container {

Container.registerRouters(container);

Container.registerWebSockets(container);

Container.registerListTypes(container);

container.register<Fika>("Fika", Fika, { lifecycle: Lifecycle.Singleton });
Expand All @@ -77,6 +85,7 @@ export class Container {
container.registerType("Overrides", "LocalesOverride");
container.registerType("Overrides", "AchievementControllerOverride");
container.registerType("Overrides", "DatabaseServiceOverride");
container.registerType("Overrides", "BotControllerOverride");

container.registerType("StaticRoutes", "FikaClientStaticRouter");
container.registerType("StaticRoutes", "FikaLocationStaticRouter");
Expand All @@ -85,6 +94,7 @@ export class Container {
container.registerType("StaticRoutes", "FikaUpdateStaticRouter");

container.registerType("IERouters", "FikaItemEventRouter");
container.registerType("WebSocketConnectionHandler", "FikaDedicatedRaidWebSocket");
}

private static registerUtils(container: DependencyContainer): void {
Expand All @@ -100,6 +110,7 @@ export class Container {
container.register<HttpRouterOverride>("HttpRouterOverride", HttpRouterOverride, { lifecycle: Lifecycle.Singleton });
container.register<LauncherBackgroundOverride>("LauncherBackgroundOverride", LauncherBackgroundOverride, { lifecycle: Lifecycle.Singleton });
container.register<LocalesOverride>("LocalesOverride", LocalesOverride, { lifecycle: Lifecycle.Singleton });
container.register<BotControllerOverride>("BotControllerOverride", BotControllerOverride, { lifecycle: Lifecycle.Singleton });
container.register<Overrider>("Overrider", Overrider, { lifecycle: Lifecycle.Singleton });
container.register<AchievementControllerOverride>("AchievementControllerOverride", AchievementControllerOverride, { lifecycle: Lifecycle.Singleton });
container.register<DatabaseServiceOverride>("DatabaseServiceOverride", DatabaseServiceOverride, { lifecycle: Lifecycle.Singleton });
Expand All @@ -109,6 +120,8 @@ export class Container {
container.register<FikaMatchService>("FikaMatchService", FikaMatchService, { lifecycle: Lifecycle.Singleton });
container.register<FikaFriendRequestsCacheService>("FikaFriendRequestsCacheService", FikaFriendRequestsCacheService, { lifecycle: Lifecycle.Singleton });
container.register<FikaPlayerRelationsCacheService>("FikaPlayerRelationsCacheService", FikaPlayerRelationsCacheService, { lifecycle: Lifecycle.Singleton });
container.register<FikaDedicatedRaidService>("FikaDedicatedRaidService", FikaDedicatedRaidService, { lifecycle: Lifecycle.Singleton });
container.register<FikaDedicatedProfileService>("FikaDedicatedProfileService", FikaDedicatedProfileService, { lifecycle: Lifecycle.Singleton });
}

private static registerHelpers(container: DependencyContainer): void {
Expand Down Expand Up @@ -143,4 +156,9 @@ export class Container {
container.register<FikaUpdateStaticRouter>("FikaUpdateStaticRouter", { useClass: FikaUpdateStaticRouter });
container.register<FikaItemEventRouter>("FikaItemEventRouter", { useClass: FikaItemEventRouter });
}

private static registerWebSockets(container: DependencyContainer): void {
container.register<FikaDedicatedRaidWebSocket>("FikaDedicatedRaidWebSocket", FikaDedicatedRaidWebSocket, { lifecycle: Lifecycle.Singleton });
container.register<IWebSocketConnectionHandler>("FikaDedicatedRaidWebSocket", FikaDedicatedRaidWebSocket, { lifecycle: Lifecycle.Singleton });
}
}
1 change: 1 addition & 0 deletions src/models/fika/IFikaMatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ export interface IFikaMatch {
time: FikaTime;
raidCode: string;
natPunch: boolean;
isDedicated: boolean;
}
2 changes: 2 additions & 0 deletions src/models/fika/config/IFikaConfig.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { IFikaConfigClient } from "./IFikaConfigClient";
import { IFikaConfigServer } from "./IFikaConfigServer";
import { IFikaConfigNatPunchServer } from "./IFikaConfigNatPunchServer";
import { IFikaConfigDedicated } from "./IFikaConfigDedicated";

export interface IFikaConfig {
client: IFikaConfigClient;
server: IFikaConfigServer;
natPunchServer: IFikaConfigNatPunchServer;
dedicated: IFikaConfigDedicated;
}
9 changes: 9 additions & 0 deletions src/models/fika/config/IFikaConfigDedicated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface IFikaConfigDedicated {
profiles: {
amount: number;
}
scripts: {
generate: boolean;
forceIp: string;
}
}
4 changes: 4 additions & 0 deletions src/models/fika/dedicated/IDedicatedClientInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IDedicatedClientInfo {
state: string;
lastPing: number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface IGetStatusDedicatedResponse {
available: boolean
}
16 changes: 16 additions & 0 deletions src/models/fika/routes/raid/dedicated/IStartDedicatedRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { BotSettings, TimeAndWeatherSettings, WavesSettings } from "@spt-aki/models/eft/match/IRaidSettings";
import { DateTime } from "@spt-aki/models/enums/DateTime";
import { PlayersSpawnPlace } from "@spt-aki/models/enums/PlayersSpawnPlace";
import { SideType } from "@spt-aki/models/enums/SideType";

export interface IStartDedicatedRequest {
expectedNumberOfPlayers: number;
time: DateTime;
locationId: string;
spawnPlace: PlayersSpawnPlace;
metabolismDisabled: boolean;
timeAndWeatherSettings: TimeAndWeatherSettings;
botSettings: BotSettings;
wavesSettings: WavesSettings;
side: SideType;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IStartDedicatedResponse {
matchId: string;
error: string;
}
Loading

0 comments on commit 5200d00

Please sign in to comment.