This repository has been archived on 2026-03-19. You can view files and clone it, but cannot push or open issues or pull requests.
Files
galvanic-corrosion/src/data/content/room.ts
zombieb 3b6d905180 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
2025-04-13 01:06:23 -04:00

132 lines
6.9 KiB
TypeScript

/* 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 Rooms from "./rooms.ts";
import { IntegratedRoomScene, RoomAccessibility, RoomDetails, RoomState } from "./roomtypes.ts";
interface RoomFetchOptions {
roomName?: string,
roomId?: number
}
export function parseBooleanDefault(obj: string, def: boolean | undefined = false) {
try {
return JSON.parse(obj) as boolean;
} catch {
return def;
}
}
export class RoomFetch {
roomId: number | null = null;
roomName: string | null = null;
constructor(options: RoomFetchOptions) {
this.roomId = options.roomId ?? null;
this.roomName = options.roomName ?? null;
}
async fetch() {
if (!this.roomId && this.roomName) {
const givenId = await Rooms.getIdFromName(this.roomName);
if (!givenId) return null;
else this.roomId = givenId;
} else if (!this.roomName && this.roomId) {
const givenName = await Rooms.getNameFromId(this.roomId);
if (!givenName) return null;
else this.roomName = givenName;
} else if (!this.roomId && !this.roomName) return null;
const roomRootKey = Redis.buildKey(
Redis.KeyGroups.Rooms.Root,
this.roomId!.toString(), // code above takes care of null possibility
);
const roomMetaKey = Redis.buildKey(
roomRootKey,
Rooms.roomRootKeys.Meta
);
const [ hash, cheerCount, favoriteCount, visitCount ] = await Promise.all([
Redis.Database.hgetall(roomMetaKey),
Redis.Database.get(Redis.buildKey(roomRootKey, Rooms.roomRootKeys.CheerCount)),
Redis.Database.get(Redis.buildKey(roomRootKey, Rooms.roomRootKeys.FavoriteCount)),
Redis.Database.get(Redis.buildKey(roomRootKey, Rooms.roomRootKeys.VisitCount)),
]);
const room: RoomDetails = {
Room: {
RoomId: hash[Rooms.roomMetaKeys.RoomId] ? parseInt(hash[Rooms.roomMetaKeys.RoomId]) : 0,
Name: hash[Rooms.roomMetaKeys.Name] ?? "DATABASEERROR",
Description: hash[Rooms.roomMetaKeys.Description] ?? "DATABASEERROR",
CreatorPlayerId: hash[Rooms.roomMetaKeys.CreatorPlayerId] ? parseInt(hash[Rooms.roomMetaKeys.CreatorPlayerId]) : 1,
ImageName: hash[Rooms.roomMetaKeys.ImageName] ?? "DefaultProfileImage.png",
State: hash[Rooms.roomMetaKeys.State] ? parseInt(hash[Rooms.roomMetaKeys.State]) : RoomState.Active,
Accessibility: hash[Rooms.roomMetaKeys.Accessibility] ? parseInt(hash[Rooms.roomMetaKeys.Accessibility]) : RoomAccessibility.Unlisted,
SupportsLevelVoting: hash[Rooms.roomMetaKeys.SupportsLevelVoting] ? parseBooleanDefault(hash[Rooms.roomMetaKeys.SupportsLevelVoting], true) : true,
IsAGRoom: hash[Rooms.roomMetaKeys.IsAGRoom] ? parseBooleanDefault(hash[Rooms.roomMetaKeys.IsAGRoom], false) : false,
IsDormRoom: hash[Rooms.roomMetaKeys.IsDormRoom] ? parseBooleanDefault(hash[Rooms.roomMetaKeys.IsDormRoom], false) : false,
CloningAllowed: hash[Rooms.roomMetaKeys.CloningAllowed] ? parseBooleanDefault(hash[Rooms.roomMetaKeys.CloningAllowed], false) : false,
SupportsScreens: hash[Rooms.roomMetaKeys.SupportsScreens] ? parseBooleanDefault(hash[Rooms.roomMetaKeys.SupportsScreens], true) : true,
SupportsWalkVR: hash[Rooms.roomMetaKeys.SupportsWalkVR] ? parseBooleanDefault(hash[Rooms.roomMetaKeys.SupportsWalkVR], true) : true,
SupportsTeleportVR: hash[Rooms.roomMetaKeys.SupportsTeleportVR] ? parseBooleanDefault(hash[Rooms.roomMetaKeys.SupportsTeleportVR], true) : true,
AllowsJuniors: hash[Rooms.roomMetaKeys.AllowsJuniors] ? parseBooleanDefault(hash[Rooms.roomMetaKeys.AllowsJuniors], true) : true,
RoomWarningMask: hash[Rooms.roomMetaKeys.RoomWarningMask] ? parseInt(hash[Rooms.roomMetaKeys.RoomWarningMask]) : 0,
CustomRoomWarning: hash[Rooms.roomMetaKeys.CustomRoomWarning] ?? "",
DisableMicAutoMute: hash[Rooms.roomMetaKeys.DisableMicAutoMute] ? parseBooleanDefault(hash[Rooms.roomMetaKeys.DisableMicAutoMute], false) : undefined,
},
Scenes: [], // temporary
CoOwners: [], // temporary
InvitedCoOwners: [], // temporary
Hosts: [], // temporary
InvitedHosts: [], // temporary
CheerCount: cheerCount ? parseInt(cheerCount) : 0,
FavoriteCount: favoriteCount ? parseInt(favoriteCount) : 0,
VisitCount: visitCount ? parseInt(visitCount) : 0,
Tags: [] // temporary
}
const subrooms = await Rooms.getSubroomIdsFromRoom(this.roomId!);
for (const subroom of subrooms) {
const subroomMetaKey = Redis.buildKey(
Redis.KeyGroups.Rooms.Root,
this.roomId!.toString(),
Rooms.roomRootKeys.Subrooms,
subroom.toString(),
Rooms.subroomRootKeys.Meta
);
const subroomDetails = await Redis.Database.hgetall(subroomMetaKey);
room.Scenes.push({
RoomSceneId: parseInt(subroom),
RoomId: this.roomId ?? 0,
RoomSceneLocationId: subroomDetails[Rooms.subroomMetaKeys.RoomSceneLocationId] ?? IntegratedRoomScene.MakerRoom,
Name: subroomDetails[Rooms.subroomMetaKeys.Name] ?? "DATABASE ERROR",
IsSandbox: subroomDetails[Rooms.subroomMetaKeys.IsSandbox] ? parseBooleanDefault(subroomDetails[Rooms.subroomMetaKeys.IsSandbox], false) : false,
CanMatchmakeInto: subroomDetails[Rooms.subroomMetaKeys.IsSandbox] ? parseBooleanDefault(subroomDetails[Rooms.subroomMetaKeys.IsSandbox], true) : undefined,
DataBlobName: subroomDetails[Rooms.subroomMetaKeys.DataBlobName] ?? "",
MaxPlayers: subroomDetails[Rooms.subroomMetaKeys.MaxPlayers] ? parseInt(subroomDetails[Rooms.subroomMetaKeys.MaxPlayers]) : 1,
DataModifiedAt: subroomDetails[Rooms.subroomMetaKeys.DataModifiedAt] ?? new Date().toISOString()
});
}
return room;
}
}