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
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)
This program is free software: you can redistribute it and/or modify

View File

@@ -3,7 +3,7 @@
delectable yum yum
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"/>

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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -131,11 +131,11 @@ export function genericResponse(
};
}
type RecNetResponse = {
Success: boolean;
Message: string;
success: boolean;
error?: string;
};
export function RecNetResponse(success: boolean, message: string) {
const msg: RecNetResponse = { Success: success, Message: message };
export function RecNetResponse(success: boolean, message?: string) {
const msg: RecNetResponse = { success: success, error: message };
return (_rq: express.Request, rs: express.Response) => {
rs.json(msg);
};
@@ -190,7 +190,7 @@ export class RateLimiter {
* @param interval In seconds: rate at which hit counts will be cleared
* @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.#intervalId = setInterval(() => {
@@ -224,6 +224,11 @@ export class RateLimiter {
nxt: express.NextFunction,
) => {
const address = getSrcIpDefault(rq);
if (address == '127.0.0.1' || address == '::1') {
nxt();
return;
}
this.#addressIncrement(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) {
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);
if (matches == null) {
rs.json(genericResponseFormat(true, "Login Lock failure"));

View File

@@ -1,5 +1,5 @@
/* 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)
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 * 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");
@@ -49,7 +49,7 @@ type PublicConfiguration = {
levelScale: number;
maxLevels: number;
patches: string[];
photonRegionId: PhotonRegionCodeString;
photonRegionId: PhotonRegionCodeString | PhotonRegionCodeNumber;
};
type LoggingConfiguration = {
@@ -111,7 +111,7 @@ export const defaultConfig: GalvanicConfiguration = {
levelScale: 1,
maxLevels: 30,
patches: [],
photonRegionId: PhotonRegionCodeString.UnitedStates,
photonRegionId: PhotonRegionCodeNumber.us,
},
logging: {
notfound: false,

View File

@@ -1,5 +1,5 @@
/* 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)
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 { Objectives } from "./objectives.ts";
export type Config = {
Key: string;
Value: string;
};
export type LevelProgressionItem = {
Level: number;
RequiredXp: number;
@@ -38,13 +34,13 @@ export type AutoMicMutingConfig = {
MicSpamWarningStateVolumeMultiplier: number
}
export type PublicConfig = {
ShareBaseUrl: string
ServerMaintenance: {
StartsInMinutes: number;
};
LevelProgressionMaps: LevelProgressionItem[];
DailyObjectives: Objectives.Objective[][];
ConfigTable: Config[];
AutoMicMutingConfig: AutoMicMutingConfig
AutoMicMutingConfig: AutoMicMutingConfig,
};
/**
@@ -72,7 +68,6 @@ export function getConfig() {
},
LevelProgressionMaps: generateLevelProgressionMap(),
DailyObjectives: [],
ConfigTable: [],
AutoMicMutingConfig: {
MicSpamVolumeThreshold: 1.125,
MicVolumeSampleInterval: 0.25,
@@ -82,7 +77,8 @@ export function getConfig() {
MicSpamSamplePercentageForForceMute: 0.8,
MicSpamSamplePercentageForForceMuteToEnd: 0.2,
MicSpamWarningStateVolumeMultiplier: 0.25
}
},
ShareBaseUrl: `${config.web.api.securepublichost ? 'https' : 'http'}://${config.web.api.publichost}/{0}` // {0} is replaced by the game
};
return conf;

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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 { 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 { Profile } from "../profiles.ts";
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);
}
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(
Redis.KeyGroups.Rooms.Root,
roomid.toString(),
@@ -183,22 +183,21 @@ class RoomsBase {
try {
canBeCloned = JSON.parse(canBeClonedRaw) as boolean;
} catch {
log.d(`Cloneroom ${roomid}: parse error`);
return null;
}
if (!canBeCloned) {
log.d(`Cloneroom ${roomid}: cannot be cloned`);
return null;
}
if (!canBeCloned) return null;
const beforeRoom = await Rooms.get(roomid); // room must exist
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();
beforeRoom.Room.CreatorPlayerId = newowner.getId();
beforeRoom.Room.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);
return beforeRoom;
@@ -211,19 +210,19 @@ class RoomsBase {
Redis.KeyGroups.Rooms.PlayerDorms
), player.getId().toString());
if (unparsedId) {
log.d(`Unparsed dorm ID for profile ${player.getId()}: ${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");
log.d('Base dorm 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');
const newDorm = await this.generateNewDorm(player);
await this.#setRoom(newDorm);
log.d(`New dorm for ${player.getId()} existed`);
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(
Redis.KeyGroups.Rooms.Root,
Redis.KeyGroups.Rooms.PlayerDorms
@@ -231,10 +230,59 @@ class RoomsBase {
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() {
if ((await Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Rooms.Root, this.miscKeys.BuiltinGenerated))) !== null) return true;
for (const builtinRoom of rooms) {
if (builtinRoom.Name == 'DormRoom') continue;
const newId = await this.#getAvailableRoomId();
await Redis.Database.sadd(Redis.buildKey(Redis.KeyGroups.Rooms.Root, this.miscKeys.AGRooms), newId);
const roomDets: RoomDetails = {
@@ -320,6 +368,11 @@ class RoomsBase {
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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 {
PlayerStatusVisibility = "PlayerStatusVisibility",
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 {
PlayerStatusVisibility = "1",
VRMovementMode = "0"
PlayerStatusVisibility = "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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -28,4 +28,23 @@ export enum StorefrontTypes {
Bowling = 500,
StuntRunner = 600,
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -66,6 +66,7 @@ class MatchmakingBase {
else if (instance.isPrivate) return { errorCode: MatchmakingErrorCode.RoomInstanceIsPrivate };
await Instances.setPlayerInstance(options.profile, instance);
Instances.clearAllRoomEmptyInstances(instance.roomId);
return { errorCode: MatchmakingErrorCode.Success, roomInstance: instance };
}
@@ -73,35 +74,76 @@ class MatchmakingBase {
} 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);
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 };
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);
const subroomId = targetRoom.Scenes.find(scene => scene.Name == options.subRoomName)?.RoomSceneId;
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) {
const matchmakeableSubrooms = targetRoom.Scenes.filter(scene => scene.CanMatchmakeInto);
const newInstance = Instances.createInstance({
const newInstance = await Instances.createInstance({
Room: targetRoom,
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 };
} else {
const currentInstance = options.profile.getInstance();
if (currentInstance?.roomInstanceId == foundInstance.roomInstanceId)
return { errorCode: MatchmakingErrorCode.AlreadyInBestInstance };
await Instances.setPlayerInstance(options.profile, foundInstance);
Instances.clearAllRoomEmptyInstances(roomId);
return { errorCode: MatchmakingErrorCode.Success, roomInstance: foundInstance };
}
}
}

View File

@@ -1,5 +1,5 @@
/* 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)
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/>. */
import Logging from "@proxnet/undead-logging";
import { Profile } from "../profiles.ts";
import UnifiedProfile, { Profile } from "../profiles.ts";
import { RoomInstance, InstanceOptions } from "./types.ts";
import { Config } from "../../config.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.
*/
createInstance(options: InstanceOptions) {
async createInstance(options: InstanceOptions) {
const scene = options.Room.Scenes[options.SceneIndex];
const newId = this.#generateUniqueInstanceId();
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 = {
roomInstanceId: newId,
roomId: options.Room.Room.RoomId,
subRoomId: scene.RoomSceneId,
location: scene.RoomSceneLocationId,
dataBlob: scene.DataBlobName == "" ? undefined : scene.DataBlobName,
dataBlob: scene.DataBlobName,
eventId: options.EventId,
photonRegionId: config.public.photonRegionId,
photonRoomId: `20191120-GC${newId}`,
name: scene.Name === "Home" ? `^${options.Room.Room.Name}` : `^${options.Room.Room.Name}.${scene.Name}`,
photonRoomId: `20200306-GC${newId}`,
name: instanceName,
maxCapacity: scene.MaxPlayers,
isFull: false,
isPrivate: typeof options.Private !== 'boolean' ? false : options.Private,
@@ -161,7 +167,9 @@ class InstancesBase {
}
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);
const pres = await Presence.get(player);

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -58,7 +58,7 @@ export interface RoomInstance {
location: string,
dataBlob?: string,
eventId?: number,
photonRegionId: PhotonRegionCodeString,
photonRegionId: PhotonRegionCodeString | PhotonRegionCodeNumber,
photonRoomId: string,
name?: string,
maxCapacity: number,
@@ -75,7 +75,8 @@ export interface InstanceOptions {
EventId?: number,
Name?: string,
Private?: boolean,
FirstPlayer?: Profile
FirstPlayer?: Profile,
IsDorm?: boolean
}

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -24,4 +24,14 @@ export enum PlatformMask {
HeadlessBot = 16,
IOS = 32,
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -21,6 +21,10 @@ export class ProfileContentManager {
this.profileId = profileId;
}
onProfileInit() {
return;
}
profileId: number;
}

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -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/>. */
import { Redis } from "../../db.ts";
import { SettingKey } from "../content/settings.ts";
import { SettingKey, SettingDefault } from "../content/settings.ts";
import { ProfileContentManager } from "./base/profilemanagerbase.ts";
export interface Setting {
@@ -26,6 +26,14 @@ export interface Setting {
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() {
const settings = await Redis.Database.hgetall(Redis.buildKey(Redis.KeyGroups.Profiles.Root, this.profileId.toString(), Redis.KeyGroups.Profiles.Settings));
const returnSettings: Setting[] = [];

View File

@@ -1,5 +1,5 @@
/* 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)
This program is free software: you can redistribute it and/or modify
@@ -140,7 +140,11 @@ class Profile {
newUsername,
);
return new Profile(newId);
const profile = new Profile(newId);
profile.Settings.onProfileInit();
return profile;
}
// surely this can be written better
@@ -164,7 +168,7 @@ class Profile {
platforms: 1,
username: values[2] == null ? "DATABASEERROR" : values[2],
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() {
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;
}
@@ -302,7 +306,7 @@ class Profile {
sub: this.#id,
role: (await this.getIsOperator()) ? 'developer' : 'user',
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" });
}
@@ -335,6 +339,15 @@ class UnifiedProfileBase {
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();

View File

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

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -76,6 +76,7 @@ export const KeyGroups = {
},
Profile_Usernames: "profile-usernames",
PlatformAssociations: "platforms",
AddressBans: "address-bans",
Profiles: {
Root: "profiles",
Username: "username",
@@ -87,6 +88,7 @@ export const KeyGroups = {
DeviceClass: "deviceClass",
Xp: "xp",
Bio: "bio",
Rooms: "rooms",
Relationships: {
Root: "relationships",
IncomingFriendRequests: "incomingFriendRequests",

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -28,6 +28,7 @@ import UnifiedProfile, { ProfileTokenFormat } from "./data/profiles.ts";
import { SocketHandoff } from "./socket/handoff.ts";
import { SignalRSocketHandler } from "./socket/socket.ts";
import Rooms from "./data/content/rooms.ts";
import { GameConfigs } from "./data/config.ts";
const instanceId = generateRandomString(64);
@@ -114,10 +115,6 @@ if (!(await Rooms.generateBuiltinRooms())) log.i(`Generated built-in rooms`);
try {
/**
* Galvanic WebSocket Server
*/
type AuthResultBase = {
valid: boolean
}
@@ -133,10 +130,13 @@ try {
const authHeader = req.headers.get('authorization');
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;
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);
if (!schemaResult.success) return { valid: false } as AuthResult;
else return { token: decodedToken, valid: true } as AuthResult;
@@ -149,6 +149,14 @@ try {
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
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}`);
@@ -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("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 => {

View File

@@ -1,5 +1,5 @@
/* 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)
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 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(ParentalControlRoute.path, ParentalControlRoute.router);

View File

@@ -1,5 +1,5 @@
/* 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)
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 UnifiedProfile, { Profile } from "../../data/profiles.ts";
import { z } from "zod";
import { AuthType } from "../../data/users.ts";
export const route = APIUtils.createRouter("/account");
@@ -28,7 +29,7 @@ const CreateAccountRequestBodySchema = z.object({
deviceId: z.string()
});
const rateLimit = new APIUtils.RateLimiter(25, 5);
const rateLimit = new APIUtils.RateLimiter();
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 {
id?: string
}

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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/>. */
import { APIUtils } from "../../apiutils.ts";
import { AuthType } from "../../data/users.ts";
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -20,7 +20,7 @@ import { GameConfigs } from "../../data/config.ts";
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) => {
const config = GameConfigs.getConfig();

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -27,4 +27,4 @@ route.router.get('/v2/getUnlocked',
APIUtils.emptyArrayResponse
)
);

View File

@@ -1,5 +1,5 @@
/* 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)
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/>. */
import { APIUtils } from "../../apiutils.ts";
import { GameConfigs } from "../../data/config.ts";
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -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
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 express from "express";
export const route = APIUtils.createRouter('/objectives');
@@ -32,4 +34,28 @@ 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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -38,4 +38,16 @@ route.router.get('/v1/:id',
rs.json(await UnifiedProfile.get(parsedPlayerId).Reputation.getReputation());
}
);
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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 express from "express";
import UnifiedProfile from "../../data/profiles.ts";
import { AuthType } from "../../data/users.ts";
const log = new Logging("ProgressionRoute");
const rateLimit = new APIUtils.RateLimiter(60, 2);
const rateLimit = new APIUtils.RateLimiter();
export const route = APIUtils.createRouter("/players");
@@ -48,4 +49,15 @@ route.router.get('/v1/progression/:id',
rs.json(res);
}
);
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
This program is free software: you can redistribute it and/or modify
@@ -66,7 +66,7 @@ route.router.get('/v1/hot',
async (_rq, rs) => {
// temporary: return all public AG rooms for testing
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());
if (!room || rq.params.name == 'DormRoom') {
rs.sendStatus(404);
if (room) {
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;
} else {
rs.json(room.Room);
rs.sendStatus(404);
return;
}
},
@@ -118,4 +123,4 @@ route.router.post('/v1/roomRolePermissions',
rs.sendStatus(200);
},
);
);

View File

@@ -1,5 +1,5 @@
/* 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)
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) => {
rs.locals.profile.Settings.setSettingRaw(rq.body.Key, rq.body.Value),
rs.json({
Succeeded: true,
Error: "",
ShouldRetry: false
});
rs.sendStatus(200);
log.d(`${rs.locals.profile.getId()} set settings key '${rq.body.Key}' to '${rq.body.Value}'`);
}
);

View File

@@ -1,5 +1,5 @@
/* 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)
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 express from "express";
import { AuthType } from "../../data/users.ts";
import { CurrencyType, StorefrontBalanceType } from "../../data/content/storefronts.ts";
export const route = APIUtils.createRouter('/storefronts');
@@ -26,6 +28,7 @@ interface StorefrontFetchParams {
route.router.get('/v3/giftdropstore/:id',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
(rq: express.Request<StorefrontFetchParams>, rs: express.Response) => {
if (!rq.params.id) {
@@ -39,4 +42,28 @@ 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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -19,7 +19,9 @@ import { APIUtils } from "../../apiutils.ts";
export const route = APIUtils.createRouter("/versioncheck");
const validVersion = "20191120";
export const validVersions = [
"20200306"
];
enum VersionStatus {
ValidForPlay,
@@ -35,10 +37,10 @@ route.router.get("/v4", (rq, rs) => {
const requestedVer = rq.query["v"];
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.json(APIUtils.genericResponseFormat(true, "One or more query parameters were not found."));
} else if (requestedVer !== validVersion) {
rs.json(APIUtils.genericResponseFormat(true, "One or more query parameters were not found or invalid."));
} else if (!validVersions.includes(requestedVer as string)) {
const res: ValidVersionResponse = {
VersionStatus: VersionStatus.UpdateRequired,
};

View File

@@ -1,5 +1,5 @@
/* 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)
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 { route as CachedLoginRoute } from "./auth/cachedlogin.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(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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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 { AuthType } from "../../data/users.ts";
import { Redis } from "../../db.ts";
import { validVersions } from "../api/versioncheck.ts";
const config = Config.getConfig();
@@ -116,7 +117,7 @@ route.router.post("/token",
const conditionsMet = ![
rq.body.client_id === "recroom",
rq.body.platform === "0",
rq.body.ver === '20191120',
validVersions.includes(rq.body.ver),
rq.body.device_class.length === 1,
!isNaN(Number(rq.body.device_class)),
!(rq.body.device_id.length > 96),

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
This program is free software: you can redistribute it and/or modify
@@ -36,6 +36,7 @@ interface ImageQueryOptions {
cropSquare?: string;
width?: string;
height?: string;
sig?: string;
}
route.router.get(
@@ -49,8 +50,6 @@ route.router.get(
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;
const imageSource = baseImages.includes(filename)
? BaseImages.getBaseImage(filename)
@@ -80,6 +79,23 @@ route.router.get(
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) {
const targetWidth = width > image.width ? image.width : width;
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 (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()));
},
);

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -35,8 +35,9 @@ route.router.post('/room/:roomName',
APIUtils.Authentication,
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) {
log.d('Matchmake failed: No room specified');
rs.json({
@@ -45,22 +46,30 @@ route.router.post('/room/:roomName',
return;
}
rs.json(await Matchmaking.matchmake({ profile: rs.locals.profile, roomName: rq.params.roomName }));
nxt();
},
APIUtils.stopTimer
);
route.router.post('/room/:roomName/:subRoomName',
APIUtils.Authentication,
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) {
log.d('Matchmake failed: No room specified');
rs.json({
errorCode: MatchmakingErrorCode.NoSuchRoom
});
return;
}
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -25,6 +25,7 @@ import Logging from "@proxnet/undead-logging";
import UnifiedProfile from "../../data/profiles.ts";
import { PlayerStatusVisibility, VRMovementMode } from "../../data/live/types.ts";
import { SettingKey } from "../../data/content/settings.ts";
import Instances from "../../data/live/instances.ts";
const log = new Logging("MatchPlayerRoute");
@@ -85,7 +86,7 @@ route.router.post('/logout',
APIUtils.validateRequestBody(LoginSchema),
(_rq, rs) => {
Matchmaking.deleteLoginLock(rs.locals.profile);
Instances.removePlayerFromCurrentInstance(rs.locals.profile);
rs.sendStatus(200);
}
@@ -110,14 +111,14 @@ interface StatusVisibilityBody {
statusVisibility: PlayerStatusVisibility
}
const StatusVisibilitySchema = z.object({
statusVisibility: z.nativeEnum(PlayerStatusVisibility)
statusVisibility: z.enum(Object.values(PlayerStatusVisibility).map(String) as [string, ...string[]])
});
route.router.put('/statusvisibility',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
express.urlencoded({ extended: true }),
APIUtils.logBody,
APIUtils.validateRequestBody(StatusVisibilitySchema),
async (rq: express.Request<NoBody, NoBody, StatusVisibilityBody>, rs: express.Response) => {
@@ -148,4 +149,15 @@ route.router.put('/vrmovementmode',
rs.sendStatus(200);
},
);
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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");
type NameserverHosts = {
Accounts: string;
Auth: string;
API: string;
WWW: string;
@@ -38,6 +39,7 @@ type NameserverHosts = {
};
const nameserver: NameserverHosts = {
Accounts: `${protocol}://${config.web.api.publichost}/accounts`,
Auth: `${protocol}://${config.web.api.publichost}/auth`,
API: `${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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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
@@ -57,7 +57,7 @@ const AuthRequestRootSchema = z.object({
pubkey: z.string(),
});
const rateLimit = new APIUtils.RateLimiter(60, 2);
const rateLimit = new APIUtils.RateLimiter();
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) => {
@@ -152,7 +152,7 @@ route.router.get('/checkExpired', checkRateLimit.middle(), async (rq, rs) => {
try {
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 {
rs.json(true);
}

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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();
#PresenceUpdateId: number;
#PeriodicalId: number;
constructor(socket: WebSocket, player: Profile) {
@@ -57,9 +57,12 @@ export class SignalRSocketHandler {
this.#Targets.set('SubscribeToPlayers', new PlayerSocketSubscriptionTarget());
this.#PresenceUpdateId = setInterval(async () => {
const pres = await Presence.get(this.#profile);
this.sendNotification("PresenceUpdate", await pres.export());
this.#PeriodicalId = setInterval(async () => {
if (this.#socket.readyState !== this.#socket.CLOSED) {
const pres = await Presence.get(this.#profile);
this.sendNotification("PresenceUpdate", await pres.export());
this.sendRaw({ type: 6 });
}
}, 8000);
}
@@ -83,7 +86,7 @@ export class SignalRSocketHandler {
this.sendRaw({});
return;
} 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
const res = await this.#dispatchTarget(message.data.target, message.data.arguments[0]); // rec room only uses the first index
if (res.type == TargetResultType.Success) {
@@ -145,18 +148,19 @@ export class SignalRSocketHandler {
destroy(sock: SignalRSocketHandler) {
return () => {
clearInterval(sock.#PresenceUpdateId);
clearInterval(sock.#PeriodicalId);
sock.sendRaw({ type: 7, error: "Socket closed" });
sock.#socket.close();
sock.#log.i(`Closed hub socket`);
sock.#log.i(`Closed socket`);
sock.#profile.clearSocketHandler();
}
}
sendRaw(data: object) {
this.#socket.send(`${JSON.stringify(data)}\u001e`);
// todo sometime: make this less confusing
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)}`);
// todo sometime: make the below less confusing
//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)}`);
}
sendNotification(id: PushNotificationId | string, args: object) {

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
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.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
<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

View File

@@ -1,5 +1,5 @@
/* 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)
This program is free software: you can redistribute it and/or modify