aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfboy248 <georgejvindkarlsen@gmail.com>2024-09-16 18:19:19 +0200
committerWolfboy248 <georgejvindkarlsen@gmail.com>2024-09-16 18:19:19 +0200
commit4c036c9a8bb39abe3bc10a30fdfcf53fb9613e21 (patch)
tree2162b11b64083aca965724f89e658164eec28f25
parentrefactor: rankings page (diff)
parentrefactor: proper game/map ordering (diff)
downloadlphub-4c036c9a8bb39abe3bc10a30fdfcf53fb9613e21.tar.gz
lphub-4c036c9a8bb39abe3bc10a30fdfcf53fb9613e21.tar.bz2
lphub-4c036c9a8bb39abe3bc10a30fdfcf53fb9613e21.zip
Rankings page
-rw-r--r--RULES.md42
-rw-r--r--backend/handlers/map.go8
-rw-r--r--frontend/src/App.tsx2
-rw-r--r--frontend/src/css/Rules.css3
-rw-r--r--frontend/src/pages/Rules.tsx37
5 files changed, 88 insertions, 4 deletions
diff --git a/RULES.md b/RULES.md
new file mode 100644
index 0000000..99c5a3e
--- /dev/null
+++ b/RULES.md
@@ -0,0 +1,42 @@
1# Rules
2
3To compete on the leaderboard, you must adhere to the following rules. Failure to do so may result in warnings or bans depending on severity.
4
5## Game
6
7All runs must be performed on the latest release of Portal 2. Game files must not be modified in any way (things such as binary or dll files).
8Launch options that alter game behavior (e.g., `-tickrate`) are prohibited
9The use of scripts, cheats, plugins, third-party software, or anything that changes the game's behavior is strictly forbidden.
10The only allowed plugin is SourceAutoRecord and if used it must be latest version.
11
12### Texture Modifications
13
14You may modify texture files as long as it doesn't give you any advantage.
15Both `.vtf` and `.vmt` files associated with these textures can be modified.
16Models cannot be modified as they alter game behaviour
17
18## Runs
19
20### Demos
21
22Proof of your run must be recorded using demos. To start recording, type `record <demoname>` when entering the map, or use the SAR plugin with the command `sar_record_at 0`.
23A valid demo begins when the player can move and ends when the player touches the end flags.
24For cooperative runs, both players must submit their demos.
25
26### Console Commands & Cheats
27
28The use of cheats, including specific console commands, is prohibited. Even if a command is not cheat-protected, it may still invalidate your run. For a full list of banned commands, refer to rules.portal2.sr/#command-list.
29Additionally, commands that affect game behavior (e.g., `net_*` commands) are not allowed.
30
31### Banned Exploits
32
33The following exploits are banned: freezing the game window, pause abuse, packet loss manipulation, intentional internet disconnection, and any glitches requiring setup before the run (e.g., moving portals or EHM).
34If you're unsure whether an exploit is allowed, ask in the Discord server.
35
36### Note
37
38The moderation team has the authority to remove any record they believe to be illegitimate.
39If you accidentally submit an illegitimate run, the moderation team will attempt to contact you, and you may receive a warning.
40However, ignoring their attempts to contact you, deliberately cheating, or receiving too many warnings may result in a ban.
41
42As this is an open beta, we highly encourage players to test the limits and report any exploits they discover. Your feedback is essential to improving the system and ensuring fair competition.
diff --git a/backend/handlers/map.go b/backend/handlers/map.go
index 56c3455..33910fe 100644
--- a/backend/handlers/map.go
+++ b/backend/handlers/map.go
@@ -328,7 +328,7 @@ func FetchMapLeaderboards(c *gin.Context) {
328// @Failure 400 {object} models.Response 328// @Failure 400 {object} models.Response
329// @Router /games [get] 329// @Router /games [get]
330func FetchGames(c *gin.Context) { 330func FetchGames(c *gin.Context) {
331 rows, err := database.DB.Query(`SELECT id, name, is_coop, image FROM games`) 331 rows, err := database.DB.Query(`SELECT id, name, is_coop, image FROM games ORDER BY id;`)
332 if err != nil { 332 if err != nil {
333 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 333 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
334 return 334 return
@@ -340,7 +340,7 @@ func FetchGames(c *gin.Context) {
340 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 340 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
341 return 341 return
342 } 342 }
343 categoryPortalRows, err := database.DB.Query(`SELECT c.id, c.name FROM game_categories gc JOIN categories c ON gc.category_id = c.id WHERE gc.game_id = $1`, game.ID) 343 categoryPortalRows, err := database.DB.Query(`SELECT c.id, c.name FROM game_categories gc JOIN categories c ON gc.category_id = c.id WHERE gc.game_id = $1 ORDER BY c.id;`, game.ID)
344 if err != nil { 344 if err != nil {
345 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 345 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
346 return 346 return
@@ -403,7 +403,7 @@ func FetchChapters(c *gin.Context) {
403 return 403 return
404 } 404 }
405 var response ChaptersResponse 405 var response ChaptersResponse
406 rows, err := database.DB.Query(`SELECT c.id, c.name, g.name, c.is_disabled, c.image FROM chapters c INNER JOIN games g ON c.game_id = g.id WHERE game_id = $1`, gameID) 406 rows, err := database.DB.Query(`SELECT c.id, c.name, g.name, c.is_disabled, c.image FROM chapters c INNER JOIN games g ON c.game_id = g.id WHERE game_id = $1 ORDER BY c.id;`, gameID)
407 if err != nil { 407 if err != nil {
408 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 408 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
409 return 409 return
@@ -448,7 +448,7 @@ func FetchMaps(c *gin.Context) {
448 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 448 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
449 return 449 return
450 } 450 }
451 categoryPortalRows, err := database.DB.Query(`SELECT c.id, c.name FROM game_categories gc JOIN categories c ON gc.category_id = c.id WHERE gc.game_id = $1`, gameID) 451 categoryPortalRows, err := database.DB.Query(`SELECT c.id, c.name FROM game_categories gc JOIN categories c ON gc.category_id = c.id WHERE gc.game_id = $1 ORDER BY c.id;`, gameID)
452 if err != nil { 452 if err != nil {
453 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 453 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
454 return 454 return
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 095cbbe..3980e1b 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -11,6 +11,7 @@ import Maps from './pages/Maps';
11import User from './pages/User'; 11import User from './pages/User';
12import Homepage from './pages/Homepage'; 12import Homepage from './pages/Homepage';
13import UploadRunDialog from './components/UploadRunDialog'; 13import UploadRunDialog from './components/UploadRunDialog';
14import Rules from './pages/Rules';
14import About from './pages/About'; 15import About from './pages/About';
15import { Game } from './types/Game'; 16import { Game } from './types/Game';
16import { API } from './api/Api'; 17import { API } from './api/Api';
@@ -59,6 +60,7 @@ const App: React.FC = () => {
59 <Route path="/games" element={<Games games={games} />} /> 60 <Route path="/games" element={<Games games={games} />} />
60 <Route path='/games/:id' element={<Maplist />}></Route> 61 <Route path='/games/:id' element={<Maplist />}></Route>
61 <Route path="/maps/*" element={<Maps profile={profile} isModerator={isModerator} onUploadRun={(mapID) => {setUploadRunDialog(true);setUploadRunDialogMapID(mapID)}} />}/> 62 <Route path="/maps/*" element={<Maps profile={profile} isModerator={isModerator} onUploadRun={(mapID) => {setUploadRunDialog(true);setUploadRunDialogMapID(mapID)}} />}/>
63 <Route path="/rules" element={<Rules />} />
62 <Route path="/about" element={<About />} /> 64 <Route path="/about" element={<About />} />
63 <Route path='/rankings' element={<Rankings></Rankings>}></Route> 65 <Route path='/rankings' element={<Rankings></Rankings>}></Route>
64 <Route path="*" element={"404"} /> 66 <Route path="*" element={"404"} />
diff --git a/frontend/src/css/Rules.css b/frontend/src/css/Rules.css
new file mode 100644
index 0000000..bbc84c0
--- /dev/null
+++ b/frontend/src/css/Rules.css
@@ -0,0 +1,3 @@
1main {
2 font-size: 24px;
3} \ No newline at end of file
diff --git a/frontend/src/pages/Rules.tsx b/frontend/src/pages/Rules.tsx
new file mode 100644
index 0000000..516b73c
--- /dev/null
+++ b/frontend/src/pages/Rules.tsx
@@ -0,0 +1,37 @@
1import React from 'react';
2import ReactMarkdown from 'react-markdown';
3
4import '../css/Rules.css';
5
6const Rules: React.FC = () => {
7
8 const [rulesText, setRulesText] = React.useState<string>("");
9
10 React.useEffect(() => {
11 const fetchRules = async () => {
12 try {
13 const response = await fetch(
14 'https://raw.githubusercontent.com/pektezol/leastportalshub/main/README.md'
15 );
16 if (!response.ok) {
17 throw new Error('Failed to fetch README');
18 }
19 const rulesText = await response.text();
20 setRulesText(rulesText);
21 } catch (error) {
22 console.error('Error fetching Rules:', error);
23 }
24 setRulesText(rulesText)
25 };
26 fetchRules();
27 }, []);
28
29
30 return (
31 <main>
32 <ReactMarkdown>{rulesText}</ReactMarkdown>
33 </main>
34 );
35};
36
37export default Rules;