build config changes
All checks were successful
Galvanic Corrosion Cross-Compile / build (push) Successful in 1m50s
All checks were successful
Galvanic Corrosion Cross-Compile / build (push) Successful in 1m50s
* Commit hash shipped with builds
* Post & pre-build events
* Objective fixes
* Orientation challenge filler
* Custom Rooms base
- Currently cannot save rooms (CDN not set up)
* Moved root path to path.ts
* Room cloning
* Rewrote instances - the whole thing
* Relationships are still untested
* Charades Words
* AG Room fetch
* Private room matchmaking
* Socket fixes
This commit is contained in:
2
LICENSE
2
LICENSE
@@ -623,7 +623,7 @@ copy of the Program in return for a fee.
|
|||||||
|
|
||||||
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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
# Galvanic Corrosion
|
# Galvanic Corrosion
|
||||||
|
|
||||||
delectable yum yum
|
delectable yum yum<br>
|
||||||
|
|
||||||
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 1063 (Timestamp: 637191339113673856, Version: 20200306)
|
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"/><br>
|
||||||
|
Photo taken by Nick Gromicko, CMI®
|
||||||
|
|
||||||
# Disclaimer
|
# Disclaimer
|
||||||
Galvanic Corrosion and its contributors are **not** associated in **any** form with:
|
Galvanic Corrosion and its contributors are **not** associated in **any** form with:
|
||||||
* RecNet ("the RecNet platform")
|
|
||||||
* Rec Room, Inc.
|
* Rec Room, Inc.
|
||||||
* Exit Games Inc.
|
|
||||||
* Against Gravity
|
* Against Gravity
|
||||||
* Photon Network, Photon Engine, or services associated
|
* Exit Games Inc.
|
||||||
* Any person(s) in contact with or employed for or with Rec Room Inc.
|
* Any person(s) in contact with or employed for or with Rec Room Inc.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|||||||
15
deno.json
15
deno.json
@@ -1,9 +1,13 @@
|
|||||||
{
|
{
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"compile-win": "deno compile --include res --include src --target x86_64-pc-windows-msvc -o build/GalvanicCorrosion.exe -A src/main.ts",
|
"compile-win-a": "deno compile --include res --include src --target x86_64-pc-windows-msvc -o build/GalvanicCorrosion.exe -A src/main.ts",
|
||||||
"compile-linux": "deno compile --include res --include src --target x86_64-unknown-linux-gnu -o build/GalvanicCorrosion -A src/main.ts",
|
"compile-linux-a": "deno compile --include res --include src --target x86_64-unknown-linux-gnu -o build/GalvanicCorrosion -A src/main.ts",
|
||||||
"cross-compile": "deno run compile-win && deno run compile-linux",
|
"compile-win": "deno run prebuild && deno run compile-win-a && deno run postbuild",
|
||||||
"dev": "deno run -A src/main.ts --dev"
|
"compile-linux": "deno run prebuild && deno run compile-linux-a && deno run postbuild",
|
||||||
|
"cross-compile": "deno run prebuild && deno run compile-win-a && deno run compile-linux-a && deno run postbuild",
|
||||||
|
"dev": "deno run -A src/main.ts --dev",
|
||||||
|
"prebuild": "deno run -A ./prebuild.ts",
|
||||||
|
"postbuild": "deno run -A ./postbuild.ts"
|
||||||
},
|
},
|
||||||
"imports": {
|
"imports": {
|
||||||
"@gz/jwt": "jsr:@gz/jwt@^0.1.0",
|
"@gz/jwt": "jsr:@gz/jwt@^0.1.0",
|
||||||
@@ -28,5 +32,6 @@
|
|||||||
"./src/types/express.ts",
|
"./src/types/express.ts",
|
||||||
"./src/types/http.ts"
|
"./src/types/http.ts"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"version": "0.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
24
postbuild.ts
Normal file
24
postbuild.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/* 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/>. */
|
||||||
|
|
||||||
|
try {
|
||||||
|
Deno.removeSync('./ver.ts');
|
||||||
|
Deno.renameSync('./ver.ts.bak', 'ver.ts');
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Cannot post-build version information: ${err}`);
|
||||||
|
Deno.exit(1);
|
||||||
|
}
|
||||||
38
prebuild.ts
Normal file
38
prebuild.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/* 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/>. */
|
||||||
|
|
||||||
|
interface DenoProj {
|
||||||
|
version: string
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const file = JSON.parse(Deno.readTextFileSync('./deno.json').toString()) as DenoProj;
|
||||||
|
|
||||||
|
const devVer = Deno.readTextFileSync('./ver.ts');
|
||||||
|
const commitHash = new Deno.Command("git", { args: ["rev-parse", "--short=12", "HEAD"] }).outputSync();
|
||||||
|
|
||||||
|
const newVerString = `${file.version}-${new TextDecoder().decode(commitHash.stdout).trim()}`;
|
||||||
|
|
||||||
|
if (file.version) {
|
||||||
|
Deno.writeTextFileSync('./ver.ts.bak', devVer);
|
||||||
|
Deno.writeTextFileSync('./ver.ts', devVer.replace('development', newVerString));
|
||||||
|
console.info('Built version information');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Cannot build version information: ${err}`);
|
||||||
|
Deno.exit(1);
|
||||||
|
}
|
||||||
262
res/words.json
Normal file
262
res/words.json
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
{
|
||||||
|
"easy": [
|
||||||
|
"Bike",
|
||||||
|
"Light",
|
||||||
|
"Jacket",
|
||||||
|
"Butterfly",
|
||||||
|
"Orange",
|
||||||
|
"Triangle",
|
||||||
|
"Lemon",
|
||||||
|
"Crab",
|
||||||
|
"Alligator",
|
||||||
|
"Shoe",
|
||||||
|
"Purse",
|
||||||
|
"Leg",
|
||||||
|
"Neck",
|
||||||
|
"Starfish",
|
||||||
|
"Box",
|
||||||
|
"Backpack",
|
||||||
|
"House",
|
||||||
|
"Duck",
|
||||||
|
"Skateboard",
|
||||||
|
"Cupcake",
|
||||||
|
"Hamburger",
|
||||||
|
"Owl",
|
||||||
|
"Cup",
|
||||||
|
"Hand",
|
||||||
|
"Smile",
|
||||||
|
"Curl",
|
||||||
|
"Hippo",
|
||||||
|
"Turtle",
|
||||||
|
"Truck",
|
||||||
|
"Beach",
|
||||||
|
"Ocean",
|
||||||
|
"Pants",
|
||||||
|
"Lips",
|
||||||
|
"Drum",
|
||||||
|
"Dragon",
|
||||||
|
"Egg",
|
||||||
|
"Fish",
|
||||||
|
"Desk",
|
||||||
|
"Mouth",
|
||||||
|
"Feather",
|
||||||
|
"Grapes",
|
||||||
|
"Zoo",
|
||||||
|
"Bathroom",
|
||||||
|
"Bus",
|
||||||
|
"Shirt",
|
||||||
|
"Grass",
|
||||||
|
"Snail",
|
||||||
|
"Ice Cream Cone",
|
||||||
|
"Snake",
|
||||||
|
"Arm",
|
||||||
|
"Cookie",
|
||||||
|
"Table",
|
||||||
|
"Dinosaur",
|
||||||
|
"Dream",
|
||||||
|
"Frog",
|
||||||
|
"Ant",
|
||||||
|
"Sheep",
|
||||||
|
"Boat",
|
||||||
|
"Baby",
|
||||||
|
"Bowl",
|
||||||
|
"Banana",
|
||||||
|
"Pig",
|
||||||
|
"Dog",
|
||||||
|
"Ants",
|
||||||
|
"Corn",
|
||||||
|
"Coat",
|
||||||
|
"Slide",
|
||||||
|
"Comb",
|
||||||
|
"Bug",
|
||||||
|
"Pizza",
|
||||||
|
"Plant",
|
||||||
|
"Pencil",
|
||||||
|
"Key",
|
||||||
|
"Cloud",
|
||||||
|
"Lamp",
|
||||||
|
"Balloon",
|
||||||
|
"Robot",
|
||||||
|
"Chimney",
|
||||||
|
"Motorcycle",
|
||||||
|
"Bounce",
|
||||||
|
"Square",
|
||||||
|
"Pie",
|
||||||
|
"Swimming Pool",
|
||||||
|
"Bumblebee",
|
||||||
|
"Flower",
|
||||||
|
"Lollipop",
|
||||||
|
"Bird",
|
||||||
|
"King",
|
||||||
|
"Jellyfish",
|
||||||
|
"Bone",
|
||||||
|
"Island",
|
||||||
|
"Moon",
|
||||||
|
"Seashell",
|
||||||
|
"Nail",
|
||||||
|
"Bunk Bed",
|
||||||
|
"Jail",
|
||||||
|
"Ring",
|
||||||
|
"Family",
|
||||||
|
"Airplane",
|
||||||
|
"Earth",
|
||||||
|
"Hair",
|
||||||
|
"Snowman",
|
||||||
|
"Car",
|
||||||
|
"Hook",
|
||||||
|
"Sea",
|
||||||
|
"Pen",
|
||||||
|
"Diamond",
|
||||||
|
"Spoon",
|
||||||
|
"Kite",
|
||||||
|
"Woman",
|
||||||
|
"Socks",
|
||||||
|
"Mouse",
|
||||||
|
"Cube",
|
||||||
|
"Finger",
|
||||||
|
"Lizard",
|
||||||
|
"Angel",
|
||||||
|
"Mickey Mouse",
|
||||||
|
"Spider",
|
||||||
|
"Mountain",
|
||||||
|
"Branch",
|
||||||
|
"Spider Web",
|
||||||
|
"Ship",
|
||||||
|
"Bunny",
|
||||||
|
"Face",
|
||||||
|
"Music",
|
||||||
|
"Bell",
|
||||||
|
"Rainbow",
|
||||||
|
"Star"
|
||||||
|
],
|
||||||
|
"hard": [
|
||||||
|
"Parent",
|
||||||
|
"Concession Stand",
|
||||||
|
"Tablespoon",
|
||||||
|
"Puppet",
|
||||||
|
"Gold",
|
||||||
|
"Mirror",
|
||||||
|
"Nanny",
|
||||||
|
"Irrigation",
|
||||||
|
"Humidity",
|
||||||
|
"Postcard",
|
||||||
|
"Musician",
|
||||||
|
"Chairman",
|
||||||
|
"Human",
|
||||||
|
"Barber",
|
||||||
|
"Judge",
|
||||||
|
"Jedi",
|
||||||
|
"Customer",
|
||||||
|
"Fur",
|
||||||
|
"Punk",
|
||||||
|
"Elf",
|
||||||
|
"Sled",
|
||||||
|
"Vitamin",
|
||||||
|
"Print",
|
||||||
|
"Internet",
|
||||||
|
"Swarm",
|
||||||
|
"Zoo",
|
||||||
|
"Shelter",
|
||||||
|
"Blizzard",
|
||||||
|
"Dust Bunny",
|
||||||
|
"Printer Ink",
|
||||||
|
"Oxcart",
|
||||||
|
"Carat",
|
||||||
|
"Black Belt",
|
||||||
|
"Fireman Pole",
|
||||||
|
"Darkness",
|
||||||
|
"Carpenter",
|
||||||
|
"Coach",
|
||||||
|
"Back Flip",
|
||||||
|
"Extension Cord",
|
||||||
|
"Flu",
|
||||||
|
"Telephone Booth",
|
||||||
|
"Country",
|
||||||
|
"Sticky Note",
|
||||||
|
"Traffic Jam",
|
||||||
|
"Science",
|
||||||
|
"Wooly Mammoth",
|
||||||
|
"Captain",
|
||||||
|
"Driveway",
|
||||||
|
"Mysterious",
|
||||||
|
"Dew",
|
||||||
|
"Injury",
|
||||||
|
"Sunburn",
|
||||||
|
"Grandpa",
|
||||||
|
"Ceiling Fan",
|
||||||
|
"Cruise",
|
||||||
|
"Chime",
|
||||||
|
"Accounting",
|
||||||
|
"Hour",
|
||||||
|
"End Zone",
|
||||||
|
"Miner",
|
||||||
|
"Government",
|
||||||
|
"Lunar Rover",
|
||||||
|
"Pro",
|
||||||
|
"Date",
|
||||||
|
"Police",
|
||||||
|
"Fireside",
|
||||||
|
"Hand Soap",
|
||||||
|
"Ditch",
|
||||||
|
"Expert",
|
||||||
|
"Fade",
|
||||||
|
"Nap",
|
||||||
|
"Last",
|
||||||
|
"Hot Tub",
|
||||||
|
"Loveseat",
|
||||||
|
"Braid",
|
||||||
|
"Rodeo",
|
||||||
|
"Coastline",
|
||||||
|
"Molar",
|
||||||
|
"Drugstore",
|
||||||
|
"Tow Truck",
|
||||||
|
"Pickup Truck",
|
||||||
|
"Shrink Ray",
|
||||||
|
"Crane",
|
||||||
|
"Bedbug",
|
||||||
|
"Beluga Whale",
|
||||||
|
"Fiance",
|
||||||
|
"Fizz",
|
||||||
|
"Junk",
|
||||||
|
"Yolk",
|
||||||
|
"Photosynthesis",
|
||||||
|
"Wobble",
|
||||||
|
"Hairspray",
|
||||||
|
"Crop Duster",
|
||||||
|
"Recycle",
|
||||||
|
"Script",
|
||||||
|
"Vein",
|
||||||
|
"Jaw",
|
||||||
|
"Thaw",
|
||||||
|
"Goalkeeper",
|
||||||
|
"Optometrist",
|
||||||
|
"Shower Curtain",
|
||||||
|
"Cowboy",
|
||||||
|
"Tide",
|
||||||
|
"Quadrant",
|
||||||
|
"Bride",
|
||||||
|
"Pile",
|
||||||
|
"Midnight",
|
||||||
|
"Amusement Park",
|
||||||
|
"Orbit",
|
||||||
|
"Goblin",
|
||||||
|
"Bonnet",
|
||||||
|
"Snore",
|
||||||
|
"Cape",
|
||||||
|
"Truck Stop",
|
||||||
|
"Ginger",
|
||||||
|
"Hermit Crab",
|
||||||
|
"Safe",
|
||||||
|
"Jungle",
|
||||||
|
"Student",
|
||||||
|
"Headache",
|
||||||
|
"Scuba Diving",
|
||||||
|
"Neighborhood",
|
||||||
|
"Bookend",
|
||||||
|
"Crow's Nest",
|
||||||
|
"Plantation",
|
||||||
|
"Owner",
|
||||||
|
"Stuffed Animal",
|
||||||
|
"Gown"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|||||||
|
|
||||||
import { Config } from "../config.ts";
|
import { Config } from "../config.ts";
|
||||||
import { Redis } from "../db.ts";
|
import { Redis } from "../db.ts";
|
||||||
import { Objectives } from "./objectives.ts";
|
import { Objectives, ObjectiveType } from "./objectives.ts";
|
||||||
|
|
||||||
export type LevelProgressionItem = {
|
export type LevelProgressionItem = {
|
||||||
Level: number;
|
Level: number;
|
||||||
@@ -67,7 +67,43 @@ export function getConfig() {
|
|||||||
StartsInMinutes: 0,
|
StartsInMinutes: 0,
|
||||||
},
|
},
|
||||||
LevelProgressionMaps: generateLevelProgressionMap(),
|
LevelProgressionMaps: generateLevelProgressionMap(),
|
||||||
DailyObjectives: [[{type: -1,score:0},{type: -1,score:0},{type: -1,score:0}],[{type: -1,score:0},{type: -1,score:0},{type: -1,score:0}],[{type: -1,score:0},{type: -1,score:0},{type: -1,score:0}]],
|
DailyObjectives: [
|
||||||
|
[
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0},
|
||||||
|
{type: ObjectiveType.Default, score: 0}
|
||||||
|
]
|
||||||
|
],
|
||||||
AutoMicMutingConfig: {
|
AutoMicMutingConfig: {
|
||||||
MicSpamVolumeThreshold: 1.125,
|
MicSpamVolumeThreshold: 1.125,
|
||||||
MicVolumeSampleInterval: 0.25,
|
MicVolumeSampleInterval: 0.25,
|
||||||
|
|||||||
47
src/data/content/activities.ts
Normal file
47
src/data/content/activities.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/* 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 Logging from "@proxnet/undead-logging";
|
||||||
|
import { RootPath } from "../../path.ts";
|
||||||
|
|
||||||
|
const log = new Logging("Activities");
|
||||||
|
|
||||||
|
enum CharadesWordsDifficulty {
|
||||||
|
Easy,
|
||||||
|
Hard
|
||||||
|
}
|
||||||
|
interface CharadesWord {
|
||||||
|
EN_US: string,
|
||||||
|
Difficulty: CharadesWordsDifficulty
|
||||||
|
}
|
||||||
|
interface WordsConfig {
|
||||||
|
easy: string[],
|
||||||
|
hard: string[]
|
||||||
|
}
|
||||||
|
let charades: WordsConfig | undefined;
|
||||||
|
try {
|
||||||
|
const data = Deno.readTextFileSync(`${RootPath}/res/words.json`);
|
||||||
|
charades = JSON.parse(data);
|
||||||
|
} catch (err) {
|
||||||
|
log.e(`Could not read charades words config from disk!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWords() {
|
||||||
|
if (!charades) return [{EN_US: "Galvanic Corrosion", Difficulty: CharadesWordsDifficulty.Easy}] as CharadesWord[]
|
||||||
|
else return charades.easy.map(val => ({EN_US: val, Difficulty: CharadesWordsDifficulty.Easy} as CharadesWord))
|
||||||
|
.concat(charades.hard.map(val => ({EN_US: val, Difficulty: CharadesWordsDifficulty.Hard} as CharadesWord)))
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -15,9 +15,7 @@ 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 { platform } from "node:process";
|
import { RootPath } from "../../path.ts";
|
||||||
|
|
||||||
export const RootPath = Deno.mainModule.substring(platform == 'win32' ? 8 : 7, Deno.mainModule.length - 11);
|
|
||||||
|
|
||||||
export function getBaseImage(name: string) {
|
export function getBaseImage(name: string) {
|
||||||
try {
|
try {
|
||||||
@@ -31,4 +29,4 @@ export function getAllBaseImages() {
|
|||||||
Deno.readDirSync(`${RootPath}/res/img/`).map((val) => val.isFile ? val.name : undefined),
|
Deno.readDirSync(`${RootPath}/res/img/`).map((val) => val.isFile ? val.name : undefined),
|
||||||
).filter((val) => typeof val == "string");
|
).filter((val) => typeof val == "string");
|
||||||
}
|
}
|
||||||
// todo: make this async
|
// todo: make this async
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
/* 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 { Buffer } from "node:buffer";
|
|
||||||
import { Redis } from "../../db.ts";
|
|
||||||
import { generateRandomString } from "../../apiutils.ts";
|
|
||||||
|
|
||||||
export enum FileType {
|
|
||||||
Unknown,
|
|
||||||
RoomSave,
|
|
||||||
Holotar,
|
|
||||||
Image,
|
|
||||||
Video,
|
|
||||||
Invention
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getFileName(prefix: string, type: FileType) {
|
|
||||||
switch (type) {
|
|
||||||
case FileType.RoomSave:
|
|
||||||
return `${prefix}.room`;
|
|
||||||
case FileType.Holotar:
|
|
||||||
return `${prefix}.holotar`;
|
|
||||||
case FileType.Image:
|
|
||||||
return `${prefix}.image`;
|
|
||||||
case FileType.Video:
|
|
||||||
return `${prefix}.video`;
|
|
||||||
case FileType.Invention:
|
|
||||||
return `${prefix}.invention`;
|
|
||||||
default:
|
|
||||||
return `${prefix}.unknown`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getFile(name: string) {
|
|
||||||
const data = await Redis.Database.getBuffer(Redis.buildKey(
|
|
||||||
Redis.KeyGroups.Content.Root,
|
|
||||||
name
|
|
||||||
));
|
|
||||||
|
|
||||||
if (!data) return null;
|
|
||||||
else return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns Name of the new file
|
|
||||||
*/
|
|
||||||
export async function setFile(data: Buffer<ArrayBufferLike>, type: FileType, name?: string) {
|
|
||||||
let filename = generateRandomString(24);
|
|
||||||
if (name) filename = name;
|
|
||||||
const finalName = getFileName(filename, type);
|
|
||||||
|
|
||||||
await Redis.Database.set(Redis.buildKey(
|
|
||||||
Redis.KeyGroups.Content.Root,
|
|
||||||
finalName
|
|
||||||
), data);
|
|
||||||
await initFileMeta(filename, type);
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FileMeta {
|
|
||||||
created: Date | string;
|
|
||||||
fetchCount: number;
|
|
||||||
type: FileType
|
|
||||||
}
|
|
||||||
|
|
||||||
async function initFileMeta(filename: string, type: FileType) {
|
|
||||||
const meta: FileMeta = {
|
|
||||||
created: new Date(),
|
|
||||||
fetchCount: 0,
|
|
||||||
type: type
|
|
||||||
}
|
|
||||||
await Redis.Database.hset(Redis.buildKey(
|
|
||||||
Redis.KeyGroups.Content.Files,
|
|
||||||
getFileName(filename, type)
|
|
||||||
), meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function incrementFileFetches(name: string, type: FileType) {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -16,13 +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 { Redis } from "../../db.ts";
|
import { Redis } from "../../db.ts";
|
||||||
import { RootPath } from "./baseimages.ts";
|
|
||||||
import { Profile } from "../profiles.ts";
|
import { Profile } from "../profiles.ts";
|
||||||
import Logging from "@proxnet/undead-logging";
|
import Logging from "@proxnet/undead-logging";
|
||||||
import { BuiltinRoom, FactoryMode, IntegratedRoomScene, RoomAccessibility, RoomDetails, RoomState, WriteMode } from "./rooms/DataTypes.ts";
|
import { BuiltinRoom, FactoryMode, IntegratedRoomScene, RoomAccessibility, RoomDataTypes, RoomDetails, RoomState, WriteMode } from "./rooms/DataTypes.ts";
|
||||||
import { RoomFactory } from "./rooms/RoomFactory.ts";
|
import { RoomFactory } from "./rooms/RoomFactory.ts";
|
||||||
import { SubroomFactory } from "./rooms/SubroomFactory.ts";
|
import { SubroomFactory } from "./rooms/SubroomFactory.ts";
|
||||||
import { Image } from "https://deno.land/x/imagescript@1.3.0/ImageScript.js";
|
import { RootPath } from "../../path.ts";
|
||||||
|
|
||||||
const log = new Logging("Rooms");
|
const log = new Logging("Rooms");
|
||||||
|
|
||||||
@@ -87,34 +86,27 @@ class RoomsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async cloneRoom(roomid: number, newname: string, newowner: Profile) {
|
async cloneRoom(roomid: number, newname: string, newowner: Profile) {
|
||||||
enum CloneResult {
|
|
||||||
Success,
|
|
||||||
DoesNotAllowCloning,
|
|
||||||
CannotCloneDormRoom,
|
|
||||||
NameIsTaken,
|
|
||||||
Unknown
|
|
||||||
}
|
|
||||||
interface RoomClone {
|
interface RoomClone {
|
||||||
factory?: RoomFactory;
|
factory?: RoomFactory;
|
||||||
result: CloneResult;
|
result: RoomDataTypes.CreateModifyRoomStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
const factory = await new RoomFactory({ id: roomid, factoryMode: FactoryMode.Fetch }).init();
|
const factory = await new RoomFactory({ id: roomid, factoryMode: FactoryMode.Fetch }).init();
|
||||||
if (!factory || !factory.CloningAllowed) return { result: CloneResult.DoesNotAllowCloning } as RoomClone;
|
if (!factory || !factory.CloningAllowed) return { result: RoomDataTypes.CreateModifyRoomStatus.PermissionDenied } as RoomClone;
|
||||||
if (factory.Name == 'DormRoom') return { result: CloneResult.CannotCloneDormRoom } as RoomClone;
|
if (factory.Name == 'DormRoom') return { result: RoomDataTypes.CreateModifyRoomStatus.ReservedName } as RoomClone;
|
||||||
if (factory.Name == newname) return { result: CloneResult.NameIsTaken } as RoomClone;
|
if (factory.Name == newname) return { result: RoomDataTypes.CreateModifyRoomStatus.DuplicateName } as RoomClone;
|
||||||
|
|
||||||
const newFactory = await new RoomFactory({ id: await Rooms.#getAvailableRoomId(), factoryMode: FactoryMode.Write }).init();
|
const newFactory = await new RoomFactory({ id: await Rooms.#getAvailableRoomId(), factoryMode: FactoryMode.Write }).init();
|
||||||
if (!newFactory) return { result: CloneResult.Unknown } as RoomClone;
|
if (!newFactory) return { result: RoomDataTypes.CreateModifyRoomStatus.Unknown } as RoomClone;
|
||||||
|
|
||||||
newFactory.CreatorPlayerId = newowner.getId();
|
newFactory.CreatorPlayerId = newowner.getId();
|
||||||
newFactory.Description = factory.Description;
|
newFactory.Description = factory.Description;
|
||||||
newFactory.Name = factory.Name;
|
newFactory.Name = newname;
|
||||||
newFactory.ImageName = factory.Description;
|
newFactory.ImageName = factory.ImageName;
|
||||||
newFactory.State = factory.State;
|
newFactory.State = RoomState.Active;
|
||||||
newFactory.RoomAccessibility = factory.RoomAccessibility;
|
newFactory.RoomAccessibility = RoomAccessibility.Private;
|
||||||
newFactory.SupportsLevelVoting = factory.SupportsLevelVoting;
|
newFactory.SupportsLevelVoting = factory.SupportsLevelVoting;
|
||||||
newFactory.IsAGRoom = factory.IsAGRoom;
|
newFactory.IsAGRoom = false;
|
||||||
newFactory.IsDormRoom = factory.IsDormRoom;
|
newFactory.IsDormRoom = factory.IsDormRoom;
|
||||||
newFactory.CloningAllowed = false; // new rooms cannot be cloned
|
newFactory.CloningAllowed = false; // new rooms cannot be cloned
|
||||||
newFactory.AllowsJuniors = factory.AllowsJuniors;
|
newFactory.AllowsJuniors = factory.AllowsJuniors;
|
||||||
@@ -128,8 +120,8 @@ class RoomsBase {
|
|||||||
|
|
||||||
const oldSubroomIds = await factory.getAllSubroomIds();
|
const oldSubroomIds = await factory.getAllSubroomIds();
|
||||||
const promises = oldSubroomIds.map(async (id) => {
|
const promises = oldSubroomIds.map(async (id) => {
|
||||||
const newSubroomFactory = newFactory.getSubroom(id, FactoryMode.Write, WriteMode.Overwrite);
|
const newSubroomFactory = await newFactory.getSubroom(id, FactoryMode.Write, WriteMode.Overwrite).init();
|
||||||
const oldSubroomFactory = factory.getSubroom(id, FactoryMode.Fetch);
|
const oldSubroomFactory = await factory.getSubroom(id, FactoryMode.Fetch).init();
|
||||||
|
|
||||||
newSubroomFactory.RoomSceneLocationId = oldSubroomFactory.RoomSceneLocationId;
|
newSubroomFactory.RoomSceneLocationId = oldSubroomFactory.RoomSceneLocationId;
|
||||||
newSubroomFactory.Name = oldSubroomFactory.Name;
|
newSubroomFactory.Name = oldSubroomFactory.Name;
|
||||||
@@ -143,10 +135,11 @@ class RoomsBase {
|
|||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
await newFactory.write();
|
await newFactory.write();
|
||||||
|
newFactory.factoryMode = FactoryMode.Fetch;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
factory: newFactory,
|
factory: newFactory,
|
||||||
result: CloneResult.Success
|
result: RoomDataTypes.CreateModifyRoomStatus.Success
|
||||||
} as RoomClone
|
} as RoomClone
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,8 +192,8 @@ class RoomsBase {
|
|||||||
factory.CustomRoomWarning = "";
|
factory.CustomRoomWarning = "";
|
||||||
|
|
||||||
factory.addHardwareSupport('*');
|
factory.addHardwareSupport('*');
|
||||||
|
|
||||||
const subroomFactory = factory.getSubroom(await this.#getAvailableSubRoomId(id), FactoryMode.Write, WriteMode.WriteIfFree);
|
const subroomFactory = await factory.getSubroom(await this.#getAvailableSubRoomId(id), FactoryMode.Write, WriteMode.WriteIfFree).init();
|
||||||
if (!subroomFactory) return null;
|
if (!subroomFactory) return null;
|
||||||
|
|
||||||
subroomFactory.RoomSceneLocationId = IntegratedRoomScene.DormRoom;
|
subroomFactory.RoomSceneLocationId = IntegratedRoomScene.DormRoom;
|
||||||
@@ -226,7 +219,7 @@ class RoomsBase {
|
|||||||
|
|
||||||
const factory = await new RoomFactory({ id: newId, factoryMode: FactoryMode.Write, writeMode: WriteMode.Overwrite }).init();
|
const factory = await new RoomFactory({ id: newId, factoryMode: FactoryMode.Write, writeMode: WriteMode.Overwrite }).init();
|
||||||
if (!factory) return;
|
if (!factory) return;
|
||||||
|
|
||||||
factory.Name = builtinRoom.Name;
|
factory.Name = builtinRoom.Name;
|
||||||
factory.Description = builtinRoom.Description;
|
factory.Description = builtinRoom.Description;
|
||||||
factory.CreatorPlayerId = 1;
|
factory.CreatorPlayerId = 1;
|
||||||
@@ -268,7 +261,7 @@ class RoomsBase {
|
|||||||
subroomFactory.DataBlobName = "";
|
subroomFactory.DataBlobName = "";
|
||||||
subroomFactory.MaxPlayers = subroom.MaxPlayers;
|
subroomFactory.MaxPlayers = subroom.MaxPlayers;
|
||||||
subroomFactory.CanMatchmakeInto = subroom.CanMatchmakeInto;
|
subroomFactory.CanMatchmakeInto = subroom.CanMatchmakeInto;
|
||||||
|
|
||||||
await subroomFactory.write();
|
await subroomFactory.write();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -37,9 +37,9 @@ export enum RoomState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum RoomAccessibility {
|
export enum RoomAccessibility {
|
||||||
Private,
|
Private,
|
||||||
Public,
|
Public,
|
||||||
Unlisted
|
Unlisted
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BuiltinScene {
|
export interface BuiltinScene {
|
||||||
@@ -143,6 +143,7 @@ export enum IntegratedRoomScene {
|
|||||||
DiscGolfLake = "f6f7256c-e438-4299-b99e-d20bef8cf7e0",
|
DiscGolfLake = "f6f7256c-e438-4299-b99e-d20bef8cf7e0",
|
||||||
DiscGolfPropulsion = "d9378c9f-80bc-46fb-ad1e-1bed8a674f55",
|
DiscGolfPropulsion = "d9378c9f-80bc-46fb-ad1e-1bed8a674f55",
|
||||||
Dodgeball = "3d474b26-26f7-45e9-9a36-9b02847d5e6f",
|
Dodgeball = "3d474b26-26f7-45e9-9a36-9b02847d5e6f",
|
||||||
|
DodgeballVR = "3d474b26-26f7-45e9-9a36-9b02847d5e6f",
|
||||||
Paddleball = "d89f74fa-d51e-477a-a425-025a891dd499",
|
Paddleball = "d89f74fa-d51e-477a-a425-025a891dd499",
|
||||||
Paintball_River = "e122fe98-e7db-49e8-a1b1-105424b6e1f0",
|
Paintball_River = "e122fe98-e7db-49e8-a1b1-105424b6e1f0",
|
||||||
Paintball_Homestead = "a785267d-c579-42ea-be43-fec1992d1ca7",
|
Paintball_Homestead = "a785267d-c579-42ea-be43-fec1992d1ca7",
|
||||||
@@ -179,7 +180,6 @@ export enum IntegratedRoomScene {
|
|||||||
Stadium = "6d5eea4b-f069-4ed0-9916-0e2f07df0d03",
|
Stadium = "6d5eea4b-f069-4ed0-9916-0e2f07df0d03",
|
||||||
Hangar = "239e676c-f12f-489f-bf3a-d4c383d692c3",
|
Hangar = "239e676c-f12f-489f-bf3a-d4c383d692c3",
|
||||||
CyberJunkCity = "9d6456ce-6264-48b4-808d-2d96b3d91038",
|
CyberJunkCity = "9d6456ce-6264-48b4-808d-2d96b3d91038",
|
||||||
DodgeballVR = "3d474b26-26f7-45e9-9a36-9b02847d5e6f",
|
|
||||||
Crescendo = "49cb8993-a956-43e2-86f4-1318f279b22a",
|
Crescendo = "49cb8993-a956-43e2-86f4-1318f279b22a",
|
||||||
Bowling = "ae929543-9a07-41d5-8ee9-dbbee8c36800",
|
Bowling = "ae929543-9a07-41d5-8ee9-dbbee8c36800",
|
||||||
BowlingAlley = "ae929543-9a07-41d5-8ee9-dbbee8c36800",
|
BowlingAlley = "ae929543-9a07-41d5-8ee9-dbbee8c36800",
|
||||||
@@ -188,4 +188,31 @@ export enum IntegratedRoomScene {
|
|||||||
StuntRunnerBaseRoom = "882e9b96-7115-4b03-86f6-c0c9d8e22e00",
|
StuntRunnerBaseRoom = "882e9b96-7115-4b03-86f6-c0c9d8e22e00",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CreateModifyRoomStatus {
|
||||||
|
Success,
|
||||||
|
Unknown,
|
||||||
|
PermissionDenied,
|
||||||
|
RoomNotActive,
|
||||||
|
RoomDoesNotExist,
|
||||||
|
RoomHasNoDataBlob,
|
||||||
|
DuplicateName = 10,
|
||||||
|
ReservedName,
|
||||||
|
InappropriateName,
|
||||||
|
InappropriateDescription,
|
||||||
|
TooManyRooms = 20,
|
||||||
|
InvalidMaxPlayers = 30,
|
||||||
|
DataHistoryDoesNotExist = 40,
|
||||||
|
DataHistoryAlreadyActive,
|
||||||
|
InvalidTags = 50,
|
||||||
|
NoStartingRoomScene = 55,
|
||||||
|
RoomUnderModerationReview = 100,
|
||||||
|
PlayerHasRoomUnderModerationReview,
|
||||||
|
AccessibilityUnderModerationLock,
|
||||||
|
JuniorStatusFail = 200,
|
||||||
|
InappropriateCustomWarning = 300,
|
||||||
|
PartialBanSuccessBanPower = 400,
|
||||||
|
TargetHasBanPower,
|
||||||
|
PlayerIsRoomBanned = 410
|
||||||
|
}
|
||||||
|
|
||||||
export * as RoomDataTypes from "./DataTypes.ts";
|
export * as RoomDataTypes from "./DataTypes.ts";
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -60,14 +60,14 @@ class MatchmakingBase {
|
|||||||
const instance = Instances.getInstance(options.instanceId);
|
const instance = Instances.getInstance(options.instanceId);
|
||||||
if (instance) {
|
if (instance) {
|
||||||
|
|
||||||
if (Instances.playerIsInInstance(options.profile, instance)) return { errorCode: MatchmakingErrorCode.AlreadyInTargetInstance };
|
if (instance.hasPlayer(options.profile)) return { errorCode: MatchmakingErrorCode.AlreadyInTargetInstance };
|
||||||
else {
|
else {
|
||||||
if (instance.isFull) return { errorCode: MatchmakingErrorCode.InsufficientSpace }
|
if (instance.isFull) return { errorCode: MatchmakingErrorCode.InsufficientSpace }
|
||||||
else if (instance.isPrivate) return { errorCode: MatchmakingErrorCode.RoomInstanceIsPrivate };
|
else if (instance.isPrivate) return { errorCode: MatchmakingErrorCode.RoomInstanceIsPrivate };
|
||||||
|
|
||||||
await Instances.setPlayerInstance(options.profile, instance);
|
await instance.addPlayer(options.profile);
|
||||||
Instances.clearAllRoomEmptyInstances(instance.roomId);
|
Instances.clearEmptyInstances(instance.roomId);
|
||||||
return { errorCode: MatchmakingErrorCode.Success, roomInstance: instance };
|
return { errorCode: MatchmakingErrorCode.Success, roomInstance: instance.snapshot() };
|
||||||
}
|
}
|
||||||
|
|
||||||
} else return { errorCode: MatchmakingErrorCode.NoSuchGame }
|
} else return { errorCode: MatchmakingErrorCode.NoSuchGame }
|
||||||
@@ -82,7 +82,7 @@ class MatchmakingBase {
|
|||||||
if (targetRoom.Room.State !== RoomDataTypes.RoomState.Active) return { errorCode: MatchmakingErrorCode.RoomIsNotActive };
|
if (targetRoom.Room.State !== RoomDataTypes.RoomState.Active) return { errorCode: MatchmakingErrorCode.RoomIsNotActive };
|
||||||
const roomId = targetRoom.Room.RoomId;
|
const roomId = targetRoom.Room.RoomId;
|
||||||
|
|
||||||
Instances.clearAllRoomEmptyInstances(roomId);
|
Instances.clearEmptyInstances(roomId);
|
||||||
|
|
||||||
// get all available instance
|
// 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);
|
||||||
@@ -108,9 +108,9 @@ class MatchmakingBase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
allInstances = allInstances.sort((a, b) => {
|
allInstances = allInstances.sort((a, b) => {
|
||||||
const pidsA = Instances.getInstancePlayers(a);
|
const pidsA = a.getAllPlayers();
|
||||||
const pidsB = Instances.getInstancePlayers(b);
|
const pidsB = b.getAllPlayers();
|
||||||
return pidsA.size - pidsB.size;
|
return pidsA.length - pidsB.length;
|
||||||
}).reverse(); // Largest instances first
|
}).reverse(); // Largest instances first
|
||||||
|
|
||||||
const foundInstance = allInstances[0];
|
const foundInstance = allInstances[0];
|
||||||
@@ -125,8 +125,8 @@ class MatchmakingBase {
|
|||||||
IsDorm: options.roomName == 'DormRoom'
|
IsDorm: options.roomName == 'DormRoom'
|
||||||
});
|
});
|
||||||
|
|
||||||
Instances.clearAllRoomEmptyInstances(roomId);
|
Instances.clearEmptyInstances(roomId);
|
||||||
return { errorCode: MatchmakingErrorCode.Success, roomInstance: newInstance };
|
return { errorCode: MatchmakingErrorCode.Success, roomInstance: newInstance.snapshot() };
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -134,11 +134,11 @@ class MatchmakingBase {
|
|||||||
if (currentInstance?.roomInstanceId == foundInstance.roomInstanceId)
|
if (currentInstance?.roomInstanceId == foundInstance.roomInstanceId)
|
||||||
return { errorCode: MatchmakingErrorCode.AlreadyInBestInstance };
|
return { errorCode: MatchmakingErrorCode.AlreadyInBestInstance };
|
||||||
|
|
||||||
await Instances.setPlayerInstance(options.profile, foundInstance);
|
await foundInstance.addPlayer(options.profile);
|
||||||
|
|
||||||
Instances.clearAllRoomEmptyInstances(roomId);
|
Instances.clearEmptyInstances(roomId);
|
||||||
|
|
||||||
return { errorCode: MatchmakingErrorCode.Success, roomInstance: foundInstance };
|
return { errorCode: MatchmakingErrorCode.Success, roomInstance: foundInstance.snapshot() };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -21,84 +21,191 @@ 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";
|
||||||
import { RoomFactory } from "../content/rooms/RoomFactory.ts";
|
import { RoomFactory } from "../content/rooms/RoomFactory.ts";
|
||||||
|
import { RoomDataTypes } from "../content/rooms/DataTypes.ts";
|
||||||
|
import { PushNotificationId } from "../../socket/types.ts";
|
||||||
|
|
||||||
const log = new Logging("Instances");
|
const log = new Logging("Instances");
|
||||||
|
|
||||||
const config = Config.getConfig();
|
const config = Config.getConfig();
|
||||||
|
|
||||||
const instancePlayers: Map<RoomInstance, Set<Profile>> = new Map();
|
|
||||||
/**
|
/**
|
||||||
* `Map<roomId (number), RoomInstance>`
|
* `Map<roomId (number), Instance>`
|
||||||
*/
|
*/
|
||||||
const instanceMap: Map<number, Set<RoomInstance>> = new Map();
|
const instanceSet: Set<Instance> = new Set();
|
||||||
|
|
||||||
|
export class Instance {
|
||||||
|
|
||||||
|
#players = new Set<Profile>();
|
||||||
|
timeCreated = new Date().toISOString();
|
||||||
|
|
||||||
|
#id: number;
|
||||||
|
#room: RoomDataTypes.RoomDetails | undefined;
|
||||||
|
#subroom: RoomDataTypes.RoomScene | undefined;
|
||||||
|
|
||||||
|
#eventId?: number; // not yet implemented
|
||||||
|
#name?: string;
|
||||||
|
#priv?: boolean;
|
||||||
|
#inProgress?: boolean;
|
||||||
|
#blob?: string;
|
||||||
|
|
||||||
|
constructor(id: number) {
|
||||||
|
this.#id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(options: InstanceOptions) {
|
||||||
|
|
||||||
|
const scene = options.Room.Scenes[options.SceneIndex];
|
||||||
|
if (!scene) throw new Error("The specified scene did not exist.");
|
||||||
|
|
||||||
|
let instanceName;
|
||||||
|
if (scene.Name == 'Home' || scene.Name === options.Room.Room.Name) instanceName = `^${options.Room.Room.Name}`;
|
||||||
|
else instanceName = `^${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`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#room = options.Room;
|
||||||
|
this.#subroom = scene;
|
||||||
|
this.#name = instanceName;
|
||||||
|
this.#blob = scene.DataBlobName;
|
||||||
|
this.#inProgress = false;
|
||||||
|
this.#priv = options.Private ? options.Private : false;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
equalInstance(instance: RoomInstance) {
|
||||||
|
return instance.roomInstanceId == this.#id;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllPlayers() {
|
||||||
|
return this.#players.values().toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPlayer(player: Profile) {
|
||||||
|
return this.getAllPlayers().includes(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
removePlayer(player: Profile) {
|
||||||
|
if (!this.hasPlayer(player)) throw new Error(`Cannot remove player ${player.getId()} from instance ${this.#id} they are not in`);
|
||||||
|
this.#players.delete(player);
|
||||||
|
player.setInstance(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addPlayer(player: Profile) {
|
||||||
|
const currentInstance = player.getInstance();
|
||||||
|
if (currentInstance && currentInstance.equalInstance(this)) return;
|
||||||
|
|
||||||
|
if (currentInstance) currentInstance.removePlayer(player);
|
||||||
|
|
||||||
|
if (!this.isFull) {
|
||||||
|
const instancePlayers = this.getAllPlayers();
|
||||||
|
const profileExport = await player.export();
|
||||||
|
log.i(`Player ${player.getId()} "${profileExport?.displayName}" went to '${this.name}' with ${instancePlayers.length} other players`);
|
||||||
|
|
||||||
|
this.#players.add(player);
|
||||||
|
player.setInstance(this);
|
||||||
|
|
||||||
|
const pres = await Presence.get(player);
|
||||||
|
pres.update();
|
||||||
|
|
||||||
|
const room = await new RoomFactory({ id: this.roomId }).init();
|
||||||
|
await room?.addVisit();
|
||||||
|
|
||||||
|
// move some of this to a dedicated "onPlayerMove" function
|
||||||
|
} else log.w(`Instance ${this.roomInstanceId} is full. Cannot add player ${player.getId()}`);
|
||||||
|
|
||||||
|
log.d(`Players in instance ${this.#id}: ${this.#players.values().toArray().map(prof => prof.getId()).join(',')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
get roomInstanceId() { return this.#id }
|
||||||
|
|
||||||
|
get roomId() { return this.#room ? this.#room?.Room.RoomId : 0 }
|
||||||
|
|
||||||
|
get subRoomId() { return this.#subroom ? this.#subroom?.RoomSceneId : 0 }
|
||||||
|
|
||||||
|
get location() { return this.#subroom ? this.#subroom?.RoomSceneLocationId : "" }
|
||||||
|
|
||||||
|
get dataBlob() { return this.#blob ? this.#blob : undefined }
|
||||||
|
set dataBlob(data) { this.#blob = data }
|
||||||
|
|
||||||
|
get eventId() { return this.#eventId }
|
||||||
|
|
||||||
|
get photonRegionId() { return config.public.photonRegionId }
|
||||||
|
|
||||||
|
get photonRoomId() { return `GC20200306-${this.#id}` }
|
||||||
|
|
||||||
|
get name() { return this.#name ? this.#name : "InstanceNameError" }
|
||||||
|
|
||||||
|
get maxCapacity() { return this.#subroom ? this.#subroom.MaxPlayers : 8 }
|
||||||
|
|
||||||
|
get isFull() { return this.#players.size >= this.maxCapacity }
|
||||||
|
|
||||||
|
get isPrivate() { return this.#priv ? this.#priv : false }
|
||||||
|
set isPrivate(data) { this.#priv = data }
|
||||||
|
|
||||||
|
get isInProgress() { return this.#inProgress ? this.#inProgress : false }
|
||||||
|
set isInProgress(data) { this.#inProgress = data }
|
||||||
|
|
||||||
|
snapshot() {
|
||||||
|
const inst: RoomInstance = {
|
||||||
|
roomInstanceId: this.roomInstanceId,
|
||||||
|
roomId: this.roomId,
|
||||||
|
subRoomId: this.subRoomId,
|
||||||
|
location: this.location,
|
||||||
|
dataBlob: this.dataBlob,
|
||||||
|
eventId: this.eventId,
|
||||||
|
photonRegionId: this.photonRegionId,
|
||||||
|
photonRoomId: this.photonRoomId,
|
||||||
|
name: this.name,
|
||||||
|
maxCapacity: this.maxCapacity,
|
||||||
|
isFull: this.isFull,
|
||||||
|
isPrivate: this.isPrivate,
|
||||||
|
isInProgress: this.isInProgress
|
||||||
|
}
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
instanceSet.delete(this);
|
||||||
|
if (this.#players.size !== 0) for (const player of this.#players) player.getSocketHandler()?.sendNotification(PushNotificationId.Logout);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class InstancesBase {
|
class InstancesBase {
|
||||||
|
|
||||||
getInstance(id: number) {
|
getInstance(id: number) {
|
||||||
const instances = instancePlayers.keys();
|
const instances = instanceSet.values().toArray();
|
||||||
const instance = instances.find(val => val.roomInstanceId == id);
|
const instance = instances.find(val => val.roomInstanceId == id);
|
||||||
if (instance) return instance;
|
if (instance) return instance;
|
||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllInstances() {
|
getAllInstances() {
|
||||||
return new Set([...instanceMap.values()].flatMap(set => [...set]));
|
return new Set([...instanceSet.values().toArray()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllRoomInstances(roomId: number) {
|
getAllRoomInstances(roomId: number) {
|
||||||
let instances = instanceMap.get(roomId);
|
return new Set([...this.getAllInstances().values().toArray().filter(val => val.roomId == roomId)]);
|
||||||
if (!instances) {
|
|
||||||
instances = new Set();
|
|
||||||
instanceMap.set(roomId, instances);
|
|
||||||
}
|
|
||||||
return instances;
|
|
||||||
}
|
|
||||||
|
|
||||||
getInstancePlayers(instance: RoomInstance): Set<Profile> {
|
|
||||||
let players = instancePlayers.get(instance);
|
|
||||||
if (!players) {
|
|
||||||
players = new Set();
|
|
||||||
instancePlayers.set(instance, players);
|
|
||||||
}
|
|
||||||
return players;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clearEmptyInstances(instances: Set<RoomInstance>, roomId?: number) {
|
clearEmptyInstances(roomId?: number) {
|
||||||
const beforeCount = instances.size;
|
const beforeCount = instanceSet.size;
|
||||||
for (const instance of instances) {
|
for (const instance of instanceSet) {
|
||||||
const profiles = this.getInstancePlayers(instance);
|
if (roomId && instance.roomId == roomId) continue;
|
||||||
if (profiles.size === 0) {
|
const profiles = instance.getAllPlayers();
|
||||||
|
if (profiles.length === 0) {
|
||||||
log.i(`Instance ${instance.roomInstanceId} empty, deleting`);
|
log.i(`Instance ${instance.roomInstanceId} empty, deleting`);
|
||||||
instancePlayers.delete(instance);
|
instance.destroy();
|
||||||
this.getAllRoomInstances(instance.roomId).delete(instance);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const afterCount = instances.size;
|
const afterCount = instanceSet.size;
|
||||||
log.d(`Cleared ${roomId !== undefined ? `room ${roomId}` : 'all'} empty instances.\n Instances before: ${beforeCount}\n Instances after: ${afterCount}`);
|
log.d(`Cleared empty instances for roomId ${roomId ? roomId : "*"}.\n Instances before: ${beforeCount}\n Instances after: ${afterCount}`);
|
||||||
}
|
|
||||||
|
|
||||||
clearAllEmptyInstances() {
|
|
||||||
this.clearEmptyInstances(this.getAllInstances());
|
|
||||||
}
|
|
||||||
|
|
||||||
clearAllRoomEmptyInstances(roomId: number) {
|
|
||||||
this.clearEmptyInstances(this.getAllRoomInstances(roomId), roomId);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateGlobalInstancesIsFull() {
|
|
||||||
for (const instance of this.getAllInstances())
|
|
||||||
instance.isFull = this.getInstancePlayers(instance).size >= instance.maxCapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSingleInstanceIsFull(instance: RoomInstance) {
|
|
||||||
const profiles = this.getInstancePlayers(instance);
|
|
||||||
if (profiles.size >= instance.maxCapacity) instance.isFull = true;
|
|
||||||
else instance.isFull = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
instanceCanFitPlayer(instance: RoomInstance) {
|
|
||||||
return this.getInstancePlayers(instance).size < instance.maxCapacity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#generateUniqueInstanceId() {
|
#generateUniqueInstanceId() {
|
||||||
@@ -112,96 +219,19 @@ class InstancesBase {
|
|||||||
* Create an instance with options.
|
* Create an instance with options.
|
||||||
*
|
*
|
||||||
* If `options.FirstPlayer` is not specified, the created instance will not contain any players and may be removed.
|
* If `options.FirstPlayer` is not specified, the created instance will not contain any players and may be removed.
|
||||||
*
|
|
||||||
* If one is, the player will be automatically added to the instance and their `profile.getInstance()` will be synchronized.
|
|
||||||
*/
|
*/
|
||||||
async createInstance(options: InstanceOptions) {
|
async createInstance(options: InstanceOptions) {
|
||||||
|
|
||||||
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.");
|
const newInstance = await new Instance(newId).init(options);
|
||||||
|
|
||||||
let instanceName = scene.Name === "Home" || scene.Name === options.Room.Room.Name ? `^${options.Room.Room.Name}` : `^${options.Room.Room.Name}.${scene.Name}`;
|
instanceSet.add(newInstance);
|
||||||
if (options.IsDorm) {
|
if (options.FirstPlayer)
|
||||||
const dormCreatorPlayer = UnifiedProfile.get(options.Room.Room.CreatorPlayerId);
|
newInstance.addPlayer(options.FirstPlayer);
|
||||||
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,
|
|
||||||
eventId: options.EventId,
|
|
||||||
photonRegionId: config.public.photonRegionId,
|
|
||||||
photonRoomId: `20200306-GC${newId}`,
|
|
||||||
name: instanceName,
|
|
||||||
maxCapacity: scene.MaxPlayers,
|
|
||||||
isFull: false,
|
|
||||||
isPrivate: typeof options.Private !== 'boolean' ? false : options.Private,
|
|
||||||
isInProgress: false
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getAllRoomInstances(options.Room.Room.RoomId).add(newInstance);
|
|
||||||
if (options.FirstPlayer) {
|
|
||||||
this.setPlayerInstance(options.FirstPlayer, newInstance);
|
|
||||||
this.getInstancePlayers(newInstance).add(options.FirstPlayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newInstance;
|
return newInstance;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Call only when the player is ready to be moved to an instance
|
|
||||||
*
|
|
||||||
* Synchronizes profile instance to `instance` and adds player to instance.
|
|
||||||
*/
|
|
||||||
async setPlayerInstance(player: Profile, instance: RoomInstance) {
|
|
||||||
const currentInstance = player.getInstance();
|
|
||||||
if (currentInstance === instance) return;
|
|
||||||
|
|
||||||
if (currentInstance) {
|
|
||||||
this.getInstancePlayers(currentInstance).delete(player);
|
|
||||||
this.updateSingleInstanceIsFull(currentInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.instanceCanFitPlayer(instance)) {
|
|
||||||
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);
|
|
||||||
pres.update();
|
|
||||||
|
|
||||||
this.updateSingleInstanceIsFull(instance);
|
|
||||||
} else log.w(`Instance ${instance.roomInstanceId} is full. Cannot add player ${player.getId()}`);
|
|
||||||
|
|
||||||
const room = await new RoomFactory({ id: instance.roomId }).init();
|
|
||||||
await room?.addVisit();
|
|
||||||
}
|
|
||||||
|
|
||||||
playerIsInInstance(player: Profile, instance: RoomInstance) {
|
|
||||||
|
|
||||||
const profiles = this.getInstancePlayers(instance);
|
|
||||||
return profiles.has(player);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call only when the player is ready to be removed (or when not responding)
|
|
||||||
*
|
|
||||||
* Synchronizes profile instance to `null` and removes player from instance.
|
|
||||||
*/
|
|
||||||
removePlayerFromCurrentInstance(player: Profile) {
|
|
||||||
const instance = player.getInstance();
|
|
||||||
if (!instance) return;
|
|
||||||
this.getInstancePlayers(instance).delete(player);
|
|
||||||
player.setInstance(null);
|
|
||||||
this.updateSingleInstanceIsFull(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -20,6 +20,7 @@ import { SettingKey } from "../content/settings.ts";
|
|||||||
import { Profile } from "../profiles.ts";
|
import { Profile } from "../profiles.ts";
|
||||||
import { DeviceClass, PlayerStatusVisibility, RoomInstance, VRMovementMode } from "./types.ts";
|
import { DeviceClass, PlayerStatusVisibility, RoomInstance, VRMovementMode } from "./types.ts";
|
||||||
import Logging from "@proxnet/undead-logging";
|
import Logging from "@proxnet/undead-logging";
|
||||||
|
import { Instance } from "./instances.ts";
|
||||||
|
|
||||||
const log = new Logging("Presence");
|
const log = new Logging("Presence");
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ export interface PresenceExport {
|
|||||||
vrMovementMode?: VRMovementMode;
|
vrMovementMode?: VRMovementMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This whole class needs rewritten .. probably
|
||||||
class PlayerPresence {
|
class PlayerPresence {
|
||||||
|
|
||||||
intervalId: number;
|
intervalId: number;
|
||||||
@@ -63,7 +65,7 @@ class PlayerPresence {
|
|||||||
statusVisibility: PlayerStatusVisibility;
|
statusVisibility: PlayerStatusVisibility;
|
||||||
deviceClass: DeviceClass;
|
deviceClass: DeviceClass;
|
||||||
vrMovementMode: VRMovementMode | undefined;
|
vrMovementMode: VRMovementMode | undefined;
|
||||||
roomInstance: RoomInstance | null;
|
roomInstance: Instance | null;
|
||||||
|
|
||||||
lastSeen: Date;
|
lastSeen: Date;
|
||||||
|
|
||||||
@@ -102,9 +104,10 @@ class PlayerPresence {
|
|||||||
*/
|
*/
|
||||||
async export() {
|
async export() {
|
||||||
await this.update();
|
await this.update();
|
||||||
|
const inst = this.roomInstance?.snapshot();
|
||||||
const exp: PresenceExport = {
|
const exp: PresenceExport = {
|
||||||
playerId: this.playerId,
|
playerId: this.playerId,
|
||||||
roomInstance: this.roomInstance,
|
roomInstance: inst ? inst : null,
|
||||||
statusVisibility: this.statusVisibility,
|
statusVisibility: this.statusVisibility,
|
||||||
deviceClass: this.deviceClass,
|
deviceClass: this.deviceClass,
|
||||||
vrMovementMode: this.vrMovementMode
|
vrMovementMode: this.vrMovementMode
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -41,6 +41,7 @@ interface Relationship {
|
|||||||
Favorited?: ReciprocalStatus
|
Favorited?: ReciprocalStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Literally all of this is untested
|
||||||
export class ProfileRelationshipManager extends ProfileContentManager {
|
export class ProfileRelationshipManager extends ProfileContentManager {
|
||||||
|
|
||||||
#baseRelationships: Relationship[] = [
|
#baseRelationships: Relationship[] = [
|
||||||
@@ -123,15 +124,15 @@ export class ProfileRelationshipManager extends ProfileContentManager {
|
|||||||
return (await Redis.Database.smembers(this.#friendsKey)).map(val => parseInt(val)).filter(val => !isNaN(val));
|
return (await Redis.Database.smembers(this.#friendsKey)).map(val => parseInt(val)).filter(val => !isNaN(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
async #getIncomingRequests() {
|
async getIncomingRequests() {
|
||||||
return (await Redis.Database.smembers(this.#incomingFriends)).map(val => parseInt(val)).filter(val => !isNaN(val));
|
return (await Redis.Database.smembers(this.#incomingFriends)).map(val => parseInt(val)).filter(val => !isNaN(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
async #getOutgoingRequests() {
|
async getOutgoingRequests() {
|
||||||
return (await Redis.Database.smembers(this.#outgoingFriends)).map(val => parseInt(val)).filter(val => !isNaN(val));
|
return (await Redis.Database.smembers(this.#outgoingFriends)).map(val => parseInt(val)).filter(val => !isNaN(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
createRemoteRootKey(remoteProfileId: number) {
|
#createRemoteRootKey(remoteProfileId: number) {
|
||||||
return Redis.buildKey(
|
return Redis.buildKey(
|
||||||
Redis.KeyGroups.Profiles.Root,
|
Redis.KeyGroups.Profiles.Root,
|
||||||
remoteProfileId.toString(),
|
remoteProfileId.toString(),
|
||||||
@@ -140,7 +141,7 @@ export class ProfileRelationshipManager extends ProfileContentManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async #clearAssociationWithRemote(remoteProfileId: number) {
|
async #clearAssociationWithRemote(remoteProfileId: number) {
|
||||||
const remoteRootKey = this.createRemoteRootKey(remoteProfileId);
|
const remoteRootKey = this.#createRemoteRootKey(remoteProfileId);
|
||||||
await Redis.Database.srem(this.#incomingFriends, remoteProfileId);
|
await Redis.Database.srem(this.#incomingFriends, remoteProfileId);
|
||||||
await Redis.Database.srem(Redis.buildKey(remoteRootKey, Redis.KeyGroups.Profiles.Relationships.OutgoingFriendRequests), this.profileId);
|
await Redis.Database.srem(Redis.buildKey(remoteRootKey, Redis.KeyGroups.Profiles.Relationships.OutgoingFriendRequests), this.profileId);
|
||||||
await Redis.Database.srem(Redis.buildKey(remoteRootKey, Redis.KeyGroups.Profiles.Relationships.IncomingFriendRequests), this.profileId);
|
await Redis.Database.srem(Redis.buildKey(remoteRootKey, Redis.KeyGroups.Profiles.Relationships.IncomingFriendRequests), this.profileId);
|
||||||
@@ -148,27 +149,27 @@ export class ProfileRelationshipManager extends ProfileContentManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async acceptRequest(remoteProfileId: number) {
|
async acceptRequest(remoteProfileId: number) {
|
||||||
const requests = await this.#getIncomingRequests();
|
const requests = await this.getIncomingRequests();
|
||||||
if (!requests.includes(remoteProfileId)) return;
|
if (!requests.includes(remoteProfileId)) return;
|
||||||
|
|
||||||
await this.#clearAssociationWithRemote(remoteProfileId);
|
await this.#clearAssociationWithRemote(remoteProfileId);
|
||||||
|
|
||||||
const remoteRootKey = this.createRemoteRootKey(remoteProfileId);
|
const remoteRootKey = this.#createRemoteRootKey(remoteProfileId);
|
||||||
|
|
||||||
await Redis.Database.sadd(this.#friendsKey, remoteProfileId);
|
await Redis.Database.sadd(this.#friendsKey, remoteProfileId);
|
||||||
await Redis.Database.sadd(Redis.buildKey(remoteRootKey, Redis.KeyGroups.Profiles.Relationships.Friends), this.profileId);
|
await Redis.Database.sadd(Redis.buildKey(remoteRootKey, Redis.KeyGroups.Profiles.Relationships.Friends), this.profileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async denyRequest(remoteProfileId: number) {
|
async denyRequest(remoteProfileId: number) {
|
||||||
const requests = await this.#getIncomingRequests();
|
const requests = await this.getIncomingRequests();
|
||||||
if (!requests.includes(remoteProfileId)) return;
|
if (!requests.includes(remoteProfileId)) return;
|
||||||
await this.#clearAssociationWithRemote(remoteProfileId);
|
await this.#clearAssociationWithRemote(remoteProfileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRelationshipType(remoteProfileId: number) {
|
async getRelationshipType(remoteProfileId: number) {
|
||||||
const isFriendsWithRemote = (await Redis.Database.sismember(this.#friendsKey, remoteProfileId)) >= 1;
|
const isFriendsWithRemote = (await Redis.Database.sismember(this.#friendsKey, remoteProfileId)) >= 1;
|
||||||
const remoteSentRequest = (await this.#getIncomingRequests()).includes(remoteProfileId);
|
const remoteSentRequest = (await this.getIncomingRequests()).includes(remoteProfileId);
|
||||||
const localSentRequest = (await this.#getOutgoingRequests()).includes(remoteProfileId);
|
const localSentRequest = (await this.getOutgoingRequests()).includes(remoteProfileId);
|
||||||
|
|
||||||
if (isFriendsWithRemote || (remoteSentRequest && localSentRequest)) return RelationshipType.Friend;
|
if (isFriendsWithRemote || (remoteSentRequest && localSentRequest)) return RelationshipType.Friend;
|
||||||
else if (remoteSentRequest) return RelationshipType.FriendRequestReceived;
|
else if (remoteSentRequest) return RelationshipType.FriendRequestReceived;
|
||||||
@@ -177,7 +178,7 @@ export class ProfileRelationshipManager extends ProfileContentManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getMutedReciprocal(remoteProfileId: number) {
|
async getMutedReciprocal(remoteProfileId: number) {
|
||||||
const remoteKey = this.createRemoteRootKey(remoteProfileId);
|
const remoteKey = this.#createRemoteRootKey(remoteProfileId);
|
||||||
|
|
||||||
const localMuted = (await this.getAllMuted()).includes(remoteProfileId);
|
const localMuted = (await this.getAllMuted()).includes(remoteProfileId);
|
||||||
const remoteMuted = await Redis.Database.sismember(Redis.buildKey(remoteKey, Redis.KeyGroups.Profiles.Relationships.Muted), this.profileId);
|
const remoteMuted = await Redis.Database.sismember(Redis.buildKey(remoteKey, Redis.KeyGroups.Profiles.Relationships.Muted), this.profileId);
|
||||||
@@ -189,7 +190,7 @@ export class ProfileRelationshipManager extends ProfileContentManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getIgnoredReciprocal(remoteProfileId: number) {
|
async getIgnoredReciprocal(remoteProfileId: number) {
|
||||||
const remoteKey = this.createRemoteRootKey(remoteProfileId);
|
const remoteKey = this.#createRemoteRootKey(remoteProfileId);
|
||||||
|
|
||||||
const localIgnored = (await this.getAllMuted()).includes(remoteProfileId);
|
const localIgnored = (await this.getAllMuted()).includes(remoteProfileId);
|
||||||
const remoteIgnored = await Redis.Database.sismember(Redis.buildKey(remoteKey, Redis.KeyGroups.Profiles.Relationships.Ignoring), this.profileId);
|
const remoteIgnored = await Redis.Database.sismember(Redis.buildKey(remoteKey, Redis.KeyGroups.Profiles.Relationships.Ignoring), this.profileId);
|
||||||
@@ -211,12 +212,12 @@ export class ProfileRelationshipManager extends ProfileContentManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async sendPlayerFriendRequest(player: Profile) {
|
async sendPlayerFriendRequest(player: Profile) {
|
||||||
await Redis.Database.sadd(Redis.buildKey(this.createRemoteRootKey(player.getId()), Redis.KeyGroups.Profiles.Relationships.IncomingFriendRequests), this.profileId);
|
await Redis.Database.sadd(Redis.buildKey(this.#createRemoteRootKey(player.getId()), Redis.KeyGroups.Profiles.Relationships.IncomingFriendRequests), this.profileId);
|
||||||
await Redis.Database.sadd(this.#outgoingFriends, player.getId());
|
await Redis.Database.sadd(this.#outgoingFriends, player.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
async removePlayerFriendRequest(player: Profile) {
|
async removePlayerFriendRequest(player: Profile) {
|
||||||
await Redis.Database.srem(Redis.buildKey(this.createRemoteRootKey(player.getId()), Redis.KeyGroups.Profiles.Relationships.IncomingFriendRequests), this.profileId);
|
await Redis.Database.srem(Redis.buildKey(this.#createRemoteRootKey(player.getId()), Redis.KeyGroups.Profiles.Relationships.IncomingFriendRequests), this.profileId);
|
||||||
await Redis.Database.srem(this.#outgoingFriends, player.getId());
|
await Redis.Database.srem(this.#outgoingFriends, player.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -23,11 +23,15 @@ export class ProfileRoomsManager extends ProfileContentManager {
|
|||||||
#rootKey = Redis.buildKey(
|
#rootKey = Redis.buildKey(
|
||||||
Redis.KeyGroups.Profiles.Root,
|
Redis.KeyGroups.Profiles.Root,
|
||||||
this.profileId.toString(),
|
this.profileId.toString(),
|
||||||
Redis.KeyGroups.Profiles.Avatar.Root
|
Redis.KeyGroups.Profiles.Rooms
|
||||||
);
|
);
|
||||||
|
|
||||||
async getRooms() {
|
async getOwnedRoomIds() {
|
||||||
// get player rooms
|
return (await Redis.Database.smembers(this.#rootKey)).map(val => parseInt(val)).filter(val => !isNaN(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
async addOwnedRoomId(id: number) {
|
||||||
|
await Redis.Database.sadd(this.#rootKey, id.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -16,23 +16,25 @@ 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 Logging from "@proxnet/undead-logging";
|
||||||
import Dictionary from "./usernames.ts";
|
import Dictionary from "./usernames.ts";
|
||||||
import { Config } from "../config.ts";
|
import { Config } from "../config.ts";
|
||||||
import { AuthType } from "./users.ts";
|
import { AuthType } from "./users.ts";
|
||||||
import * as JsonWebToken from "@gz/jwt";
|
import * as JsonWebToken from "@gz/jwt";
|
||||||
import { TokenBaseFormat } from "../apiutils.ts";
|
import { TokenBaseFormat } from "../apiutils.ts";
|
||||||
import { DeviceClass, RoomInstance, VRMovementMode } from "./live/types.ts";
|
import { DeviceClass, VRMovementMode } from "./live/types.ts";
|
||||||
import { SettingKey } from "./content/settings.ts";
|
import { SettingKey } from "./content/settings.ts";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { SignalRSocketHandler } from "../socket/socket.ts";
|
import { SignalRSocketHandler } from "../socket/socket.ts";
|
||||||
import { ProfileSettingsManager } from "./profile/settings.ts";
|
import { ProfileSettingsManager } from "./profile/settings.ts";
|
||||||
import { ProfileProgressionManager } from "./profile/progression.ts";
|
import { ProfileProgressionManager } from "./profile/progression.ts";
|
||||||
import { ProfileReputationManager } from "./profile/reputation.ts";
|
import { ProfileReputationManager } from "./profile/reputation.ts";
|
||||||
import Logging from "@proxnet/undead-logging";
|
|
||||||
import { ProfileRelationshipManager } from "./profile/relationships.ts";
|
import { ProfileRelationshipManager } from "./profile/relationships.ts";
|
||||||
import { ProfileAvatarManager } from "./profile/avatar.ts";
|
import { ProfileAvatarManager } from "./profile/avatar.ts";
|
||||||
import { EventManager } from "./baseevent.ts";
|
import { EventManager } from "./baseevent.ts";
|
||||||
import { ProfileEvents, ProfileUpdatedEvent } from "./profileevents.ts";
|
import { ProfileEvents, ProfileUpdatedEvent } from "./profileevents.ts";
|
||||||
|
import { Instance } from "./live/instances.ts";
|
||||||
|
import { ProfileRoomsManager } from "./profile/rooms.ts";
|
||||||
|
|
||||||
const config = Config.getConfig();
|
const config = Config.getConfig();
|
||||||
|
|
||||||
@@ -149,7 +151,6 @@ class Profile extends EventManager {
|
|||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
// surely this can be written better
|
|
||||||
static getExportAccount(id: number): Promise<SelfAccountExport | null> {
|
static getExportAccount(id: number): Promise<SelfAccountExport | null> {
|
||||||
return new Promise((resolve, _reject) => {
|
return new Promise((resolve, _reject) => {
|
||||||
Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profiles.Root, id.toString(), Redis.KeyGroups.Profiles.Username)).then((val) => {
|
Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profiles.Root, id.toString(), Redis.KeyGroups.Profiles.Username)).then((val) => {
|
||||||
@@ -177,6 +178,11 @@ class Profile extends EventManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get player account exports in bulk. Returns only profiles that exist.
|
||||||
|
* @param ids Player IDs
|
||||||
|
* @returns Promise - Array of Profiles
|
||||||
|
*/
|
||||||
static async getExportAccountsBulk(ids: number[]) {
|
static async getExportAccountsBulk(ids: number[]) {
|
||||||
const accs = await Promise.all(
|
const accs = await Promise.all(
|
||||||
ids.map((val) => this.getExportAccount(val)),
|
ids.map((val) => this.getExportAccount(val)),
|
||||||
@@ -186,7 +192,7 @@ class Profile extends EventManager {
|
|||||||
|
|
||||||
#id: number;
|
#id: number;
|
||||||
|
|
||||||
#instance: RoomInstance | null = null;
|
#instance: Instance | null = null;
|
||||||
|
|
||||||
#socket: SignalRSocketHandler | null = null;
|
#socket: SignalRSocketHandler | null = null;
|
||||||
|
|
||||||
@@ -195,6 +201,7 @@ class Profile extends EventManager {
|
|||||||
Reputation: ProfileReputationManager;
|
Reputation: ProfileReputationManager;
|
||||||
Relationships: ProfileRelationshipManager;
|
Relationships: ProfileRelationshipManager;
|
||||||
Avatar: ProfileAvatarManager;
|
Avatar: ProfileAvatarManager;
|
||||||
|
Rooms: ProfileRoomsManager;
|
||||||
|
|
||||||
constructor(id: number) {
|
constructor(id: number) {
|
||||||
super();
|
super();
|
||||||
@@ -206,6 +213,7 @@ class Profile extends EventManager {
|
|||||||
this.Reputation = new ProfileReputationManager(this.#id);
|
this.Reputation = new ProfileReputationManager(this.#id);
|
||||||
this.Relationships = new ProfileRelationshipManager(this.#id);
|
this.Relationships = new ProfileRelationshipManager(this.#id);
|
||||||
this.Avatar = new ProfileAvatarManager(this.#id);
|
this.Avatar = new ProfileAvatarManager(this.#id);
|
||||||
|
this.Rooms = new ProfileRoomsManager(this.#id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#emitProfileUpdated() {
|
#emitProfileUpdated() {
|
||||||
@@ -216,7 +224,7 @@ class Profile extends EventManager {
|
|||||||
this.emit(ProfileEvents.BaseUpdated, ev);
|
this.emit(ProfileEvents.BaseUpdated, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
setInstance(instance: RoomInstance | null) {
|
setInstance(instance: Instance | null) {
|
||||||
this.#instance = instance;
|
this.#instance = instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -24,7 +24,6 @@ import { TokenBaseFormat } from "../apiutils.ts";
|
|||||||
type UserInitOptions = {
|
type UserInitOptions = {
|
||||||
client_id: string;
|
client_id: string;
|
||||||
pubkey: string;
|
pubkey: string;
|
||||||
captcha?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum AuthType {
|
export enum AuthType {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -71,7 +71,7 @@ export const KeyGroups = {
|
|||||||
},
|
},
|
||||||
Content: {
|
Content: {
|
||||||
Root: "content",
|
Root: "content",
|
||||||
Files: "file-meta",
|
Words: "charades"
|
||||||
},
|
},
|
||||||
Profile_Usernames: "profile-usernames",
|
Profile_Usernames: "profile-usernames",
|
||||||
PlatformAssociations: "platforms",
|
PlatformAssociations: "platforms",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
19
src/main.ts
19
src/main.ts
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -27,15 +27,16 @@ import { decode } from "@gz/jwt";
|
|||||||
import UnifiedProfile, { ProfileTokenFormat } from "./data/profiles.ts";
|
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 { GameConfigs } from "./data/config.ts";
|
import { GameConfigs } from "./data/config.ts";
|
||||||
import { RootPath } from "./data/content/baseimages.ts";
|
import { getVersion } from "./ver.ts";
|
||||||
|
import Rooms from "./data/content/rooms.ts";
|
||||||
|
import { PushNotificationId } from "./socket/types.ts";
|
||||||
|
|
||||||
const instanceId = generateRandomString(64);
|
const instanceId = generateRandomString(64);
|
||||||
|
|
||||||
const log = new Log.default("Main");
|
const log = new Log.default("Main");
|
||||||
|
|
||||||
log.i(`Starting Galvanic Corrosion..`);
|
log.i(`Galvanic Corrosion '${await getVersion()}'`);
|
||||||
|
|
||||||
const config = Config.getConfig();
|
const config = Config.getConfig();
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ try {
|
|||||||
}}, async (req: Request, info: Deno.ServeHandlerInfo<Deno.NetAddr>) => {
|
}}, async (req: Request, info: Deno.ServeHandlerInfo<Deno.NetAddr>) => {
|
||||||
const path = new URL(req.url).pathname;
|
const path = new URL(req.url).pathname;
|
||||||
const upgrade = req.headers.get('Upgrade') === 'websocket';
|
const upgrade = req.headers.get('Upgrade') === 'websocket';
|
||||||
log.n(`U:${upgrade}; ${info.remoteAddr.hostname}:${info.remoteAddr.port} ${req.method} ${path}`);
|
log.n(`SOCK U:${upgrade}; ${info.remoteAddr.hostname}:${info.remoteAddr.port} ${req.method} ${path}`);
|
||||||
|
|
||||||
if (path === '/negotiate' && req.method == 'POST')
|
if (path === '/negotiate' && req.method == 'POST')
|
||||||
return new Response(JSON.stringify({}));
|
return new Response(JSON.stringify({}));
|
||||||
@@ -199,15 +200,17 @@ try {
|
|||||||
Deno.addSignalListener("SIGINT", () => {
|
Deno.addSignalListener("SIGINT", () => {
|
||||||
if (shuttingDown) return;
|
if (shuttingDown) return;
|
||||||
shuttingDown = true;
|
shuttingDown = true;
|
||||||
|
for (const handoff of SocketHandoff.all()) handoff.complete();
|
||||||
|
for (const sock of UnifiedProfile.getAllSockets()) sock.sendNotification(PushNotificationId.ModerationQuitGame);
|
||||||
|
});
|
||||||
|
Deno.addSignalListener("SIGINT", () => {
|
||||||
|
if (shuttingDown) return;
|
||||||
log.i(`Shutting down`);
|
log.i(`Shutting down`);
|
||||||
|
|
||||||
abort.abort(); // websockets
|
abort.abort(); // websockets
|
||||||
http.close();
|
http.close();
|
||||||
http.closeAllConnections();
|
http.closeAllConnections();
|
||||||
});
|
});
|
||||||
Deno.addSignalListener("SIGINT", () => {
|
|
||||||
for (const handoff of SocketHandoff.all()) handoff.complete();
|
|
||||||
});
|
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
20
src/path.ts
Normal file
20
src/path.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/* 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 { platform } from "node:process";
|
||||||
|
|
||||||
|
export const RootPath = Deno.mainModule.substring(platform == 'win32' ? 8 : 7, Deno.mainModule.length - 11);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -15,14 +15,17 @@ 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 { APIUtils, NoBody } 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";
|
import { AuthType } from "../../data/users.ts";
|
||||||
|
import Logging from "@proxnet/undead-logging";
|
||||||
|
|
||||||
export const route = APIUtils.createRouter("/account");
|
export const route = APIUtils.createRouter("/account");
|
||||||
|
|
||||||
|
const log = new Logging("AccountRoute");
|
||||||
|
|
||||||
const CreateAccountRequestBodySchema = z.object({
|
const CreateAccountRequestBodySchema = z.object({
|
||||||
platform: z.string(),
|
platform: z.string(),
|
||||||
platformId: z.string(),
|
platformId: z.string(),
|
||||||
@@ -70,11 +73,9 @@ route.router.get("/bulk",
|
|||||||
|
|
||||||
} else if (typeof rq.query.id == "string") {
|
} else if (typeof rq.query.id == "string") {
|
||||||
|
|
||||||
const id = parseInt(rq.query.id, 10);
|
const id = parseInt(rq.query.id);
|
||||||
if (isNaN(id)) {
|
if (isNaN(id)) {
|
||||||
rs.json(
|
rs.json(APIUtils.genericResponseFormat(true, "Query data error"));
|
||||||
APIUtils.genericResponseFormat(true, "Query data error"),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
rs.json([await Profile.getExportAccount(id)].filter((val) => val !== null));
|
rs.json([await Profile.getExportAccount(id)].filter((val) => val !== null));
|
||||||
@@ -116,7 +117,7 @@ route.router.put("/me/displayname",
|
|||||||
express.urlencoded({ extended: true }),
|
express.urlencoded({ extended: true }),
|
||||||
APIUtils.validateRequestBody(DisplayNameUpdateSchema),
|
APIUtils.validateRequestBody(DisplayNameUpdateSchema),
|
||||||
|
|
||||||
(rq: express.Request<{}, {}, DisplayNameUpdate>, rs: express.Response, nxt: express.NextFunction) => {
|
(rq: express.Request<NoBody, NoBody, DisplayNameUpdate>, rs: express.Response, nxt: express.NextFunction) => {
|
||||||
rs.locals.profile.setDisplayName(rq.body.displayName);
|
rs.locals.profile.setDisplayName(rq.body.displayName);
|
||||||
nxt();
|
nxt();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -39,6 +39,7 @@ import { route as CommunityBoardRoute } from "./api/communityboard.ts";
|
|||||||
import { route as PlayerEventsRoute } from "./api/playerevents.ts";
|
import { route as PlayerEventsRoute } from "./api/playerevents.ts";
|
||||||
import { route as StorefrontsRoute } from "./api/storefronts.ts";
|
import { route as StorefrontsRoute } from "./api/storefronts.ts";
|
||||||
import { route as AnnouncementRoute } from "./api/announcement.ts";
|
import { route as AnnouncementRoute } from "./api/announcement.ts";
|
||||||
|
import { route as ActivitiesRoute } from "./api/activities.ts";
|
||||||
|
|
||||||
export const route = APIUtils.createRouter("/api");
|
export const route = APIUtils.createRouter("/api");
|
||||||
|
|
||||||
@@ -64,4 +65,5 @@ route.router.use(ImagesRoute.path, ImagesRoute.router);
|
|||||||
route.router.use(CommunityBoardRoute.path, CommunityBoardRoute.router);
|
route.router.use(CommunityBoardRoute.path, CommunityBoardRoute.router);
|
||||||
route.router.use(PlayerEventsRoute.path, PlayerEventsRoute.router);
|
route.router.use(PlayerEventsRoute.path, PlayerEventsRoute.router);
|
||||||
route.router.use(StorefrontsRoute.path, StorefrontsRoute.router);
|
route.router.use(StorefrontsRoute.path, StorefrontsRoute.router);
|
||||||
route.router.use(AnnouncementRoute.path, AnnouncementRoute.router);
|
route.router.use(AnnouncementRoute.path, AnnouncementRoute.router);
|
||||||
|
route.router.use(ActivitiesRoute.path, ActivitiesRoute.router);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
34
src/routes/api/activities.ts
Normal file
34
src/routes/api/activities.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* 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 { getWords } from "../../data/content/activities.ts";
|
||||||
|
|
||||||
|
export const route = APIUtils.createRouter("/activities");
|
||||||
|
|
||||||
|
const rateLimit = new APIUtils.RateLimiter();
|
||||||
|
|
||||||
|
const words = getWords();
|
||||||
|
route.router.get('/charades/v1/words',
|
||||||
|
|
||||||
|
rateLimit.middle(),
|
||||||
|
|
||||||
|
(_rq, rs) => {
|
||||||
|
rs.json(words);
|
||||||
|
},
|
||||||
|
|
||||||
|
);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -16,6 +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 { APIUtils } from "../../apiutils.ts";
|
import { APIUtils } from "../../apiutils.ts";
|
||||||
|
import { ObjectiveType } from "../../data/objectives.ts";
|
||||||
import { AuthType } from "../../data/users.ts";
|
import { AuthType } from "../../data/users.ts";
|
||||||
|
|
||||||
export const route = APIUtils.createRouter('/checklist');
|
export const route = APIUtils.createRouter('/checklist');
|
||||||
@@ -25,6 +26,171 @@ route.router.get('/v1/current',
|
|||||||
APIUtils.Authentication,
|
APIUtils.Authentication,
|
||||||
APIUtils.AuthenticationType(AuthType.Game),
|
APIUtils.AuthenticationType(AuthType.Game),
|
||||||
|
|
||||||
APIUtils.emptyArrayResponse
|
(_rq, rs) => {
|
||||||
|
rs.json([
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Order: 1,
|
||||||
|
Objective: ObjectiveType.CompleteAnyDaily,
|
||||||
|
Count: 1,
|
||||||
|
CreditAmount: -1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
);
|
);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -36,6 +36,17 @@ route.router.get('/v1/myprogress',
|
|||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
route.router.post('/v1/updateobjective',
|
||||||
|
|
||||||
|
APIUtils.Authentication,
|
||||||
|
APIUtils.AuthenticationType(AuthType.Game),
|
||||||
|
|
||||||
|
(_rq, rs) => {
|
||||||
|
rs.sendStatus(200);
|
||||||
|
},
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
interface ClearGroupRequestBody {
|
interface ClearGroupRequestBody {
|
||||||
Group: number
|
Group: number
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -57,7 +57,7 @@ route.router.post('/v1/bulk',
|
|||||||
express.urlencoded({ extended: true }),
|
express.urlencoded({ extended: true }),
|
||||||
APIUtils.validateRequestBody(reputationBulkSchema),
|
APIUtils.validateRequestBody(reputationBulkSchema),
|
||||||
|
|
||||||
async (rq: express.Request<NoBody, {}, ReputationBulkBody>, rs: express.Response) => {
|
async (rq: express.Request<NoBody, NoBody, ReputationBulkBody>, rs: express.Response) => {
|
||||||
if (typeof rq.body.Ids == 'object') {
|
if (typeof rq.body.Ids == 'object') {
|
||||||
const reputations = rq.body.Ids
|
const reputations = rq.body.Ids
|
||||||
.map(id => parseInt(id)).filter(id => !isNaN(id)) // parse as int[] and filter out non-numbers
|
.map(id => parseInt(id)).filter(id => !isNaN(id)) // parse as int[] and filter out non-numbers
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -68,7 +68,7 @@ route.router.post('/v1/progression/bulk',
|
|||||||
express.urlencoded({ extended: true }),
|
express.urlencoded({ extended: true }),
|
||||||
APIUtils.validateRequestBody(progressionBulkSchema),
|
APIUtils.validateRequestBody(progressionBulkSchema),
|
||||||
|
|
||||||
async (rq: express.Request<NoBody, {}, ProgressionBulkBody>, rs: express.Response) => {
|
async (rq: express.Request<NoBody, NoBody, ProgressionBulkBody>, rs: express.Response) => {
|
||||||
if (typeof rq.body.Ids == 'object') {
|
if (typeof rq.body.Ids == 'object') {
|
||||||
const progressions = rq.body.Ids
|
const progressions = rq.body.Ids
|
||||||
.map(id => parseInt(id)).filter(id => !isNaN(id)) // filter out non-numbers
|
.map(id => parseInt(id)).filter(id => !isNaN(id)) // filter out non-numbers
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -15,11 +15,13 @@ 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 Rooms from "../../data/content/rooms.ts";
|
import Rooms from "../../data/content/rooms.ts";
|
||||||
import { RoomDataTypes } from "../../data/content/rooms/DataTypes.ts";
|
import { RoomDataTypes } from "../../data/content/rooms/DataTypes.ts";
|
||||||
import { AuthType } from "../../data/users.ts";
|
import { AuthType } from "../../data/users.ts";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
|
import { RoomFactory } from "../../data/content/rooms/RoomFactory.ts";
|
||||||
|
|
||||||
export const route = APIUtils.createRouter("/rooms");
|
export const route = APIUtils.createRouter("/rooms");
|
||||||
|
|
||||||
@@ -54,7 +56,19 @@ route.router.get('/v2/myrooms',
|
|||||||
APIUtils.Authentication,
|
APIUtils.Authentication,
|
||||||
APIUtils.AuthenticationType(AuthType.Game),
|
APIUtils.AuthenticationType(AuthType.Game),
|
||||||
|
|
||||||
APIUtils.emptyArrayResponse
|
async (_rq, rs) => {
|
||||||
|
const ids = await rs.locals.profile.Rooms.getOwnedRoomIds();
|
||||||
|
if (ids.length == 0) {
|
||||||
|
rs.json([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const roomFactoriesPreInit = ids.map(id => new RoomFactory({ id: id }));
|
||||||
|
const roomFactories = (await Promise.all(roomFactoriesPreInit.map(factory => factory.init()))).filter(val => val !== null);
|
||||||
|
const detailsPromises = (await Promise.all(roomFactories.map(factory => factory.export())));
|
||||||
|
|
||||||
|
rs.json(detailsPromises.map(roomDetails => roomDetails.Room));
|
||||||
|
},
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -119,8 +133,58 @@ route.router.post('/v1/roomRolePermissions',
|
|||||||
APIUtils.Authentication,
|
APIUtils.Authentication,
|
||||||
APIUtils.AuthenticationType(AuthType.Game),
|
APIUtils.AuthenticationType(AuthType.Game),
|
||||||
|
|
||||||
(rq, rs) => {
|
(_rq, rs) => {
|
||||||
rs.sendStatus(200);
|
rs.sendStatus(200);
|
||||||
},
|
},
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
route.router.get('/v1/agRoomIds',
|
||||||
|
|
||||||
|
APIUtils.Authentication,
|
||||||
|
APIUtils.AuthenticationType(AuthType.Game),
|
||||||
|
|
||||||
|
async (_rq, rs) => {
|
||||||
|
|
||||||
|
const rooms = await Rooms.getAllBuiltinRoomGenerations();
|
||||||
|
rs.json(rooms.map(det => det.Room.RoomId));
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
const CloneRoomSchema = z.object({
|
||||||
|
Name: z.string(),
|
||||||
|
RoomId: z.number()
|
||||||
|
});
|
||||||
|
interface CloneRoomBody {
|
||||||
|
Name: string,
|
||||||
|
RoomId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
route.router.post('/v1/clone',
|
||||||
|
|
||||||
|
APIUtils.Authentication,
|
||||||
|
APIUtils.AuthenticationType(AuthType.Game),
|
||||||
|
express.json(),
|
||||||
|
APIUtils.validateRequestBody(CloneRoomSchema),
|
||||||
|
|
||||||
|
async (rq: express.Request<NoBody, NoBody, CloneRoomBody>, rs: express.Response) => {
|
||||||
|
|
||||||
|
const room = await Rooms.cloneRoom(rq.body.RoomId, rq.body.Name, rs.locals.profile);
|
||||||
|
|
||||||
|
const masterRoomFactory = await new RoomFactory({ id: rq.body.RoomId }).init();
|
||||||
|
|
||||||
|
rs.json({
|
||||||
|
Result: room.result,
|
||||||
|
RoomDetails: room.result == RoomDataTypes.CreateModifyRoomStatus.Success ? await room.factory?.export() : await masterRoomFactory?.export()
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
room.result == RoomDataTypes.CreateModifyRoomStatus.Success
|
||||||
|
&& room.factory
|
||||||
|
) rs.locals.profile.Rooms.addOwnedRoomId(room.factory.RoomId);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -18,7 +18,7 @@ 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 { AuthType } from "../../data/users.ts";
|
||||||
import { CurrencyType, StorefrontBalanceType } from "../../data/content/storefronts.ts";
|
import { StorefrontBalanceType } from "../../data/content/storefronts.ts";
|
||||||
|
|
||||||
export const route = APIUtils.createRouter('/storefronts');
|
export const route = APIUtils.createRouter('/storefronts');
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -16,11 +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 Logging from "@proxnet/undead-logging";
|
import Logging from "@proxnet/undead-logging";
|
||||||
import { APIUtils } from "../../apiutils.ts";
|
import { APIUtils, NoBody } from "../../apiutils.ts";
|
||||||
import Matchmaking from "../../data/live/base.ts";
|
import Matchmaking from "../../data/live/base.ts";
|
||||||
import { MatchmakingErrorCode } from "../../data/live/types.ts";
|
import { MatchmakingErrorCode } from "../../data/live/types.ts";
|
||||||
import { AuthType } from "../../data/users.ts";
|
import { AuthType } from "../../data/users.ts";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
const log = new Logging("MatchGotoRoute");
|
const log = new Logging("MatchGotoRoute");
|
||||||
|
|
||||||
@@ -31,13 +32,31 @@ interface MatchmakingParams {
|
|||||||
subRoomName?: string
|
subRoomName?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ProperCaseBooleanSchema = z.preprocess((val) => {
|
||||||
|
if (val === "True") return true;
|
||||||
|
if (val === "False") return false;
|
||||||
|
if (typeof val === "boolean") return val; // allow raw booleans too
|
||||||
|
return val; // will fail validation
|
||||||
|
}, z.boolean());
|
||||||
|
|
||||||
|
interface MatchmakingOptions {
|
||||||
|
CreatePrivateInstance?: string,
|
||||||
|
BypassMovementModeRestriction?: string
|
||||||
|
}
|
||||||
|
|
||||||
route.router.post('/room/:roomName',
|
route.router.post('/room/:roomName',
|
||||||
|
|
||||||
APIUtils.Authentication,
|
APIUtils.Authentication,
|
||||||
APIUtils.AuthenticationType(AuthType.Game),
|
APIUtils.AuthenticationType(AuthType.Game),
|
||||||
APIUtils.startTimer,
|
APIUtils.startTimer,
|
||||||
|
express.urlencoded({ extended: true }),
|
||||||
|
APIUtils.validateRequestBody(z.object({
|
||||||
|
CreatePrivateInstance: ProperCaseBooleanSchema.optional(),
|
||||||
|
BypassMovementModeRestriction: ProperCaseBooleanSchema.optional()
|
||||||
|
})),
|
||||||
|
|
||||||
async (rq: express.Request<MatchmakingParams>, rs: express.Response, nxt: express.NextFunction) => {
|
async (rq: express.Request<MatchmakingParams, NoBody, MatchmakingOptions>, rs: express.Response, nxt: express.NextFunction) => {
|
||||||
|
log.d(`Player ${rs.locals.profile.getId()} is requesting to matchmake\n Room: '${rq.params.roomName}'\n Body: ${JSON.stringify(rq.body)}`);
|
||||||
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,7 +64,11 @@ 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,
|
||||||
|
private: rq.body.CreatePrivateInstance ? rq.body.CreatePrivateInstance == 'True' : undefined
|
||||||
|
}));
|
||||||
nxt();
|
nxt();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -57,8 +80,10 @@ route.router.post('/room/:roomName/:subRoomName',
|
|||||||
APIUtils.Authentication,
|
APIUtils.Authentication,
|
||||||
APIUtils.AuthenticationType(AuthType.Game),
|
APIUtils.AuthenticationType(AuthType.Game),
|
||||||
APIUtils.startTimer,
|
APIUtils.startTimer,
|
||||||
|
express.urlencoded({ extended: true }),
|
||||||
|
|
||||||
async (rq: express.Request<MatchmakingParams>, rs: express.Response, nxt: express.NextFunction) => {
|
async (rq: express.Request<MatchmakingParams, NoBody, MatchmakingOptions>, rs: express.Response, nxt: express.NextFunction) => {
|
||||||
|
log.d(`Player ${rs.locals.profile.getId()} is requesting to matchmake\n Room: '${rq.params.roomName}'\n Subroom: '${rq.params.subRoomName}'\n Body: ${JSON.stringify(rq.body)}`);
|
||||||
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({
|
||||||
@@ -66,7 +91,12 @@ route.router.post('/room/:roomName/:subRoomName',
|
|||||||
});
|
});
|
||||||
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,
|
||||||
|
private: rq.body.CreatePrivateInstance ? rq.body.CreatePrivateInstance == 'True' : undefined
|
||||||
|
}));
|
||||||
nxt();
|
nxt();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -25,7 +25,6 @@ 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");
|
||||||
|
|
||||||
@@ -86,7 +85,7 @@ route.router.post('/logout',
|
|||||||
APIUtils.validateRequestBody(LoginSchema),
|
APIUtils.validateRequestBody(LoginSchema),
|
||||||
|
|
||||||
(_rq, rs) => {
|
(_rq, rs) => {
|
||||||
Instances.removePlayerFromCurrentInstance(rs.locals.profile);
|
rs.locals.profile.getInstance()?.removePlayer(rs.locals.profile);
|
||||||
rs.sendStatus(200);
|
rs.sendStatus(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,10 +128,10 @@ route.router.put('/statusvisibility',
|
|||||||
);
|
);
|
||||||
|
|
||||||
interface VRMovementModeBody {
|
interface VRMovementModeBody {
|
||||||
vrMovementMode: PlayerStatusVisibility
|
vrMovementMode: VRMovementMode
|
||||||
}
|
}
|
||||||
const VRMovementModeSchema = z.object({
|
const VRMovementModeSchema = z.object({
|
||||||
vrMovementMode: z.nativeEnum(VRMovementMode)
|
vrMovementMode: z.enum(Object.values(VRMovementMode).map(String) as [string, ...string[]])
|
||||||
});
|
});
|
||||||
|
|
||||||
route.router.put('/vrmovementmode',
|
route.router.put('/vrmovementmode',
|
||||||
@@ -155,7 +154,7 @@ route.router.put('/photonregionpings',
|
|||||||
APIUtils.Authentication,
|
APIUtils.Authentication,
|
||||||
APIUtils.AuthenticationType(AuthType.Game),
|
APIUtils.AuthenticationType(AuthType.Game),
|
||||||
|
|
||||||
(rq, rs) => {
|
(_rq, rs) => {
|
||||||
rs.sendStatus(200);
|
rs.sendStatus(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -48,8 +48,8 @@ route.router.get('/:id/instances',
|
|||||||
roomId: parsedId,
|
roomId: parsedId,
|
||||||
subRoomId: instance.subRoomId,
|
subRoomId: instance.subRoomId,
|
||||||
isFull: instance.isFull,
|
isFull: instance.isFull,
|
||||||
createdAt: new Date().toISOString(), // TODO: rewrite instance - create instance class rather than using sets - include datetime when instance was created
|
createdAt: instance.timeCreated,
|
||||||
playerIds: Instances.getInstancePlayers(instance).values().toArray().map(profile => profile.getId())
|
playerIds: instance.getAllPlayers().map(profile => profile.getId())
|
||||||
})));
|
})));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
@@ -34,10 +34,9 @@ import {
|
|||||||
import { SocketTarget } from "./targets/targetbase.ts";
|
import { SocketTarget } from "./targets/targetbase.ts";
|
||||||
import { PlayerSocketSubscriptionTarget } from "./targets/SubscribeToPlayers.ts";
|
import { PlayerSocketSubscriptionTarget } from "./targets/SubscribeToPlayers.ts";
|
||||||
import Presence from "../data/live/presence.ts";
|
import Presence from "../data/live/presence.ts";
|
||||||
import Instances from "../data/live/instances.ts";
|
|
||||||
import Matchmaking from "../data/live/base.ts";
|
import Matchmaking from "../data/live/base.ts";
|
||||||
|
|
||||||
const logmessages = true;
|
const logmessages = false;
|
||||||
|
|
||||||
export class SignalRSocketHandler {
|
export class SignalRSocketHandler {
|
||||||
|
|
||||||
@@ -50,6 +49,8 @@ export class SignalRSocketHandler {
|
|||||||
|
|
||||||
#PeriodicalId: number;
|
#PeriodicalId: number;
|
||||||
|
|
||||||
|
#killed = false;
|
||||||
|
|
||||||
constructor(socket: WebSocket, player: Profile) {
|
constructor(socket: WebSocket, player: Profile) {
|
||||||
|
|
||||||
this.#socket = socket;
|
this.#socket = socket;
|
||||||
@@ -62,6 +63,7 @@ export class SignalRSocketHandler {
|
|||||||
this.#Targets.set('SubscribeToPlayers', new PlayerSocketSubscriptionTarget(this));
|
this.#Targets.set('SubscribeToPlayers', new PlayerSocketSubscriptionTarget(this));
|
||||||
|
|
||||||
this.#PeriodicalId = setInterval(async () => {
|
this.#PeriodicalId = setInterval(async () => {
|
||||||
|
if (this.#killed) return;
|
||||||
if (this.#socket.readyState !== this.#socket.CLOSED) {
|
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());
|
||||||
@@ -69,9 +71,18 @@ export class SignalRSocketHandler {
|
|||||||
}
|
}
|
||||||
}, 8000);
|
}, 8000);
|
||||||
|
|
||||||
|
this.#socket.onclose = (ev) => {
|
||||||
|
this.#log.d(`Close reason: ${ev.reason}`);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async #dispatchTarget<T = unknown>(target: string, args: unknown): Promise<TargetResult> {
|
async #dispatchTarget<T = unknown>(target: string, args: unknown): Promise<TargetResult> {
|
||||||
|
if (this.#killed) {
|
||||||
|
const error = "Tried to dispatch socket target on dead socket";
|
||||||
|
this.#log.w(error);
|
||||||
|
return { type: TargetResultType.Failure, err: error };
|
||||||
|
}
|
||||||
const targetExec = this.#Targets.get(target);
|
const targetExec = this.#Targets.get(target);
|
||||||
if (!targetExec) return { type: TargetResultType.NotATarget } as TargetResultNotATarget;
|
if (!targetExec) return { type: TargetResultType.NotATarget } as TargetResultNotATarget;
|
||||||
else {
|
else {
|
||||||
@@ -152,6 +163,7 @@ export class SignalRSocketHandler {
|
|||||||
|
|
||||||
destroy(sock: SignalRSocketHandler, internal: boolean | undefined = false) {
|
destroy(sock: SignalRSocketHandler, internal: boolean | undefined = false) {
|
||||||
return () => {
|
return () => {
|
||||||
|
sock.#killed = true;
|
||||||
clearInterval(sock.#PeriodicalId);
|
clearInterval(sock.#PeriodicalId);
|
||||||
sock.sendRaw({ type: 7, error: "Socket closed" });
|
sock.sendRaw({ type: 7, error: "Socket closed" });
|
||||||
if (!internal) sock.#socket.close();
|
if (!internal) sock.#socket.close();
|
||||||
@@ -160,7 +172,7 @@ export class SignalRSocketHandler {
|
|||||||
|
|
||||||
for (const target of sock.#Targets.values()) target.destroy();
|
for (const target of sock.#Targets.values()) target.destroy();
|
||||||
|
|
||||||
Instances.removePlayerFromCurrentInstance(this.#profile);
|
this.#profile.getInstance()?.removePlayer(this.#profile);
|
||||||
Matchmaking.deleteLoginLock(this.#profile);
|
Matchmaking.deleteLoginLock(this.#profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,13 +186,13 @@ export class SignalRSocketHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendNotification(id: PushNotificationId | string, args: object) {
|
sendNotification(id: PushNotificationId | string, args?: object) {
|
||||||
const msg: SignalRMessage = {
|
const msg: SignalRMessage = {
|
||||||
type: SignalMessageType.Invocation,
|
type: SignalMessageType.Invocation,
|
||||||
target: "Notification",
|
target: "Notification",
|
||||||
arguments: [JSON.stringify({
|
arguments: [JSON.stringify({
|
||||||
Id: id,
|
Id: id,
|
||||||
Msg: args
|
Msg: args ? args : {}
|
||||||
})]
|
})]
|
||||||
}
|
}
|
||||||
this.sendRaw(msg);
|
this.sendRaw(msg);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* 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
|
||||||
it under the terms of the GNU Affero General Public License as published
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
|||||||
25
src/ver.ts
Normal file
25
src/ver.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/* 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/>. */
|
||||||
|
|
||||||
|
export async function getVersion(): Promise<'development' | 'unknown ver' | string> {
|
||||||
|
try {
|
||||||
|
const ver = await import('../ver.ts');
|
||||||
|
return ver.Version;
|
||||||
|
} catch {
|
||||||
|
return "unknown ver"
|
||||||
|
}
|
||||||
|
}
|
||||||
18
ver.ts
Normal file
18
ver.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/* 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/>. */
|
||||||
|
|
||||||
|
export const Version = 'development';
|
||||||
Reference in New Issue
Block a user