Still figuring out initial matchmaking hang (FROSTBITE). Lots of other changes.

- Added missing room images
- Removed internal rooms and disallow cloning some rooms
- License fixes
- Switched target to 20200306
- Socket header fixes
- Sockets are closed upon shutdown
    * Sockets persist after being destroyed, fix
- Config changes for 20200306
- Settings initialized
- Name generation words cannot be longer than 9 characters
- Dorm generation changes and fixes
- Added some settings keys
- Matchmaking additions
    * Instances are not yet updated to be or not to be in-progress
- Instance fixes and logging
- Image operation fixes
- DisplayName route start
- Challenge route start
- Default Amplitude key (i can see althe Amplitude requests are ignored
- Rate limiting ease
- GameConfigs properly queried and sent
- Many 'bulk' endpoints were added in or around 20200306
- Objective routes started
- DormRoom redirection in v2/name
- Client doesn't care if it gets 200 when setting prefs
- Balance/storefronts started
- Matchmaking goto/room timer and fixes
- Selfhosted Photon addition on the client sends matchmaking /photonregionpings, ignore since Photon is only one server in one region
This commit is contained in:
2025-04-13 01:06:23 -04:00
parent 1cfd0426dd
commit 3b6d905180
89 changed files with 990 additions and 421 deletions

View File

@@ -622,7 +622,7 @@ copy of the Program in return for a fee.
LICENSE TEMPLATE LICENSE TEMPLATE
Galvanic Corrosion - Rec Room custom server for communities. Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -3,7 +3,7 @@
delectable yum yum delectable yum yum
Rec Room custom server for communities. Fast runtime and easy setup.<br>Built Rec Room custom server for communities. Fast runtime and easy setup.<br>Built
for Rec Room build 526 (Timestamp: 637098805133024772, Version: 20191120) for Rec Room build 1063 (Timestamp: 637191339113673856, Version: 20200306)
<img src="galv4.jpg" alt="drawing" width="200"/> <img src="galv4.jpg" alt="drawing" width="200"/>

BIN
res/img/Bowling.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

BIN
res/img/Crescendo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
res/img/Lake.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

BIN
res/img/LaserTag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
res/img/MakerRoom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
res/img/StuntRunner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -131,11 +131,11 @@ export function genericResponse(
}; };
} }
type RecNetResponse = { type RecNetResponse = {
Success: boolean; success: boolean;
Message: string; error?: string;
}; };
export function RecNetResponse(success: boolean, message: string) { export function RecNetResponse(success: boolean, message?: string) {
const msg: RecNetResponse = { Success: success, Message: message }; const msg: RecNetResponse = { success: success, error: message };
return (_rq: express.Request, rs: express.Response) => { return (_rq: express.Request, rs: express.Response) => {
rs.json(msg); rs.json(msg);
}; };
@@ -190,7 +190,7 @@ export class RateLimiter {
* @param interval In seconds: rate at which hit counts will be cleared * @param interval In seconds: rate at which hit counts will be cleared
* @param limit Number of hits (inclusive) before requests are blocked * @param limit Number of hits (inclusive) before requests are blocked
*/ */
constructor(interval: number, limit: number) { constructor(interval: number = 20, limit: number = 2) {
this.#hitLimit = limit; this.#hitLimit = limit;
this.#intervalId = setInterval(() => { this.#intervalId = setInterval(() => {
@@ -224,6 +224,11 @@ export class RateLimiter {
nxt: express.NextFunction, nxt: express.NextFunction,
) => { ) => {
const address = getSrcIpDefault(rq); const address = getSrcIpDefault(rq);
if (address == '127.0.0.1' || address == '::1') {
nxt();
return;
}
this.#addressIncrement(address); this.#addressIncrement(address);
const hits = this.#getAddressHits(address); const hits = this.#getAddressHits(address);
@@ -339,7 +344,7 @@ export function AuthenticationType(type: AuthType) {
} }
export function LoginLock(rq: express.Request<NoBody, NoBody, { LoginLock: string }>, rs: express.Response, nxt: express.NextFunction) { export function LoginLock(rq: express.Request<NoBody, NoBody, { LoginLock: string }>, rs: express.Response, nxt: express.NextFunction) {
log.d(`LoginLock for ${rs.locals.profile.getId()}: ${rq.body.LoginLock}`); //log.d(`LoginLock for ${rs.locals.profile.getId()}: ${rq.body.LoginLock}`);
const matches = Matchmaking.lockMatches(rs.locals.profile, rq.body.LoginLock); const matches = Matchmaking.lockMatches(rs.locals.profile, rq.body.LoginLock);
if (matches == null) { if (matches == null) {
rs.json(genericResponseFormat(true, "Login Lock failure")); rs.json(genericResponseFormat(true, "Login Lock failure"));

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
import Logging from "@proxnet/undead-logging"; import Logging from "@proxnet/undead-logging";
import * as fs from "node:fs"; import * as fs from "node:fs";
import { PhotonRegionCodeString } from "./data/live/types.ts"; import { PhotonRegionCodeNumber, PhotonRegionCodeString } from "./data/live/types.ts";
const log = new Logging("Config"); const log = new Logging("Config");
@@ -49,7 +49,7 @@ type PublicConfiguration = {
levelScale: number; levelScale: number;
maxLevels: number; maxLevels: number;
patches: string[]; patches: string[];
photonRegionId: PhotonRegionCodeString; photonRegionId: PhotonRegionCodeString | PhotonRegionCodeNumber;
}; };
type LoggingConfiguration = { type LoggingConfiguration = {
@@ -111,7 +111,7 @@ export const defaultConfig: GalvanicConfiguration = {
levelScale: 1, levelScale: 1,
maxLevels: 30, maxLevels: 30,
patches: [], patches: [],
photonRegionId: PhotonRegionCodeString.UnitedStates, photonRegionId: PhotonRegionCodeNumber.us,
}, },
logging: { logging: {
notfound: false, notfound: false,

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -19,10 +19,6 @@ import { Config } from "../config.ts";
import { Redis } from "../db.ts"; import { Redis } from "../db.ts";
import { Objectives } from "./objectives.ts"; import { Objectives } from "./objectives.ts";
export type Config = {
Key: string;
Value: string;
};
export type LevelProgressionItem = { export type LevelProgressionItem = {
Level: number; Level: number;
RequiredXp: number; RequiredXp: number;
@@ -38,13 +34,13 @@ export type AutoMicMutingConfig = {
MicSpamWarningStateVolumeMultiplier: number MicSpamWarningStateVolumeMultiplier: number
} }
export type PublicConfig = { export type PublicConfig = {
ShareBaseUrl: string
ServerMaintenance: { ServerMaintenance: {
StartsInMinutes: number; StartsInMinutes: number;
}; };
LevelProgressionMaps: LevelProgressionItem[]; LevelProgressionMaps: LevelProgressionItem[];
DailyObjectives: Objectives.Objective[][]; DailyObjectives: Objectives.Objective[][];
ConfigTable: Config[]; AutoMicMutingConfig: AutoMicMutingConfig,
AutoMicMutingConfig: AutoMicMutingConfig
}; };
/** /**
@@ -72,7 +68,6 @@ export function getConfig() {
}, },
LevelProgressionMaps: generateLevelProgressionMap(), LevelProgressionMaps: generateLevelProgressionMap(),
DailyObjectives: [], DailyObjectives: [],
ConfigTable: [],
AutoMicMutingConfig: { AutoMicMutingConfig: {
MicSpamVolumeThreshold: 1.125, MicSpamVolumeThreshold: 1.125,
MicVolumeSampleInterval: 0.25, MicVolumeSampleInterval: 0.25,
@@ -82,7 +77,8 @@ export function getConfig() {
MicSpamSamplePercentageForForceMute: 0.8, MicSpamSamplePercentageForForceMute: 0.8,
MicSpamSamplePercentageForForceMuteToEnd: 0.2, MicSpamSamplePercentageForForceMuteToEnd: 0.2,
MicSpamWarningStateVolumeMultiplier: 0.25 MicSpamWarningStateVolumeMultiplier: 0.25
} },
ShareBaseUrl: `${config.web.api.securepublichost ? 'https' : 'http'}://${config.web.api.publichost}/{0}` // {0} is replaced by the game
}; };
return conf; return conf;

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
import { Redis } from "../../db.ts"; import { Redis } from "../../db.ts";
import { RootPath } from "./baseimages.ts"; import { RootPath } from "./baseimages.ts";
import { BuiltinRoom, RoomDetails, RoomState } from "./roomtypes.ts"; import { BuiltinRoom, RoomAccessibility, RoomDetails, RoomState } from "./roomtypes.ts";
import { RoomFetch } from "./room.ts"; import { RoomFetch } from "./room.ts";
import { Profile } from "../profiles.ts"; import { Profile } from "../profiles.ts";
import Logging from "@proxnet/undead-logging"; import Logging from "@proxnet/undead-logging";
@@ -172,7 +172,7 @@ class RoomsBase {
await Redis.Database.set(Redis.buildKey(Redis.KeyGroups.Room_Names, details.Room.Name), details.Room.RoomId); await Redis.Database.set(Redis.buildKey(Redis.KeyGroups.Room_Names, details.Room.Name), details.Room.RoomId);
} }
async cloneRoom(roomid: number, newname: string, newowner: Profile, dorm?: boolean) { async cloneRoom(roomid: number, newname: string, newowner: Profile) {
const canBeClonedRaw = await Redis.Database.hget(Redis.buildKey( const canBeClonedRaw = await Redis.Database.hget(Redis.buildKey(
Redis.KeyGroups.Rooms.Root, Redis.KeyGroups.Rooms.Root,
roomid.toString(), roomid.toString(),
@@ -183,22 +183,21 @@ class RoomsBase {
try { try {
canBeCloned = JSON.parse(canBeClonedRaw) as boolean; canBeCloned = JSON.parse(canBeClonedRaw) as boolean;
} catch { } catch {
log.d(`Cloneroom ${roomid}: parse error`);
return null;
}
if (!canBeCloned) {
log.d(`Cloneroom ${roomid}: cannot be cloned`);
return null; return null;
} }
if (!canBeCloned) return null;
const beforeRoom = await Rooms.get(roomid); // room must exist const beforeRoom = await Rooms.get(roomid); // room must exist
if (!beforeRoom || !beforeRoom.Room.CloningAllowed) return null; // room must be cloneable if (!beforeRoom || !beforeRoom.Room.CloningAllowed) return null; // room must be cloneable
if (await Rooms.getByName(newname) && beforeRoom.Room.Name !== 'DormRoom') return null; // room name cannot be taken if (beforeRoom.Room.Name !== 'DormRoom' && await Rooms.getByName(newname)) return null; // room name cannot be taken
const newId = await this.#getAvailableRoomId(); const newId = await this.#getAvailableRoomId();
beforeRoom.Room.CreatorPlayerId = newowner.getId(); beforeRoom.Room.CreatorPlayerId = newowner.getId();
beforeRoom.Room.RoomId = newId; beforeRoom.Room.RoomId = newId;
for (const subroom of beforeRoom.Scenes) subroom.RoomId = newId; for (const subroom of beforeRoom.Scenes) subroom.RoomId = newId;
if (dorm) {
beforeRoom.Room.IsAGRoom = true;
beforeRoom.Room.IsDormRoom = true;
beforeRoom.Room.CloningAllowed = false;
}
await Rooms.#setRoom(beforeRoom); await Rooms.#setRoom(beforeRoom);
return beforeRoom; return beforeRoom;
@@ -211,19 +210,19 @@ class RoomsBase {
Redis.KeyGroups.Rooms.PlayerDorms Redis.KeyGroups.Rooms.PlayerDorms
), player.getId().toString()); ), player.getId().toString());
if (unparsedId) { if (unparsedId) {
log.d(`Unparsed dorm ID for profile ${player.getId()}: ${unparsedId}`);
const parsedId = parseInt(unparsedId); const parsedId = parseInt(unparsedId);
if (!isNaN(parsedId)) return await Rooms.get(parsedId); if (isNaN(parsedId)) {
log.d(`Returning new dorm for profile ${player.getId()}`);
return await Rooms.get(parsedId);
}
} }
const baseDorm = await Rooms.getByName("DormRoom"); const newDorm = await this.generateNewDorm(player);
await this.#setRoom(newDorm);
log.d('Base dorm existed'); log.d(`New dorm for ${player.getId()} existed`);
if (!baseDorm) return null;
log.d('Base dorm was not null');
const newDorm = await this.cloneRoom(baseDorm.Room.RoomId, "DormRoom", player, true);
log.d('New dorm existed');
if (!newDorm) return null; if (!newDorm) return null;
log.d('New dorm was not null'); log.d(`New dorm for ${player.getId()} was not null`);
await Redis.Database.hset(Redis.buildKey( await Redis.Database.hset(Redis.buildKey(
Redis.KeyGroups.Rooms.Root, Redis.KeyGroups.Rooms.Root,
Redis.KeyGroups.Rooms.PlayerDorms Redis.KeyGroups.Rooms.PlayerDorms
@@ -231,10 +230,59 @@ class RoomsBase {
return newDorm; return newDorm;
} }
async generateNewDorm(player: Profile) {
const id = await this.#getAvailableRoomId();
const basedorm: RoomDetails = {
Room: {
RoomId: id,
Name: `DormRoom`,
Description: "Your private room.",
CreatorPlayerId: player.getId(),
ImageName: "DefaultProfileImage.png",
State: RoomState.Active,
Accessibility: RoomAccessibility.Private,
SupportsLevelVoting: false,
IsAGRoom: false,
IsDormRoom: true,
CloningAllowed: false,
SupportsScreens: true,
SupportsTeleportVR: true,
SupportsWalkVR: true,
AllowsJuniors: true,
RoomWarningMask: 0,
CustomRoomWarning: "",
DisableMicAutoMute: false
},
Scenes: [
{
RoomId: id,
RoomSceneId: 1,
Name: "Home",
RoomSceneLocationId: "76d98498-60a1-430c-ab76-b54a29b7a163",
IsSandbox: true,
CanMatchmakeInto: true,
MaxPlayers: 4,
DataBlobName: "",
DataModifiedAt: new Date().toISOString()
}
],
CoOwners: [],
InvitedCoOwners: [],
Hosts: [],
InvitedHosts: [],
CheerCount: 0,
VisitCount: 0,
FavoriteCount: 0,
Tags: []
}
return basedorm;
}
async generateBuiltinRooms() { async generateBuiltinRooms() {
if ((await Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Rooms.Root, this.miscKeys.BuiltinGenerated))) !== null) return true; if ((await Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Rooms.Root, this.miscKeys.BuiltinGenerated))) !== null) return true;
for (const builtinRoom of rooms) { for (const builtinRoom of rooms) {
if (builtinRoom.Name == 'DormRoom') continue;
const newId = await this.#getAvailableRoomId(); const newId = await this.#getAvailableRoomId();
await Redis.Database.sadd(Redis.buildKey(Redis.KeyGroups.Rooms.Root, this.miscKeys.AGRooms), newId); await Redis.Database.sadd(Redis.buildKey(Redis.KeyGroups.Rooms.Root, this.miscKeys.AGRooms), newId);
const roomDets: RoomDetails = { const roomDets: RoomDetails = {
@@ -320,6 +368,11 @@ class RoomsBase {
else return parsedIds.map(val => val.toString()); else return parsedIds.map(val => val.toString());
} }
getSubroomNameFromId(room: RoomDetails, subroomId: number) {
const subroom = room.Scenes.find(scene => scene.RoomSceneId == subroomId);
if (subroom) return subroom.Name;
else return null;
}
} }

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -18,9 +18,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
export enum SettingKey { export enum SettingKey {
PlayerStatusVisibility = "PlayerStatusVisibility", PlayerStatusVisibility = "PlayerStatusVisibility",
VRMovementMode = "VR_MOVEMENT_MODE", VRMovementMode = "VR_MOVEMENT_MODE",
RecroomOOBE = "Recroom.OOBE",
PlayerSessionCount = "PlayerSessionCount",
BACKPACK_FAVORITE_TOOL = "BACKPACK_FAVORITE_TOOL",
Recroom_ChallengeMap = "Recroom.ChallengeMap",
FIRST_TIME_IN_FLAGS = "FIRST_TIME_IN_FLAGS"
} }
export enum SettingDefault { export enum SettingDefault {
PlayerStatusVisibility = "1", PlayerStatusVisibility = "0",
VRMovementMode = "0" VRMovementMode = "0",
RecroomOOBE = "100",
PlayerSessionCount = "1",
BACKPACK_FAVORITE_TOOL = "-1",
Recroom_ChallengeMap = "0",
FIRST_TIME_IN_FLAGS = "0"
} }

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -29,3 +29,22 @@ export enum StorefrontTypes {
StuntRunner = 600, StuntRunner = 600,
DormMirror = 700 DormMirror = 700
} }
export enum StorefrontBalanceType {
NonPurchasedNonP2P = -2,
NonPurchasedP2P,
SteamPurchased,
OculusPurchased,
PlayStationPurchased,
MicrosoftPurchased,
IOSPurchased = 5
}
export enum CurrencyType {
Invalid,
LaserTagTickets,
RecCenterTokens,
LostSkullsGold = 100,
DraculaSilver,
RecRoyale_Season1 = 200
}

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -66,6 +66,7 @@ class MatchmakingBase {
else if (instance.isPrivate) return { errorCode: MatchmakingErrorCode.RoomInstanceIsPrivate }; else if (instance.isPrivate) return { errorCode: MatchmakingErrorCode.RoomInstanceIsPrivate };
await Instances.setPlayerInstance(options.profile, instance); await Instances.setPlayerInstance(options.profile, instance);
Instances.clearAllRoomEmptyInstances(instance.roomId);
return { errorCode: MatchmakingErrorCode.Success, roomInstance: instance }; return { errorCode: MatchmakingErrorCode.Success, roomInstance: instance };
} }
@@ -73,36 +74,77 @@ class MatchmakingBase {
} else { } else {
// check to make sure room exists, is not private, and is active
const targetRoom = options.roomName !== 'DormRoom' ? await Rooms.getByName(options.roomName) : await Rooms.getProfileDormDefault(options.profile); const targetRoom = options.roomName !== 'DormRoom' ? await Rooms.getByName(options.roomName) : await Rooms.getProfileDormDefault(options.profile);
if (!targetRoom) return { errorCode: MatchmakingErrorCode.NoSuchRoom }; if (!targetRoom) return { errorCode: MatchmakingErrorCode.NoSuchRoom };
if (targetRoom.Room.Accessibility == RoomAccessibility.Private) return { errorCode: MatchmakingErrorCode.RoomIsPrivate }; if (targetRoom.Room.Accessibility == RoomAccessibility.Private && targetRoom.Room.CreatorPlayerId !== options.profile.getId())
return { errorCode: MatchmakingErrorCode.RoomIsPrivate };
if (targetRoom.Room.State !== RoomState.Active) return { errorCode: MatchmakingErrorCode.RoomIsNotActive }; if (targetRoom.Room.State !== RoomState.Active) return { errorCode: MatchmakingErrorCode.RoomIsNotActive };
const roomId = targetRoom.Room.RoomId; const roomId = targetRoom.Room.RoomId;
Instances.clearAllRoomEmptyInstances(roomId);
// get all available instance
let allInstances = Instances.getAllRoomInstances(roomId).values().toArray().filter(instance => !instance.isPrivate && !instance.isFull); let allInstances = Instances.getAllRoomInstances(roomId).values().toArray().filter(instance => !instance.isPrivate && !instance.isFull);
const subroomId = targetRoom.Scenes.find(scene => scene.Name == options.subRoomName)?.RoomSceneId; const subroomId = targetRoom.Scenes.find(scene => scene.Name == options.subRoomName)?.RoomSceneId;
if (subroomId) allInstances = allInstances.filter(instance => instance.subRoomId == subroomId); if (subroomId) allInstances = allInstances.filter(instance => instance.subRoomId == subroomId);
const foundInstance = allInstances[Math.floor(Math.random() * allInstances.length)]; // filter instances that do not support join in progress and are in progress
const builtinRooms = Rooms.getAllBuiltinRooms();
const joinInProgressSubrooms = builtinRooms.map(room =>
({Name: room.Name, Scenes: room.Scenes.map(scene =>
({Name: scene.Name, Supported: scene.SupportsJoinInProgress})
)})
);
allInstances = allInstances.filter(instance => {
const subroomName = Rooms.getSubroomNameFromId(targetRoom, instance.subRoomId);
if (!subroomName) return false;
const subrooms = joinInProgressSubrooms.find(room => room.Name == targetRoom.Room.Name);
if (!subrooms) return false;
const supportsJoinInProgress = subrooms.Scenes.find(subroom => subroom.Name == subroomName)?.Supported;
if (supportsJoinInProgress) return true;
else if (!instance.isInProgress) return true;
else return false;
});
allInstances = allInstances.sort((a, b) => {
const pidsA = Instances.getInstancePlayers(a);
const pidsB = Instances.getInstancePlayers(b);
return pidsA.size - pidsB.size;
}).reverse(); // Largest instances first
const foundInstance = allInstances[0];
if (!foundInstance) { if (!foundInstance) {
const matchmakeableSubrooms = targetRoom.Scenes.filter(scene => scene.CanMatchmakeInto); const matchmakeableSubrooms = targetRoom.Scenes.filter(scene => scene.CanMatchmakeInto);
const newInstance = Instances.createInstance({ const newInstance = await Instances.createInstance({
Room: targetRoom, Room: targetRoom,
SceneIndex: Math.floor(Math.random() * matchmakeableSubrooms.length), SceneIndex: Math.floor(Math.random() * matchmakeableSubrooms.length),
FirstPlayer: options.profile FirstPlayer: options.profile,
Private: options.private,
IsDorm: options.roomName == 'DormRoom'
}); });
Instances.clearAllRoomEmptyInstances(roomId);
return { errorCode: MatchmakingErrorCode.Success, roomInstance: newInstance }; return { errorCode: MatchmakingErrorCode.Success, roomInstance: newInstance };
} else { } else {
const currentInstance = options.profile.getInstance();
if (currentInstance?.roomInstanceId == foundInstance.roomInstanceId)
return { errorCode: MatchmakingErrorCode.AlreadyInBestInstance };
await Instances.setPlayerInstance(options.profile, foundInstance); await Instances.setPlayerInstance(options.profile, foundInstance);
Instances.clearAllRoomEmptyInstances(roomId);
return { errorCode: MatchmakingErrorCode.Success, roomInstance: foundInstance }; return { errorCode: MatchmakingErrorCode.Success, roomInstance: foundInstance };
} }
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ along with this program. If not, see <https://www.gnu.org/licenses/>. */
import Logging from "@proxnet/undead-logging"; import Logging from "@proxnet/undead-logging";
import { Profile } from "../profiles.ts"; import UnifiedProfile, { Profile } from "../profiles.ts";
import { RoomInstance, InstanceOptions } from "./types.ts"; import { RoomInstance, InstanceOptions } from "./types.ts";
import { Config } from "../../config.ts"; import { Config } from "../../config.ts";
import Presence from "./presence.ts"; import Presence from "./presence.ts";
@@ -114,22 +114,28 @@ class InstancesBase {
* *
* If one is, the player will be automatically added to the instance and their `profile.getInstance()` will be synchronized. * If one is, the player will be automatically added to the instance and their `profile.getInstance()` will be synchronized.
*/ */
createInstance(options: InstanceOptions) { async createInstance(options: InstanceOptions) {
const scene = options.Room.Scenes[options.SceneIndex]; const scene = options.Room.Scenes[options.SceneIndex];
const newId = this.#generateUniqueInstanceId(); const newId = this.#generateUniqueInstanceId();
if (!scene) throw new Error("The specified scene did not exist."); if (!scene) throw new Error("The specified scene did not exist.");
let instanceName = scene.Name === "Home" || scene.Name === options.Room.Room.Name ? `^${options.Room.Room.Name}` : `^${options.Room.Room.Name}.${scene.Name}`;
if (options.IsDorm) {
const dormCreatorPlayer = UnifiedProfile.get(options.Room.Room.CreatorPlayerId);
const player = await dormCreatorPlayer.export();
if (player) instanceName = `@${player.displayName}'s Dorm`;
}
const newInstance: RoomInstance = { const newInstance: RoomInstance = {
roomInstanceId: newId, roomInstanceId: newId,
roomId: options.Room.Room.RoomId, roomId: options.Room.Room.RoomId,
subRoomId: scene.RoomSceneId, subRoomId: scene.RoomSceneId,
location: scene.RoomSceneLocationId, location: scene.RoomSceneLocationId,
dataBlob: scene.DataBlobName == "" ? undefined : scene.DataBlobName, dataBlob: scene.DataBlobName,
eventId: options.EventId, eventId: options.EventId,
photonRegionId: config.public.photonRegionId, photonRegionId: config.public.photonRegionId,
photonRoomId: `20191120-GC${newId}`, photonRoomId: `20200306-GC${newId}`,
name: scene.Name === "Home" ? `^${options.Room.Room.Name}` : `^${options.Room.Room.Name}.${scene.Name}`, name: instanceName,
maxCapacity: scene.MaxPlayers, maxCapacity: scene.MaxPlayers,
isFull: false, isFull: false,
isPrivate: typeof options.Private !== 'boolean' ? false : options.Private, isPrivate: typeof options.Private !== 'boolean' ? false : options.Private,
@@ -161,7 +167,9 @@ class InstancesBase {
} }
if (this.instanceCanFitPlayer(instance)) { if (this.instanceCanFitPlayer(instance)) {
this.getInstancePlayers(instance).add(player); const instancePlayers = this.getInstancePlayers(instance);
log.i(`Player ${player.getId()} went to '${instance.name}' with ${instancePlayers.size} other players`);
instancePlayers.add(player);
player.setInstance(instance); player.setInstance(instance);
const pres = await Presence.get(player); const pres = await Presence.get(player);

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -58,7 +58,7 @@ export interface RoomInstance {
location: string, location: string,
dataBlob?: string, dataBlob?: string,
eventId?: number, eventId?: number,
photonRegionId: PhotonRegionCodeString, photonRegionId: PhotonRegionCodeString | PhotonRegionCodeNumber,
photonRoomId: string, photonRoomId: string,
name?: string, name?: string,
maxCapacity: number, maxCapacity: number,
@@ -75,7 +75,8 @@ export interface InstanceOptions {
EventId?: number, EventId?: number,
Name?: string, Name?: string,
Private?: boolean, Private?: boolean,
FirstPlayer?: Profile FirstPlayer?: Profile,
IsDorm?: boolean
} }

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -25,3 +25,13 @@ export enum PlatformMask {
IOS = 32, IOS = 32,
All = -1 All = -1
} }
export enum PlatformType {
All = -1,
Steam,
Oculus,
PlayStation,
Microsoft,
HeadlessBot,
IOS
}

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -21,6 +21,10 @@ export class ProfileContentManager {
this.profileId = profileId; this.profileId = profileId;
} }
onProfileInit() {
return;
}
profileId: number; profileId: number;
} }

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

33
src/data/profile/rooms.ts Normal file
View File

@@ -0,0 +1,33 @@
/* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
import { Redis } from "../../db.ts";
import { ProfileContentManager } from "./base/profilemanagerbase.ts";
export class ProfileRoomsManager extends ProfileContentManager {
#rootKey = Redis.buildKey(
Redis.KeyGroups.Profiles.Root,
this.profileId.toString(),
Redis.KeyGroups.Profiles.Avatar.Root
);
async getRooms() {
// get player rooms
}
}

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ along with this program. If not, see <https://www.gnu.org/licenses/>. */
import { Redis } from "../../db.ts"; import { Redis } from "../../db.ts";
import { SettingKey } from "../content/settings.ts"; import { SettingKey, SettingDefault } from "../content/settings.ts";
import { ProfileContentManager } from "./base/profilemanagerbase.ts"; import { ProfileContentManager } from "./base/profilemanagerbase.ts";
export interface Setting { export interface Setting {
@@ -26,6 +26,14 @@ export interface Setting {
export class ProfileSettingsManager extends ProfileContentManager { export class ProfileSettingsManager extends ProfileContentManager {
override async onProfileInit() {
await this.setSetting(SettingKey.RecroomOOBE, SettingDefault.RecroomOOBE);
await this.setSetting(SettingKey.PlayerStatusVisibility, SettingDefault.PlayerStatusVisibility);
await this.setSetting(SettingKey.FIRST_TIME_IN_FLAGS, SettingDefault.FIRST_TIME_IN_FLAGS);
await this.setSetting(SettingKey.BACKPACK_FAVORITE_TOOL, SettingDefault.BACKPACK_FAVORITE_TOOL);
await this.setSetting(SettingKey.Recroom_ChallengeMap, SettingDefault.Recroom_ChallengeMap);
}
async getSettings() { async getSettings() {
const settings = await Redis.Database.hgetall(Redis.buildKey(Redis.KeyGroups.Profiles.Root, this.profileId.toString(), Redis.KeyGroups.Profiles.Settings)); const settings = await Redis.Database.hgetall(Redis.buildKey(Redis.KeyGroups.Profiles.Root, this.profileId.toString(), Redis.KeyGroups.Profiles.Settings));
const returnSettings: Setting[] = []; const returnSettings: Setting[] = [];

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -140,7 +140,11 @@ class Profile {
newUsername, newUsername,
); );
return new Profile(newId); const profile = new Profile(newId);
profile.Settings.onProfileInit();
return profile;
} }
// surely this can be written better // surely this can be written better
@@ -164,7 +168,7 @@ class Profile {
platforms: 1, platforms: 1,
username: values[2] == null ? "DATABASEERROR" : values[2], username: values[2] == null ? "DATABASEERROR" : values[2],
displayName: values[3] == null ? (values[2] == null ? "DATABASEERROR" : values[2]) : values[3], displayName: values[3] == null ? (values[2] == null ? "DATABASEERROR" : values[2]) : values[3],
email: "" // removes a notification in messages (untested) email: "notanemail@notanemailsite.local" // we are confirmed
}); });
}); });
} }
@@ -219,7 +223,7 @@ class Profile {
async getBio() { async getBio() {
const bio = await Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profiles.Root, this.#id.toString(), Redis.KeyGroups.Profiles.Bio)); const bio = await Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profiles.Root, this.#id.toString(), Redis.KeyGroups.Profiles.Bio));
if (!bio) return "This player has not yet set their bio. Remind them to set one!"; if (!bio) return "";
else return bio; else return bio;
} }
@@ -302,7 +306,7 @@ class Profile {
sub: this.#id, sub: this.#id,
role: (await this.getIsOperator()) ? 'developer' : 'user', role: (await this.getIsOperator()) ? 'developer' : 'user',
exp: Math.round(Date.now() / 1000) + Math.round(config.auth.timeout * 60 * 60), exp: Math.round(Date.now() / 1000) + Math.round(config.auth.timeout * 60 * 60),
typ: AuthType.Game typ: AuthType.Game,
}; };
return await JsonWebToken.encode(payload, config.auth.secret, { algorithm: "HS512" }); return await JsonWebToken.encode(payload, config.auth.secret, { algorithm: "HS512" });
} }
@@ -335,6 +339,15 @@ class UnifiedProfileBase {
return await Profile.existsByName(name); return await Profile.existsByName(name);
} }
getAllSockets() {
const returnSockets: Set<SignalRSocketHandler> = new Set();
for (const profile of profiles.values()) {
const socket = profile.getSocketHandler();
if (socket) returnSockets.add(socket);
}
return returnSockets;
}
} }
const UnifiedProfile = new UnifiedProfileBase(); const UnifiedProfile = new UnifiedProfileBase();

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -18,54 +18,36 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
const Dictionary = { const Dictionary = {
Adjectives: [ Adjectives: [
"Amazing", "Amazing",
"Adventurous",
"Affable", "Affable",
"Agreeable", "Agreeable",
"Ambitious", "Ambitious",
"Amicable", "Amicable",
"Animated", "Animated",
"Approachable",
"Articulate",
"Astute", "Astute",
"Attractive",
"Authentic", "Authentic",
"Benevolent",
"Blissful", "Blissful",
"Bold", "Bold",
"Bright", "Bright",
"Buoyant", "Buoyant",
"Calm", "Calm",
"Captivating",
"Charismatic",
"Cheerful", "Cheerful",
"Clever", "Clever",
"Compassionate",
"Confident", "Confident",
"Considerate",
"Content", "Content",
"Cooperative",
"Courageous",
"Creative", "Creative",
"Cultured", "Cultured",
"Curious", "Curious",
"Dashing", "Dashing",
"Dazzling", "Dazzling",
"Dedicated", "Dedicated",
"Delightful",
"Dependable",
"Determined",
"Diligent", "Diligent",
"Dynamic", "Dynamic",
"Earnest", "Earnest",
"Easygoing", "Easygoing",
"Ebullient", "Ebullient",
"Effervescent",
"Empathetic",
"Enchanting",
"Endearing", "Endearing",
"Energetic", "Energetic",
"Engaging", "Engaging",
"Enthusiastic",
"Exuberant", "Exuberant",
"Fantastic", "Fantastic",
"Fearless", "Fearless",
@@ -77,28 +59,17 @@ const Dictionary = {
"Genuine", "Genuine",
"Gracious", "Gracious",
"Grateful", "Grateful",
"Harmonious",
"Heartwarming",
"Helpful", "Helpful",
"Honest", "Honest",
"Humble", "Humble",
"Humorous", "Humorous",
"Imaginative",
"Impeccable",
"Incisive", "Incisive",
"Incredible",
"Independent",
"Industrious",
"Ingenious", "Ingenious",
"Insightful",
"Intelligent",
"Intuitive", "Intuitive",
"Invigorating",
"Jovial", "Jovial",
"Jubilant", "Jubilant",
"Just", "Just",
"Kind", "Kind",
"Knowledgeable",
"Likable", "Likable",
"Lively", "Lively",
"Lovable", "Lovable",
@@ -110,24 +81,14 @@ const Dictionary = {
"Masterful", "Masterful",
"Mature", "Mature",
"Merciful", "Merciful",
"Methodical",
"Meticulous",
"Mindful", "Mindful",
"Motivated", "Motivated",
"Natural", "Natural",
"Nurturing", "Nurturing",
"Observant", "Observant",
"Optimistic",
"Outgoing", "Outgoing",
"Passionate",
"Patient", "Patient",
"Peaceful", "Peaceful",
"Perceptive",
"Perseverant",
"Persistent",
"Persuasive",
"Personable",
"Philanthropic",
"Placid", "Placid",
"Playful", "Playful",
"Pleasant", "Pleasant",
@@ -136,20 +97,14 @@ const Dictionary = {
"Powerful", "Powerful",
"Pragmatic", "Pragmatic",
"Proactive", "Proactive",
"Proficient",
"Prudent", "Prudent",
"Punctual", "Punctual",
"Purposeful",
"Radiant", "Radiant",
"Rational", "Rational",
"Real", "Real",
"Receptive", "Receptive",
"Reflective",
"Reliable", "Reliable",
"Resilient", "Resilient",
"Resourceful",
"Respectful",
"Responsible",
"Robust", "Robust",
"Sagacious", "Sagacious",
"Serene", "Serene",
@@ -159,33 +114,23 @@ const Dictionary = {
"Sociable", "Sociable",
"Spirited", "Spirited",
"Splendid", "Splendid",
"Spontaneous",
"Steady", "Steady",
"Sterling", "Sterling",
"Strong", "Strong",
"Sublime", "Sublime",
"Successful",
"Supportive",
"Sympathetic",
"Talented", "Talented",
"Tenacious", "Tenacious",
"Thoughtful",
"Tireless", "Tireless",
"Tolerant", "Tolerant",
"Tough", "Tough",
"Tranquil", "Tranquil",
"Trustworthy",
"Unassuming",
"Understanding",
"Unique", "Unique",
"Unpretentious",
"Upbeat", "Upbeat",
"Valiant", "Valiant",
"Vibrant", "Vibrant",
"Virtuous", "Virtuous",
"Visionary", "Visionary",
"Vivacious", "Vivacious",
"Warmhearted",
"Welcoming", "Welcoming",
"Wise", "Wise",
"Witty", "Witty",
@@ -198,7 +143,6 @@ const Dictionary = {
"Elysium", "Elysium",
"Horizon", "Horizon",
"Catalyst", "Catalyst",
"Luminescence",
"Utopia", "Utopia",
"Eclipse", "Eclipse",
"Nebula", "Nebula",
@@ -220,7 +164,6 @@ const Dictionary = {
"Vibrance", "Vibrance",
"Astral", "Astral",
"Jubilant", "Jubilant",
"Ascendancy",
"Zen", "Zen",
"Nebulous", "Nebulous",
"Ecliptic", "Ecliptic",
@@ -233,7 +176,6 @@ const Dictionary = {
"Enigma", "Enigma",
"Luminous", "Luminous",
"Epoch", "Epoch",
"Serendipity",
"Zenithal", "Zenithal",
"Paragon", "Paragon",
"Panorama", "Panorama",
@@ -255,7 +197,6 @@ const Dictionary = {
"Endeavor", "Endeavor",
"Visionary", "Visionary",
"Epoch", "Epoch",
"Renaissance",
"Panache", "Panache",
"Jubilee", "Jubilee",
"Resonance", "Resonance",
@@ -264,13 +205,11 @@ const Dictionary = {
"Ethereal", "Ethereal",
"Cascade", "Cascade",
"Radiance", "Radiance",
"Synchronicity",
"Nebula", "Nebula",
"Equinox", "Equinox",
"Pulsar", "Pulsar",
"Apex", "Apex",
"Ethos", "Ethos",
"Wanderlust",
"Zenith", "Zenith",
"Nebula", "Nebula",
"Vertex", "Vertex",

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -76,6 +76,7 @@ export const KeyGroups = {
}, },
Profile_Usernames: "profile-usernames", Profile_Usernames: "profile-usernames",
PlatformAssociations: "platforms", PlatformAssociations: "platforms",
AddressBans: "address-bans",
Profiles: { Profiles: {
Root: "profiles", Root: "profiles",
Username: "username", Username: "username",
@@ -87,6 +88,7 @@ export const KeyGroups = {
DeviceClass: "deviceClass", DeviceClass: "deviceClass",
Xp: "xp", Xp: "xp",
Bio: "bio", Bio: "bio",
Rooms: "rooms",
Relationships: { Relationships: {
Root: "relationships", Root: "relationships",
IncomingFriendRequests: "incomingFriendRequests", IncomingFriendRequests: "incomingFriendRequests",

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -28,6 +28,7 @@ import UnifiedProfile, { ProfileTokenFormat } from "./data/profiles.ts";
import { SocketHandoff } from "./socket/handoff.ts"; import { SocketHandoff } from "./socket/handoff.ts";
import { SignalRSocketHandler } from "./socket/socket.ts"; import { SignalRSocketHandler } from "./socket/socket.ts";
import Rooms from "./data/content/rooms.ts"; import Rooms from "./data/content/rooms.ts";
import { GameConfigs } from "./data/config.ts";
const instanceId = generateRandomString(64); const instanceId = generateRandomString(64);
@@ -114,10 +115,6 @@ if (!(await Rooms.generateBuiltinRooms())) log.i(`Generated built-in rooms`);
try { try {
/**
* Galvanic WebSocket Server
*/
type AuthResultBase = { type AuthResultBase = {
valid: boolean valid: boolean
} }
@@ -133,10 +130,13 @@ try {
const authHeader = req.headers.get('authorization'); const authHeader = req.headers.get('authorization');
if (!authHeader) return { valid: false } as AuthResult; if (!authHeader) return { valid: false } as AuthResult;
const token = authHeader.split(" ")[1]; log.d(authHeader);
const token = authHeader.split(", ")[1]; // Why is the header formatted like this?
if (!token) return { valid: false } as AuthResult; if (!token) return { valid: false } as AuthResult;
const splitToken = token.split(' ')[1];
if (!splitToken) return { valid: false } as AuthResult;
const decodedToken = await decode<ProfileTokenFormat>(token, config.auth.secret, {algorithm: 'HS512'}); const decodedToken = await decode<ProfileTokenFormat>(splitToken, config.auth.secret, {algorithm: 'HS512'});
const schemaResult = ProfileTokenSchema.safeParse(decodedToken); const schemaResult = ProfileTokenSchema.safeParse(decodedToken);
if (!schemaResult.success) return { valid: false } as AuthResult; if (!schemaResult.success) return { valid: false } as AuthResult;
else return { token: decodedToken, valid: true } as AuthResult; else return { token: decodedToken, valid: true } as AuthResult;
@@ -149,6 +149,14 @@ try {
const abort = new AbortController(); const abort = new AbortController();
abort.signal.addEventListener('abort', () => {
log.n("Closing all sockets");
const sockets = UnifiedProfile.getAllSockets();
for (const socket of sockets.values()) {
socket.destroy(socket)();
} // I used the socket to destroy the socket
});
// Galvanic WebSocket // Galvanic WebSocket
Deno.serve({port: config.web.socket.port, hostname: config.web.socket.host, signal: abort.signal, onListen: addr => { Deno.serve({port: config.web.socket.port, hostname: config.web.socket.host, signal: abort.signal, onListen: addr => {
log.n(`Socket listening on http://${addr.hostname}:${addr.port}`); log.n(`Socket listening on http://${addr.hostname}:${addr.port}`);
@@ -209,6 +217,9 @@ try {
if (!(await UnifiedProfile.existsByName("Coach"))) UnifiedProfile.create({ username: "Coach", id: 1 }); // create Coach id 1 if they do not exist if (!(await UnifiedProfile.existsByName("Coach"))) UnifiedProfile.create({ username: "Coach", id: 1 }); // create Coach id 1 if they do not exist
if (!(await UnifiedProfile.existsByName("Server"))) UnifiedProfile.create({ username: "Server", id: 2 }); // create Server id 2 if they do not exist if (!(await UnifiedProfile.existsByName("Server"))) UnifiedProfile.create({ username: "Server", id: 2 }); // create Server id 2 if they do not exist
if (!(await GameConfigs.getGameConfig('splitTestSoftOverrides'))) GameConfigs.setGameConfig('splitTestSoftOverrides', '');
if (!(await GameConfigs.getGameConfig('splitTestHardOverrides'))) GameConfigs.setGameConfig('splitTestHardOverrides', '');
}); });
http.on('error', err => { http.on('error', err => {

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -19,7 +19,7 @@ import { APIUtils } from "../apiutils.ts";
import { route as AccountRoute } from "./account/account.ts"; import { route as AccountRoute } from "./account/account.ts";
import { route as ParentalControlRoute } from "./account/parentalcontrol.ts"; import { route as ParentalControlRoute } from "./account/parentalcontrol.ts";
export const route = APIUtils.createRouter("/accountservice"); export const route = APIUtils.createRouter("/accounts");
route.router.use(AccountRoute.path, AccountRoute.router); route.router.use(AccountRoute.path, AccountRoute.router);
route.router.use(ParentalControlRoute.path, ParentalControlRoute.router); route.router.use(ParentalControlRoute.path, ParentalControlRoute.router);

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@ import { APIUtils } from "../../apiutils.ts";
import express from "express"; import express from "express";
import UnifiedProfile, { Profile } from "../../data/profiles.ts"; import UnifiedProfile, { Profile } from "../../data/profiles.ts";
import { z } from "zod"; import { z } from "zod";
import { AuthType } from "../../data/users.ts";
export const route = APIUtils.createRouter("/account"); export const route = APIUtils.createRouter("/account");
@@ -28,7 +29,7 @@ const CreateAccountRequestBodySchema = z.object({
deviceId: z.string() deviceId: z.string()
}); });
const rateLimit = new APIUtils.RateLimiter(25, 5); const rateLimit = new APIUtils.RateLimiter();
route.router.post("/create", route.router.post("/create",
@@ -102,6 +103,15 @@ route.router.get("/me",
); );
route.router.post("/me/displayname",
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
APIUtils.RecNetResponse(true, "DisplayName customization is not yet implemented."),
);
interface BioFetchParams { interface BioFetchParams {
id?: string id?: string
} }

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,30 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ along with this program. If not, see <https://www.gnu.org/licenses/>. */
import { APIUtils } from "../../apiutils.ts"; import { APIUtils } from "../../apiutils.ts";
import { AuthType } from "../../data/users.ts";
export const route = APIUtils.createRouter("/challenge"); export const route = APIUtils.createRouter("/challenge");
// create router for now // todo: challenges; all of it
// will require a ChallengeBuilder to compile challenge configs
route.router.get('/v2/getCurrent',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
(_rq, rs) => {
rs.json({
ChallengeMapId: 0,
StartAt: new Date().toISOString(),
EndAt: new Date(Date.now() + 604_800_000).toISOString(), // 1 week
ServerTime: new Date().toISOString(),
Challenges: [],
Gift: {
GiftDropId: 0,
Xp: 0,
Level: 0
}
});
},
);

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -20,7 +20,7 @@ import { GameConfigs } from "../../data/config.ts";
export const route = APIUtils.createRouter("/config"); export const route = APIUtils.createRouter("/config");
const rateLimit = new APIUtils.RateLimiter(60, 2); const rateLimit = new APIUtils.RateLimiter();
route.router.get("/v2", rateLimit.middle(), (_rq, rs) => { route.router.get("/v2", rateLimit.middle(), (_rq, rs) => {
const config = GameConfigs.getConfig(); const config = GameConfigs.getConfig();

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -27,4 +27,4 @@ route.router.get('/v2/getUnlocked',
APIUtils.emptyArrayResponse APIUtils.emptyArrayResponse
) );

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,12 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ along with this program. If not, see <https://www.gnu.org/licenses/>. */
import { APIUtils } from "../../apiutils.ts"; import { APIUtils } from "../../apiutils.ts";
import { GameConfigs } from "../../data/config.ts";
export const route = APIUtils.createRouter("/gameconfigs"); export const route = APIUtils.createRouter("/gameconfigs");
route.router.get("/v1/all", APIUtils.emptyArrayResponse); const rateLimit = new APIUtils.RateLimiter();
route.router.get("/v1/all", rateLimit.middle(), async (_rq, rs) => {
rs.json((await GameConfigs.getAllGameConfigs()).entries().map(val => ({Key: val[0], Value: val[1]})).toArray());
});

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -15,8 +15,10 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ along with this program. If not, see <https://www.gnu.org/licenses/>. */
import { APIUtils } from "../../apiutils.ts"; import { z } from "zod";
import { APIUtils, NoBody } from "../../apiutils.ts";
import { AuthType } from "../../data/users.ts"; import { AuthType } from "../../data/users.ts";
import express from "express";
export const route = APIUtils.createRouter('/objectives'); export const route = APIUtils.createRouter('/objectives');
@@ -33,3 +35,27 @@ route.router.get('/v1/myprogress',
}, },
); );
interface ClearGroupRequestBody {
Group: number
}
const ClearGroupRequestSchema = z.object({
Group: z.number()
});
route.router.post('/v1/cleargroup',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
express.json(),
APIUtils.logBody,
APIUtils.validateRequestBody(ClearGroupRequestSchema),
(rq: express.Request<NoBody, NoBody, ClearGroupRequestBody>, rs: express.Response) => {
rs.json({
Group: rq.body.Group,
IsCompleted: false,
ClearedAt: new Date().toISOString() // todo: objectives; all of it
});
},
);

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -39,3 +39,15 @@ route.router.get('/v1/:id',
} }
); );
route.router.get('/v1/bulk',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
express.urlencoded({ extended: true }),
APIUtils.logBody,
APIUtils.emptyArrayResponse
);

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -19,10 +19,11 @@ import Logging from "@proxnet/undead-logging";
import { APIUtils } from "../../apiutils.ts"; import { APIUtils } from "../../apiutils.ts";
import express from "express"; import express from "express";
import UnifiedProfile from "../../data/profiles.ts"; import UnifiedProfile from "../../data/profiles.ts";
import { AuthType } from "../../data/users.ts";
const log = new Logging("ProgressionRoute"); const log = new Logging("ProgressionRoute");
const rateLimit = new APIUtils.RateLimiter(60, 2); const rateLimit = new APIUtils.RateLimiter();
export const route = APIUtils.createRouter("/players"); export const route = APIUtils.createRouter("/players");
@@ -49,3 +50,14 @@ route.router.get('/v1/progression/:id',
} }
); );
route.router.post('/v1/progression/bulk',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
express.urlencoded({ extended: true }),
APIUtils.logBody,
APIUtils.emptyArrayResponse
);

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -66,7 +66,7 @@ route.router.get('/v1/hot',
async (_rq, rs) => { async (_rq, rs) => {
// temporary: return all public AG rooms for testing // temporary: return all public AG rooms for testing
const rooms = await Rooms.getAllBuiltinRoomGenerations(); const rooms = await Rooms.getAllBuiltinRoomGenerations();
rs.json(rooms.map(room => room.Room).filter(room => room.Accessibility !== RoomAccessibility.Private)); rs.json(rooms.map(room => room.Room).filter(room => room.Accessibility == RoomAccessibility.Public));
}, },
); );
@@ -98,11 +98,16 @@ route.router.get('/v2/name/:name',
} }
const room = await Rooms.getByName(rq.params.name.trim()); const room = await Rooms.getByName(rq.params.name.trim());
if (!room || rq.params.name == 'DormRoom') { if (room) {
rs.sendStatus(404); rs.json(room.Room);
return;
} else if (rq.params.name == 'DormRoom') {
const dorm = await Rooms.getProfileDormDefault(rs.locals.profile);
if (dorm) rs.json(dorm.Room);
else rs.sendStatus(404);
return; return;
} else { } else {
rs.json(room.Room); rs.sendStatus(404);
return; return;
} }
}, },

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -59,11 +59,8 @@ route.router.post('/v2/set',
(rq: express.Request<NoBody, NoBody, SettingsSetBody>, rs: express.Response) => { (rq: express.Request<NoBody, NoBody, SettingsSetBody>, rs: express.Response) => {
rs.locals.profile.Settings.setSettingRaw(rq.body.Key, rq.body.Value), rs.locals.profile.Settings.setSettingRaw(rq.body.Key, rq.body.Value),
rs.json({ rs.sendStatus(200);
Succeeded: true, log.d(`${rs.locals.profile.getId()} set settings key '${rq.body.Key}' to '${rq.body.Value}'`);
Error: "",
ShouldRetry: false
});
} }
); );

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -17,6 +17,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
import { APIUtils } from "../../apiutils.ts"; import { APIUtils } from "../../apiutils.ts";
import express from "express"; import express from "express";
import { AuthType } from "../../data/users.ts";
import { CurrencyType, StorefrontBalanceType } from "../../data/content/storefronts.ts";
export const route = APIUtils.createRouter('/storefronts'); export const route = APIUtils.createRouter('/storefronts');
@@ -26,6 +28,7 @@ interface StorefrontFetchParams {
route.router.get('/v3/giftdropstore/:id', route.router.get('/v3/giftdropstore/:id',
APIUtils.Authentication, APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
(rq: express.Request<StorefrontFetchParams>, rs: express.Response) => { (rq: express.Request<StorefrontFetchParams>, rs: express.Response) => {
if (!rq.params.id) { if (!rq.params.id) {
@@ -40,3 +43,27 @@ route.router.get('/v3/giftdropstore/:id',
}, },
); );
interface BalanceParams {
currencyType?: string
}
route.router.get('/v4/balance/:currencyType',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
(rq: express.Request<BalanceParams>, rs: express.Response) => {
const parsedCurrencyType = parseInt(rq.params.currencyType ? rq.params.currencyType : "2");
if (isNaN(parsedCurrencyType)) {
rs.sendStatus(400);
} else {
rs.json([{
Balance: 0,
BalanceType: StorefrontBalanceType.NonPurchasedNonP2P,
CurrencyType: parsedCurrencyType
}]);
}
},
);

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -19,7 +19,9 @@ import { APIUtils } from "../../apiutils.ts";
export const route = APIUtils.createRouter("/versioncheck"); export const route = APIUtils.createRouter("/versioncheck");
const validVersion = "20191120"; export const validVersions = [
"20200306"
];
enum VersionStatus { enum VersionStatus {
ValidForPlay, ValidForPlay,
@@ -35,10 +37,10 @@ route.router.get("/v4", (rq, rs) => {
const requestedVer = rq.query["v"]; const requestedVer = rq.query["v"];
const pQuery = rq.query["p"]; const pQuery = rq.query["p"];
if (typeof requestedVer == "undefined" || typeof pQuery == "undefined") { if (typeof requestedVer == "undefined" || typeof pQuery == "undefined" || typeof requestedVer == 'object') {
rs.statusCode = 400; rs.statusCode = 400;
rs.json(APIUtils.genericResponseFormat(true, "One or more query parameters were not found.")); rs.json(APIUtils.genericResponseFormat(true, "One or more query parameters were not found or invalid."));
} else if (requestedVer !== validVersion) { } else if (!validVersions.includes(requestedVer as string)) {
const res: ValidVersionResponse = { const res: ValidVersionResponse = {
VersionStatus: VersionStatus.UpdateRequired, VersionStatus: VersionStatus.UpdateRequired,
}; };

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -18,8 +18,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
import { APIUtils } from "../apiutils.ts"; import { APIUtils } from "../apiutils.ts";
import { route as CachedLoginRoute } from "./auth/cachedlogin.ts"; import { route as CachedLoginRoute } from "./auth/cachedlogin.ts";
import { route as ConnectRoute } from "./auth/connect.ts"; import { route as ConnectRoute } from "./auth/connect.ts";
import { route as AccountRoute } from "./auth/account.ts";
export const route = APIUtils.createRouter("/authservice"); export const route = APIUtils.createRouter("/auth");
route.router.use(CachedLoginRoute.path, CachedLoginRoute.router); route.router.use(CachedLoginRoute.path, CachedLoginRoute.router);
route.router.use(ConnectRoute.path, ConnectRoute.router); route.router.use(ConnectRoute.path, ConnectRoute.router);
route.router.use(AccountRoute.path, AccountRoute.router);

View File

@@ -0,0 +1,41 @@
/* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
import { APIUtils } from "../../apiutils.ts";
import { AuthType } from "../../data/users.ts";
export const route = APIUtils.createRouter("/account");
route.router.post('/me/changepassword',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
APIUtils.RecNetResponse(true, "Passwords are unsupported on Galvanic Corrosion.")
);
route.router.get('/me/haspassword',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
(rq, rs) => {
rs.json(true);
},
);

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -24,6 +24,7 @@ import Logging from "@proxnet/undead-logging";
import { z } from "zod"; import { z } from "zod";
import { AuthType } from "../../data/users.ts"; import { AuthType } from "../../data/users.ts";
import { Redis } from "../../db.ts"; import { Redis } from "../../db.ts";
import { validVersions } from "../api/versioncheck.ts";
const config = Config.getConfig(); const config = Config.getConfig();
@@ -116,7 +117,7 @@ route.router.post("/token",
const conditionsMet = ![ const conditionsMet = ![
rq.body.client_id === "recroom", rq.body.client_id === "recroom",
rq.body.platform === "0", rq.body.platform === "0",
rq.body.ver === '20191120', validVersions.includes(rq.body.ver),
rq.body.device_class.length === 1, rq.body.device_class.length === 1,
!isNaN(Number(rq.body.device_class)), !isNaN(Number(rq.body.device_class)),
!(rq.body.device_id.length > 96), !(rq.body.device_id.length > 96),

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -36,6 +36,7 @@ interface ImageQueryOptions {
cropSquare?: string; cropSquare?: string;
width?: string; width?: string;
height?: string; height?: string;
sig?: string;
} }
route.router.get( route.router.get(
@@ -49,8 +50,6 @@ route.router.get(
rq.path.substring(1, rq.path.length).replaceAll("%20", " "), rq.path.substring(1, rq.path.length).replaceAll("%20", " "),
); );
// why does it think it is never reassigned? line 39
// deno-lint-ignore prefer-const
let image: Image; let image: Image;
const imageSource = baseImages.includes(filename) const imageSource = baseImages.includes(filename)
? BaseImages.getBaseImage(filename) ? BaseImages.getBaseImage(filename)
@@ -80,6 +79,23 @@ route.router.get(
else height = num; else height = num;
} }
if (cropSquare == 1) {
if (image.width > image.height) {
image.crop(
Math.round(image.width / 2) - Math.round(image.height / 2),
0,
image.height,
image.height,
);
} else {
image.crop(
0,
Math.round(image.height / 2) - Math.round(image.width / 2),
image.width,
image.width,
);
}
}
if (width && height) { if (width && height) {
const targetWidth = width > image.width ? image.width : width; const targetWidth = width > image.width ? image.width : width;
const targetHeight = height > image.height ? image.height : height; const targetHeight = height > image.height ? image.height : height;
@@ -102,23 +118,8 @@ route.router.get(
} }
} else if (width) image.resize(width, Image.RESIZE_AUTO); } else if (width) image.resize(width, Image.RESIZE_AUTO);
else if (height) image.resize(Image.RESIZE_AUTO, height); else if (height) image.resize(Image.RESIZE_AUTO, height);
if (cropSquare == 1) {
if (image.width > image.height) {
image.crop(
Math.round(image.width / 2) - Math.round(image.height / 2),
0,
image.height,
image.height,
);
} else {image.crop(
0,
Math.round(image.height / 2) - Math.round(image.width / 2),
image.width,
image.width,
);}
}
rs.setHeader('content-signature', 'key-id=KEY:RSA:p1.rec.net; data=aGk='); // enable image signature patch on client if (rq.query.sig) rs.setHeader('content-signature', 'key-id=KEY:RSA:p1.rec.net; data=aGk=');
rs.type("png").send(Buffer.from(await image.encode())); rs.type("png").send(Buffer.from(await image.encode()));
}, },
); );

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -35,8 +35,9 @@ route.router.post('/room/:roomName',
APIUtils.Authentication, APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game), APIUtils.AuthenticationType(AuthType.Game),
APIUtils.startTimer,
async (rq: express.Request<MatchmakingParams>, rs: express.Response) => { async (rq: express.Request<MatchmakingParams>, rs: express.Response, nxt: express.NextFunction) => {
if (!rq.params.roomName) { if (!rq.params.roomName) {
log.d('Matchmake failed: No room specified'); log.d('Matchmake failed: No room specified');
rs.json({ rs.json({
@@ -45,22 +46,30 @@ route.router.post('/room/:roomName',
return; return;
} }
rs.json(await Matchmaking.matchmake({ profile: rs.locals.profile, roomName: rq.params.roomName })); rs.json(await Matchmaking.matchmake({ profile: rs.locals.profile, roomName: rq.params.roomName }));
nxt();
}, },
APIUtils.stopTimer
); );
route.router.post('/room/:roomName/:subRoomName', route.router.post('/room/:roomName/:subRoomName',
APIUtils.Authentication, APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game), APIUtils.AuthenticationType(AuthType.Game),
APIUtils.startTimer,
async (rq: express.Request<MatchmakingParams>, rs: express.Response) => { async (rq: express.Request<MatchmakingParams>, rs: express.Response, nxt: express.NextFunction) => {
if (!rq.params.roomName) { if (!rq.params.roomName) {
log.d('Matchmake failed: No room specified');
rs.json({ rs.json({
errorCode: MatchmakingErrorCode.NoSuchRoom errorCode: MatchmakingErrorCode.NoSuchRoom
}); });
return; return;
} }
rs.json(await Matchmaking.matchmake({ profile: rs.locals.profile, roomName: rq.params.roomName, subRoomName: rq.params.subRoomName })); rs.json(await Matchmaking.matchmake({ profile: rs.locals.profile, roomName: rq.params.roomName, subRoomName: rq.params.subRoomName }));
nxt();
}, },
) APIUtils.stopTimer
);

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -25,6 +25,7 @@ import Logging from "@proxnet/undead-logging";
import UnifiedProfile from "../../data/profiles.ts"; import UnifiedProfile from "../../data/profiles.ts";
import { PlayerStatusVisibility, VRMovementMode } from "../../data/live/types.ts"; import { PlayerStatusVisibility, VRMovementMode } from "../../data/live/types.ts";
import { SettingKey } from "../../data/content/settings.ts"; import { SettingKey } from "../../data/content/settings.ts";
import Instances from "../../data/live/instances.ts";
const log = new Logging("MatchPlayerRoute"); const log = new Logging("MatchPlayerRoute");
@@ -85,7 +86,7 @@ route.router.post('/logout',
APIUtils.validateRequestBody(LoginSchema), APIUtils.validateRequestBody(LoginSchema),
(_rq, rs) => { (_rq, rs) => {
Matchmaking.deleteLoginLock(rs.locals.profile); Instances.removePlayerFromCurrentInstance(rs.locals.profile);
rs.sendStatus(200); rs.sendStatus(200);
} }
@@ -110,14 +111,14 @@ interface StatusVisibilityBody {
statusVisibility: PlayerStatusVisibility statusVisibility: PlayerStatusVisibility
} }
const StatusVisibilitySchema = z.object({ const StatusVisibilitySchema = z.object({
statusVisibility: z.nativeEnum(PlayerStatusVisibility) statusVisibility: z.enum(Object.values(PlayerStatusVisibility).map(String) as [string, ...string[]])
}); });
route.router.put('/statusvisibility', route.router.put('/statusvisibility',
APIUtils.Authentication, APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game), APIUtils.AuthenticationType(AuthType.Game),
express.urlencoded({ extended: true }), express.urlencoded({ extended: true }),
APIUtils.logBody,
APIUtils.validateRequestBody(StatusVisibilitySchema), APIUtils.validateRequestBody(StatusVisibilitySchema),
async (rq: express.Request<NoBody, NoBody, StatusVisibilityBody>, rs: express.Response) => { async (rq: express.Request<NoBody, NoBody, StatusVisibilityBody>, rs: express.Response) => {
@@ -149,3 +150,14 @@ route.router.put('/vrmovementmode',
}, },
); );
route.router.put('/photonregionpings',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
(rq, rs) => {
rs.sendStatus(200);
}
);

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -24,6 +24,7 @@ const protocol = config.web.api.securepublichost ? "https" : "http";
export const route = APIUtils.createRouter("/ns"); export const route = APIUtils.createRouter("/ns");
type NameserverHosts = { type NameserverHosts = {
Accounts: string;
Auth: string; Auth: string;
API: string; API: string;
WWW: string; WWW: string;
@@ -38,6 +39,7 @@ type NameserverHosts = {
}; };
const nameserver: NameserverHosts = { const nameserver: NameserverHosts = {
Accounts: `${protocol}://${config.web.api.publichost}/accounts`,
Auth: `${protocol}://${config.web.api.publichost}/auth`, Auth: `${protocol}://${config.web.api.publichost}/auth`,
API: `${protocol}://${config.web.api.publichost}`, API: `${protocol}://${config.web.api.publichost}`,
WWW: `${protocol}://${config.web.api.publichost}`, WWW: `${protocol}://${config.web.api.publichost}`,

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -57,7 +57,7 @@ const AuthRequestRootSchema = z.object({
pubkey: z.string(), pubkey: z.string(),
}); });
const rateLimit = new APIUtils.RateLimiter(60, 2); const rateLimit = new APIUtils.RateLimiter();
route.router.post("/auth", route.router.post("/auth",
@@ -140,7 +140,7 @@ route.router.post("/auth",
}, },
); );
const checkRateLimit = new APIUtils.RateLimiter(10, 3); const checkRateLimit = new APIUtils.RateLimiter();
route.router.get('/checkExpired', checkRateLimit.middle(), async (rq, rs) => { route.router.get('/checkExpired', checkRateLimit.middle(), async (rq, rs) => {
@@ -152,7 +152,7 @@ route.router.get('/checkExpired', checkRateLimit.middle(), async (rq, rs) => {
try { try {
const decodedToken = await decode<UserTokenFormat>(token, config.auth.secret, { algorithm: "HS512", leeway: 31536000 }); // 1 year leeway const decodedToken = await decode<UserTokenFormat>(token, config.auth.secret, { algorithm: "HS512", leeway: 31536000 }); // 1 year leeway
rs.json(decodedToken.exp < Math.round(Date.now() / 1000)); rs.json(decodedToken.exp < Math.round(Date.now() / 1000)); // check it manually
} catch { } catch {
rs.json(true); rs.json(true);
} }

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -44,7 +44,7 @@ export class SignalRSocketHandler {
#Targets: Map<string, SocketTarget> = new Map(); #Targets: Map<string, SocketTarget> = new Map();
#PresenceUpdateId: number; #PeriodicalId: number;
constructor(socket: WebSocket, player: Profile) { constructor(socket: WebSocket, player: Profile) {
@@ -57,9 +57,12 @@ export class SignalRSocketHandler {
this.#Targets.set('SubscribeToPlayers', new PlayerSocketSubscriptionTarget()); this.#Targets.set('SubscribeToPlayers', new PlayerSocketSubscriptionTarget());
this.#PresenceUpdateId = setInterval(async () => { this.#PeriodicalId = setInterval(async () => {
if (this.#socket.readyState !== this.#socket.CLOSED) {
const pres = await Presence.get(this.#profile); const pres = await Presence.get(this.#profile);
this.sendNotification("PresenceUpdate", await pres.export()); this.sendNotification("PresenceUpdate", await pres.export());
this.sendRaw({ type: 6 });
}
}, 8000); }, 8000);
} }
@@ -83,7 +86,7 @@ export class SignalRSocketHandler {
this.sendRaw({}); this.sendRaw({});
return; return;
} else { } else {
this.#log.d(`CLIENT MESSAGE\n Type: ${message.data.type} (${SignalMessageType[message.data.type]})\n ${JSON.stringify(message.data)}`); //this.#log.d(`CLIENT MESSAGE\n Type: ${message.data.type} (${SignalMessageType[message.data.type]})\n ${JSON.stringify(message.data)}`);
if (message.data.type == SignalMessageType.Invocation && message.data.invocationId) { // don't send completion messages for nonblocking invocations if (message.data.type == SignalMessageType.Invocation && message.data.invocationId) { // don't send completion messages for nonblocking invocations
const res = await this.#dispatchTarget(message.data.target, message.data.arguments[0]); // rec room only uses the first index const res = await this.#dispatchTarget(message.data.target, message.data.arguments[0]); // rec room only uses the first index
if (res.type == TargetResultType.Success) { if (res.type == TargetResultType.Success) {
@@ -145,18 +148,19 @@ export class SignalRSocketHandler {
destroy(sock: SignalRSocketHandler) { destroy(sock: SignalRSocketHandler) {
return () => { return () => {
clearInterval(sock.#PresenceUpdateId); clearInterval(sock.#PeriodicalId);
sock.sendRaw({ type: 7, error: "Socket closed" }); sock.sendRaw({ type: 7, error: "Socket closed" });
sock.#socket.close(); sock.#socket.close();
sock.#log.i(`Closed hub socket`); sock.#log.i(`Closed socket`);
sock.#profile.clearSocketHandler();
} }
} }
sendRaw(data: object) { sendRaw(data: object) {
this.#socket.send(`${JSON.stringify(data)}\u001e`); this.#socket.send(`${JSON.stringify(data)}\u001e`);
// todo sometime: make this less confusing // todo sometime: make the below less confusing
const type = `Type: ${JSON.stringify(data) == '{}' ? 'Protocol Message' : `${(data as SignalRMessage).type} (${SignalMessageType[(data as SignalRMessage).type]})`}`; //const type = `Type: ${JSON.stringify(data) == '{}' ? 'Protocol Message' : `${(data as SignalRMessage).type} (${SignalMessageType[(data as SignalRMessage).type]})`}`;
this.#log.d(`SERVER MESSAGE\n ${type}\n ${JSON.stringify(data as SignalRMessage)}`); //this.#log.d(`SERVER MESSAGE\n ${type}\n ${JSON.stringify(data as SignalRMessage)}`);
} }
sendNotification(id: PushNotificationId | string, args: object) { sendNotification(id: PushNotificationId | string, args: object) {

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
/* Galvanic Corrosion - Rec Room custom server for communities. /* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion> <https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify