initial merge of both repos
This commit is contained in:
3
UNO-Backend/README.md
Normal file
3
UNO-Backend/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# UNO-Backend
|
||||
|
||||
|
||||
117
UNO-Backend/UNO-Backend.njsproj
Normal file
117
UNO-Backend/UNO-Backend.njsproj
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<Name>UNO-Backend</Name>
|
||||
<RootNamespace>UNO-Backend</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>d5b44f82-6712-42ae-bcb7-ff5775f7b3dc</ProjectGuid>
|
||||
<ProjectHome>.</ProjectHome>
|
||||
<StartupFile>server.ts</StartupFile>
|
||||
<StartWebBrowser>True</StartWebBrowser>
|
||||
<SearchPath>
|
||||
</SearchPath>
|
||||
<WorkingDirectory>.</WorkingDirectory>
|
||||
<OutputPath>.</OutputPath>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
|
||||
<NodejsPort>1337</NodejsPort>
|
||||
<EnableTypeScript>true</EnableTypeScript>
|
||||
<StartWebBrowser>true</StartWebBrowser>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="config\cards.json">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="config\game.json">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\gameLogic\UnoChat.ts">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\gameLogic\UnoGame.ts">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\gameLogic\UnoRules.ts">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\interface\rest\response.ts">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\util\logging.ts">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="src\util\token.ts">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="tsconfig.json" />
|
||||
<Content Include="package.json" />
|
||||
<Content Include="README.md" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="config\" />
|
||||
<Folder Include="src\" />
|
||||
<Folder Include="src\interface\" />
|
||||
<Folder Include="src\interface\rest\" />
|
||||
<Folder Include="src\gameLogic\" />
|
||||
<Folder Include="src\util\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<TypeScriptCompile Include="server.ts">
|
||||
<SubType>Code</SubType>
|
||||
</TypeScriptCompile>
|
||||
<TypeScriptCompile Include="src\gameLogic\UnoSocket.ts">
|
||||
<SubType>Code</SubType>
|
||||
</TypeScriptCompile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\Node.js Tools\Microsoft.NodejsToolsV2.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>False</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>0</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:48022/</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>True</UseCustomServer>
|
||||
<CustomServerUrl>http://localhost:1337</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}" User="">
|
||||
<WebProjectProperties>
|
||||
<StartPageUrl>
|
||||
</StartPageUrl>
|
||||
<StartAction>CurrentPage</StartAction>
|
||||
<AspNetDebugging>True</AspNetDebugging>
|
||||
<SilverlightDebugging>False</SilverlightDebugging>
|
||||
<NativeDebugging>False</NativeDebugging>
|
||||
<SQLDebugging>False</SQLDebugging>
|
||||
<ExternalProgram>
|
||||
</ExternalProgram>
|
||||
<StartExternalURL>
|
||||
</StartExternalURL>
|
||||
<StartCmdLineArguments>
|
||||
</StartCmdLineArguments>
|
||||
<StartWorkingDirectory>
|
||||
</StartWorkingDirectory>
|
||||
<EnableENC>False</EnableENC>
|
||||
<AlwaysStartWebServerOnDebug>False</AlwaysStartWebServerOnDebug>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
6
UNO-Backend/UNO-Backend.njsproj.user
Normal file
6
UNO-Backend/UNO-Backend.njsproj.user
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
BIN
UNO-Backend/bin/Microsoft.NodejsTools.WebRole.dll
Normal file
BIN
UNO-Backend/bin/Microsoft.NodejsTools.WebRole.dll
Normal file
Binary file not shown.
328
UNO-Backend/config/cards.json
Normal file
328
UNO-Backend/config/cards.json
Normal file
@@ -0,0 +1,328 @@
|
||||
{
|
||||
"cards": [
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "0",
|
||||
"count": 1,
|
||||
"tx": "/assets/cards/110.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "1",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/111.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "2",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/112.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "3",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/113.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "4",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/114.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "5",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/115.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "6",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/116.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "7",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/117.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "8",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/118.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "9",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/119.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "+2",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/211.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "skip",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/213.png"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "reverse",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/212.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "0",
|
||||
"count": 1,
|
||||
"tx": "/assets/cards/120.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "1",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/121.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "2",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/122.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "3",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/123.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "4",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/124.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "5",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/125.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "6",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/126.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "7",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/127.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "8",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/128.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "9",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/129.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "+2",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/221.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "skip",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/223.png"
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"number": "reverse",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/222.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "0",
|
||||
"count": 1,
|
||||
"tx": "/assets/cards/140.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "1",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/141.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "2",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/142.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "3",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/143.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "4",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/144.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "5",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/145.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "6",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/146.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "7",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/147.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "8",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/148.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "9",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/149.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "+2",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/241.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "skip",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/243.png"
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"number": "reverse",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/242.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "0",
|
||||
"count": 1,
|
||||
"tx": "/assets/cards/130.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "1",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/131.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "2",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/132.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "3",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/133.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "4",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/134.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "5",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/135.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "6",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/136.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "7",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/137.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "8",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/138.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "9",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/139.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "+2",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/231.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "skip",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/233.png"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"number": "reverse",
|
||||
"count": 2,
|
||||
"tx": "/assets/cards/232.png"
|
||||
},
|
||||
{
|
||||
"color": "select",
|
||||
"number": "wild",
|
||||
"count": 4,
|
||||
"tx": "/assets/cards/301.png"
|
||||
},
|
||||
{
|
||||
"color": "select",
|
||||
"number": "wild+4",
|
||||
"count": 4,
|
||||
"tx": "/assets/cards/302.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
UNO-Backend/config/game.json
Normal file
9
UNO-Backend/config/game.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"kickIdlePlayers": true,
|
||||
"idleTimeout": 100000,
|
||||
"serverName": "Dennis Ultrakrasser Uno Server",
|
||||
"maxPlayers": 10,
|
||||
"password": "SagIchDirNicht!",
|
||||
"startCards": 7,
|
||||
"testMode": false
|
||||
}
|
||||
22
UNO-Backend/dockerfile
Normal file
22
UNO-Backend/dockerfile
Normal file
@@ -0,0 +1,22 @@
|
||||
FROM node:12.21-alpine
|
||||
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
|
||||
|
||||
COPY ./dist/out-tsc /home/node/backend
|
||||
COPY ./package.json /home/node/backend/package.json
|
||||
WORKDIR /home/node/backend
|
||||
RUN ls -ltra
|
||||
#RUN rm node_modules -R
|
||||
#RUN rm package-lock.json
|
||||
|
||||
#RUN chown node /opt/citron3 -Rf
|
||||
|
||||
RUN chmod -R 777 /home/node/backend
|
||||
|
||||
USER node
|
||||
|
||||
RUN npm install
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD [ "node", "--experimental-json-modules", "server.js"]
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
C:\Users\dennisgunia\source\repos\UNO-Backend\UNO-Backend\obj\Debug\UNO-Backend.njsprojAssemblyReference.cache
|
||||
C:\Users\dennisgunia\source\repos\UNO-Backend\UNO-Backend\bin\Microsoft.NodejsTools.WebRole.dll
|
||||
BIN
UNO-Backend/obj/Debug/UNO-Backend.njsprojAssemblyReference.cache
Normal file
BIN
UNO-Backend/obj/Debug/UNO-Backend.njsprojAssemblyReference.cache
Normal file
Binary file not shown.
30
UNO-Backend/package.json
Normal file
30
UNO-Backend/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "uno-backend",
|
||||
"version": "0.0.0",
|
||||
"description": "UNO-Backend",
|
||||
"main": "server.js",
|
||||
"author": {
|
||||
"name": ""
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc --build ",
|
||||
"clean": "tsc --build --clean"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.3",
|
||||
"@types/node": "^8.10.59",
|
||||
"@types/ws": "^7.2.3",
|
||||
"typescript": "^3.9.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
"express": "^4.17.1",
|
||||
"express-ws": "^4.0.0",
|
||||
"nvm": "0.0.4",
|
||||
"ts-node": "^9.1.1",
|
||||
"tsc": "^1.20150623.0",
|
||||
"tslib": "^2.1.0",
|
||||
"ws": "^7.2.3"
|
||||
}
|
||||
}
|
||||
69
UNO-Backend/server.ts
Normal file
69
UNO-Backend/server.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { UnoSockets } from './src/gameLogic/UnoSocket.js'
|
||||
import express from "express";
|
||||
import bodyParser from 'body-parser'
|
||||
import { UnoSession} from './src/gameLogic/UnoSession.js'
|
||||
import expressWs from 'express-ws';
|
||||
import http from 'http';
|
||||
import WebSocket from 'ws';
|
||||
import { UnoLobby } from './src/lobby/UnoLobby.js';
|
||||
import { resp } from './src/interface/rest/response.js';
|
||||
import { watch } from 'fs';
|
||||
|
||||
|
||||
const app = express();
|
||||
app.use(bodyParser.json())
|
||||
|
||||
|
||||
let unoLobby = new UnoLobby();
|
||||
|
||||
|
||||
app.get('/', (req, res) => res.send('Hello World!'));
|
||||
|
||||
|
||||
//lobby requests
|
||||
app.get('/unogame/lobbies', (req,res)=>{
|
||||
resp(req, res, true, unoLobby.getLobbies(), 200);
|
||||
})
|
||||
|
||||
//lobby requests
|
||||
app.post('/unogame/create', (req,res)=>{
|
||||
resp(req, res, true, {
|
||||
id: unoLobby.createLobby(req.body),
|
||||
}, 200);
|
||||
})
|
||||
|
||||
//lobby join
|
||||
app.post('/unogame/join', (req,res)=>{
|
||||
let data = unoLobby.joinLobby(req.body.nick,req.body.lid);
|
||||
resp(req, res, data[0], data[1], 200);
|
||||
})
|
||||
|
||||
|
||||
|
||||
const port = 3000;
|
||||
const server = app.listen(port, () => console.log(`Example app listening on port ${port}!`));
|
||||
|
||||
|
||||
|
||||
|
||||
const wss = new WebSocket.Server({ server });
|
||||
|
||||
wss.on('connection', (ws: WebSocket) => {
|
||||
console.log("connecting socket...")
|
||||
ws.on('message', (message: string) => { actionHandler(message,ws);});
|
||||
ws.send('{"msg":"Hello!"}');
|
||||
});
|
||||
|
||||
|
||||
function actionHandler(message: string, ws: WebSocket){
|
||||
try{
|
||||
const command = JSON.parse(message);
|
||||
console.log(command);
|
||||
if (command.action == "register"){
|
||||
unoLobby.registerLobby(message,ws)
|
||||
}
|
||||
}catch(ex){
|
||||
ws.send('{"reply":"Error"}');
|
||||
}
|
||||
}
|
||||
|
||||
126
UNO-Backend/src/gameLogic/UiEvents.ts
Normal file
126
UNO-Backend/src/gameLogic/UiEvents.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import { UnoSession, UnoCard, UnoPlayer, } from './UnoSession.js';
|
||||
import * as logic from './UnoRules.js'
|
||||
import * as Log from './../util/logging.js'
|
||||
|
||||
export function processUiEvents(game: UnoSession, player: UnoPlayer, command: any){
|
||||
switch(command.button){
|
||||
case 'ready':
|
||||
p_ready(game,player);
|
||||
break;
|
||||
case 'leave':
|
||||
p_leave(game,player);
|
||||
break;
|
||||
case 'play':
|
||||
p_play(game,player,command);
|
||||
break
|
||||
case 'double':
|
||||
p_double(game,player,command);
|
||||
break;
|
||||
case 'leave':
|
||||
p_leave(game,player);
|
||||
break;
|
||||
case 'pull':
|
||||
p_pull(game,player);
|
||||
break;
|
||||
case 'skip':
|
||||
p_skip(game,player);
|
||||
break;
|
||||
case 'uno':
|
||||
p_uno(game,player);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function p_ready (game: UnoSession, player: UnoPlayer){
|
||||
if (game.started) {
|
||||
player.socket.send(JSON.stringify({"notify":"game already started"}))
|
||||
} else {
|
||||
player.ready = true;
|
||||
Log.logNotice("Player " + player.nickname + " (" + player.userId + ") is ready");
|
||||
game.unoChat.writeMessage(player.nickname + " ist bereit");
|
||||
game.checkReady();
|
||||
game.clientUpdatePlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
function p_leave (game: UnoSession, player: UnoPlayer){
|
||||
if (game.started) {
|
||||
logic.leave(game,player)
|
||||
} else {
|
||||
//remove player
|
||||
const newPlayers = game.players.filter(el => el.userId != player.userId);
|
||||
Log.logNotice("Player " + player.nickname + " (" + player.userId + ") left in lobby");
|
||||
game.unoChat.writeMessage(player.nickname + " hat die Lobby verlassen");
|
||||
game.players = newPlayers;
|
||||
game.checkReady();
|
||||
player.socket.send(JSON.stringify({kick:"Spiel verlassen."}));
|
||||
game.clientRemovePlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
function p_play(game: UnoSession, player: UnoPlayer,command:any) {
|
||||
if (!game.started) {
|
||||
player.socket.send(JSON.stringify({"notify":"game not started"}))
|
||||
} else {
|
||||
let ret = logic.playCard(game, player, command.card)
|
||||
player.socket.send(JSON.stringify({
|
||||
notify: ret[1],
|
||||
warning: ret[0],
|
||||
}))
|
||||
game.clientUpdatePlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
function p_double(game: UnoSession, player: UnoPlayer,command:any) {
|
||||
if (!game.started) {
|
||||
player.socket.send(JSON.stringify({"notify":"game not started"}))
|
||||
} else {
|
||||
let ret = logic.playCard(game, player, command.card[0], command.card[1])
|
||||
player.socket.send(JSON.stringify({
|
||||
notify: ret[1],
|
||||
warning: ret[0],
|
||||
}))
|
||||
game.clientUpdatePlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
function p_pull(game: UnoSession, player: UnoPlayer) {
|
||||
if (!game.started) {
|
||||
player.socket.send(JSON.stringify({"notify":"game not started"}))
|
||||
} else {
|
||||
let ret = logic.pull(game, player)
|
||||
player.socket.send(JSON.stringify({
|
||||
notify: ret[1],
|
||||
warning: ret[0],
|
||||
}))
|
||||
game.clientUpdatePlayer(player);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function p_skip(game: UnoSession, player: UnoPlayer) {
|
||||
if (!game.started) {
|
||||
player.socket.send(JSON.stringify({"notify":"game not started"}))
|
||||
} else {
|
||||
let ret = logic.skip(game, player)
|
||||
player.socket.send(JSON.stringify({
|
||||
notify: ret[1],
|
||||
warning: ret[0],
|
||||
}))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function p_uno(game: UnoSession, player: UnoPlayer) {
|
||||
if (!game.started) {
|
||||
player.socket.send(JSON.stringify({"notify":"game not started"}))
|
||||
} else {
|
||||
let ret = logic.uno(game, player)
|
||||
player.socket.send(JSON.stringify({
|
||||
notify: ret[1],
|
||||
warning: ret[0],
|
||||
}))
|
||||
game.clientUpdatePlayer(player);
|
||||
}
|
||||
}
|
||||
94
UNO-Backend/src/gameLogic/UiVote.ts
Normal file
94
UNO-Backend/src/gameLogic/UiVote.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import WebSocket from 'ws';
|
||||
import { UnoSession, UnoPlayer } from './UnoSession';
|
||||
|
||||
export interface UIVoteQuestion {
|
||||
question: string;
|
||||
options: string[];
|
||||
counter?: number[];
|
||||
}
|
||||
|
||||
export class UIVote {
|
||||
duration: number;
|
||||
questions: UIVoteQuestion[];
|
||||
game: UnoSession;
|
||||
title: string;
|
||||
votedPlayers: String[];
|
||||
stopTimer;
|
||||
|
||||
constructor(game: UnoSession, title:string, duration: number){
|
||||
this.duration = duration;
|
||||
this.game = game;
|
||||
this.title = title;
|
||||
this.questions = [];
|
||||
this.stopTimer = undefined;
|
||||
this.votedPlayers = [];
|
||||
}
|
||||
|
||||
public addQuestion(question: string, options: string[]){
|
||||
let countArray = [];
|
||||
options.forEach(el => countArray.push(0));
|
||||
this.questions.push({
|
||||
question: question,
|
||||
options: options,
|
||||
counter: countArray,
|
||||
})
|
||||
}
|
||||
|
||||
public startVote(callback){
|
||||
[...this.game.players, ...this.game.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
"vote": this.title,
|
||||
"questions":this.questions,
|
||||
"time": this.duration
|
||||
}))
|
||||
}
|
||||
})
|
||||
this.stopTimer = setTimeout(()=>this.endVote(callback), this.duration);
|
||||
}
|
||||
|
||||
private endVote(callback){
|
||||
[...this.game.players, ...this.game.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({"endvote":""}))
|
||||
}
|
||||
})
|
||||
callback(this.questions);
|
||||
}
|
||||
|
||||
private broadcastResults(){
|
||||
[...this.game.players, ...this.game.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({"voteres":this.questions}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public abortVote(){
|
||||
clearTimeout(this.stopTimer);
|
||||
[...this.game.players, ...this.game.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({"endvote":""}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public voteEvent(id,player:UnoPlayer){
|
||||
if (this.votedPlayers.filter(el => el == player.userId).length == 0){
|
||||
this.questions[0].counter[id - 1] ++;
|
||||
this.broadcastResults();
|
||||
player.socket.send(JSON.stringify({
|
||||
notify: "Stimme abgegeben",
|
||||
warning: true,
|
||||
}))
|
||||
this.votedPlayers.push(player.userId)
|
||||
}else{
|
||||
player.socket.send(JSON.stringify({
|
||||
notify: "Stimme bereits abgegeben",
|
||||
warning: false,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
29
UNO-Backend/src/gameLogic/UnoChat.ts
Normal file
29
UNO-Backend/src/gameLogic/UnoChat.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import * as Log from './../util/logging.js'
|
||||
import { UnoSession, UnoPlayer, } from './UnoSession.js';
|
||||
|
||||
export class UnoChat {
|
||||
private chatHistory: string[];
|
||||
private game: UnoSession;
|
||||
constructor(game: UnoSession) {
|
||||
this.chatHistory = [];
|
||||
this.game = game;
|
||||
}
|
||||
|
||||
public writeMessage (msg:string ) {
|
||||
let now = new Date();
|
||||
let timestamp = now.getHours() + ":" + now.getMinutes();
|
||||
const line = "<span class='chat-line-date'>" + timestamp + "</span><span class='chat-line-msg'> " + msg + "</span><br />"
|
||||
Log.logChat(line);
|
||||
|
||||
[...this.game.players, ...this.game.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
"chat": line
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
336
UNO-Backend/src/gameLogic/UnoRules.ts
Normal file
336
UNO-Backend/src/gameLogic/UnoRules.ts
Normal file
@@ -0,0 +1,336 @@
|
||||
import * as log from '../util/logging.js'
|
||||
import { UnoSession, UnoCard, UnoPlayer, } from './UnoSession.js';
|
||||
import { UIVote } from './UiVote.js';
|
||||
|
||||
export function playCard(game: UnoSession, player: UnoPlayer, card: UnoCard, double?: UnoCard){
|
||||
log.logNotice("Player " + player.nickname + " (" + player.userId + ") plays card");
|
||||
let topCard = game.cardsPlayed[game.cardsPlayed.length - 1];
|
||||
//pr<70>fen ob spieler dran ist
|
||||
if (!(game.currentPlayer == player.userId)) {
|
||||
if(game.extraRules.sw_jumpin){
|
||||
//zwischenwerfen
|
||||
if ((topCard.number == card.number) && (topCard.color == card.color)) {
|
||||
game.cardsPlayed.push(card);
|
||||
game.clientRemoveCard(player,card);
|
||||
player.hand = player.hand.filter(el => el.id != card.id);
|
||||
let returnString = "Karte zwischengespielt";
|
||||
game.unoChat.writeMessage(player.nickname + ' hat eine ' +formatCard(card)+ ' <font color="#FF0000">zwischengespielt</font>.');
|
||||
if (player.hand.length == 1 && !player.uno) {
|
||||
drawPlayer(game, 1);
|
||||
returnString = "Karte zwischengespielt. Da du nicht UNO gesagt hast, musstest du eine Karte ziehen."
|
||||
log.logNotice("Player " + player.nickname + " (" + player.userId + ") did not mention UNO. Add +2 Cards");
|
||||
game.unoChat.writeMessage(player.nickname + " hat nicht UNO! gesagt und muss eine Karte ziehen.");
|
||||
}
|
||||
if (player.hand.length == 0 && player.uno) {
|
||||
finishGame(game, player);
|
||||
}
|
||||
return [true, returnString]
|
||||
}else{
|
||||
return [false, "Du kannst diese Karte nicht einwerfen"]
|
||||
}
|
||||
}else{
|
||||
return [false, "Du bist nicht dran"]
|
||||
}
|
||||
}
|
||||
//pr<70>fen ob Karte passt
|
||||
if ((topCard.color == "select") || (topCard.color == card.color) || (topCard.number == card.number) || card.number == 'wild' || card.number == 'wild+4' || game.testmode) {
|
||||
//kann gelegt werden
|
||||
game.cardsPlayed.push(card);
|
||||
game.clientRemoveCard(player,card);
|
||||
player.hand = player.hand.filter(el => el.id != card.id);
|
||||
let returnString = "Karte gespielt";
|
||||
//double akti
|
||||
|
||||
if(game.extraRules.sw_double && double){
|
||||
game.cardsPlayed.push(double);
|
||||
game.clientRemoveCard(player,double);
|
||||
player.hand = player.hand.filter(el => el.id != double.id);
|
||||
returnString = "Doppelt gespielt";
|
||||
game.unoChat.writeMessage(player.nickname + ' hat <font color="#FF0000">zwei</font> ' + formatCard(card)+ ' gelegt.');
|
||||
|
||||
}
|
||||
if(game.extraRules.sw_double && !double){
|
||||
game.unoChat.writeMessage(player.nickname + ' hat eine ' + formatCard(card)+ ' gelegt.');
|
||||
}
|
||||
|
||||
//uno pr<70>fen
|
||||
|
||||
if (player.hand.length == 1 && !player.uno) {
|
||||
drawPlayer(game, 1);
|
||||
returnString = "Karte gespielt. Da du nicht UNO gesagt hast, musstest du eine Karte ziehen."
|
||||
log.logNotice("Player " + player.nickname + " (" + player.userId + ") did not mention UNO. Add +2 Cards");
|
||||
game.unoChat.writeMessage(player.nickname + " hat nicht UNO! gesagt und muss eine Karte ziehen.");
|
||||
}
|
||||
if (player.hand.length == 0 ) {
|
||||
finishGame(game, player);
|
||||
}
|
||||
//n<>chster spieler
|
||||
advancePlayer(game, card.number == 'reverse', card.number == 'skip');
|
||||
|
||||
if (card.number == '+2') {
|
||||
drawPlayer(game, 2);
|
||||
game.players.forEach((obj, ix) => {
|
||||
if (obj.userId == game.currentPlayer) { game.unoChat.writeMessage(obj.nickname + " muss zwei Karten ziehen und setzt eine Runde aus.");}
|
||||
});
|
||||
advancePlayer(game, false, false);
|
||||
}
|
||||
if (card.number == 'wild+4') {
|
||||
drawPlayer(game, 4);
|
||||
game.players.forEach((obj, ix) => {
|
||||
if (obj.userId == game.currentPlayer) { game.unoChat.writeMessage(obj.nickname + " muss vier Karten ziehen und setzt eine Runde aus."); }
|
||||
});
|
||||
advancePlayer(game, false, false);
|
||||
}
|
||||
game.clientUpdatePlayedCard();
|
||||
return [true, returnString]
|
||||
} else {
|
||||
return [false, "Du kannst diese Karte hier nicht legen"]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function skip (game: UnoSession, player: UnoPlayer){
|
||||
log.logNotice("Player " + player.nickname + " (" + player.userId + ") skips card");
|
||||
game.unoChat.writeMessage(player.nickname + " setzt aus.");
|
||||
//pr<70>fen ob spieler dran ist
|
||||
if (!(game.currentPlayer == player.userId)) {
|
||||
return [false, "Du bist nicht dran"]
|
||||
}
|
||||
advancePlayer(game, false, false);
|
||||
return [true, "Ausgesetzt"]
|
||||
}
|
||||
|
||||
export function pull(game: UnoSession, player: UnoPlayer) {
|
||||
log.logNotice("Player " + player.nickname + " (" + player.userId + ") pulls card");
|
||||
//pr<70>fen ob spieler dran ist
|
||||
if (!(game.currentPlayer == player.userId)) {
|
||||
return [false, "Du bist nicht dran"]
|
||||
}
|
||||
if (player.cardDrawn) {
|
||||
return [false, "Du hast bereits eine Karte gezogen"]
|
||||
}
|
||||
game.unoChat.writeMessage(player.nickname + " zieht eine Karte.");
|
||||
player.cardDrawn = true;
|
||||
let card = game.cardsMixed[game.cardsMixed.length - 1];
|
||||
game.cardsMixed.pop();
|
||||
log.logNotice("Pulled Card form Stack. Remaining: " + game.cardsMixed.length);
|
||||
game.clientAddCard(player,card);
|
||||
player.hand.push(card);
|
||||
player.uno = false;
|
||||
player.socket.send(JSON.stringify({
|
||||
changprop:"canskip",
|
||||
value: true,
|
||||
}))
|
||||
return [true, "Karte gezogen"]
|
||||
}
|
||||
|
||||
export function uno(game: UnoSession, player: UnoPlayer) {
|
||||
log.logNotice("Player " + player.nickname + " (" + player.userId + ") says UNO");
|
||||
game.unoChat.writeMessage(player.nickname + " sagt UNO!");
|
||||
//pr<70>fen ob spieler dran ist
|
||||
if (!(game.currentPlayer == player.userId)) {
|
||||
return [false, "Du bist nicht dran"]
|
||||
}
|
||||
player.uno = true;
|
||||
return [true, "UNO!"]
|
||||
}
|
||||
|
||||
export function leave(game: UnoSession, player: UnoPlayer) {
|
||||
log.logNotice("Player " + player.nickname + " (" + player.userId + ") leaves");
|
||||
game.unoChat.writeMessage(player.nickname + " verl<72>sst das Spiel.");
|
||||
player.hand.forEach((obj) => {
|
||||
game.cardsMixed = [obj, ...game.cardsMixed];
|
||||
});
|
||||
if (player.userId == game.currentPlayer) {
|
||||
advancePlayer(game, false, false);
|
||||
}
|
||||
player.socket.send(JSON.stringify({kick:"Spiel verlassen."}));
|
||||
game.players = game.players.filter(el => el.userId != player.userId);
|
||||
checkRestart(game);
|
||||
}
|
||||
|
||||
export function onStart(game:UnoSession){
|
||||
|
||||
if(game.extraRules.sw_sleep){
|
||||
game.startTimer(8,() => {
|
||||
let index = 0;
|
||||
game.players.forEach((obj, ix) => {
|
||||
if (obj.userId == game.currentPlayer) {index = ix;}
|
||||
});
|
||||
drawPlayer(game,1);
|
||||
game.clientNotify(game.players[index],'Du hast gepennt und musst einer Karte ziehen!',true);
|
||||
game.clientPlaySound(game.players[index],'../assets/skip.wav')
|
||||
game.unoChat.writeMessage(game.players[index].nickname + "hat gepennt und muss eine Karte ziehen");
|
||||
advancePlayer(game,false,false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function advancePlayer(game:UnoSession, change, skip) {
|
||||
|
||||
let index = 0;
|
||||
game.players.forEach((obj, ix) => {
|
||||
if (obj.userId == game.currentPlayer) {index = ix;}
|
||||
});
|
||||
if(game.extraRules.sw_sleep){
|
||||
game.startTimer(8,() => {
|
||||
let index_sub = 0;
|
||||
game.players.forEach((obj, ix) => {
|
||||
if (obj.userId == game.currentPlayer) {index_sub = ix;}
|
||||
});
|
||||
drawPlayer(game,1);
|
||||
game.clientNotify(game.players[index_sub],'Du hast gepennt und musst einer Karte ziehen!',true);
|
||||
game.clientPlaySound(game.players[index_sub],'../assets/skip.wav')
|
||||
game.unoChat.writeMessage(game.players[index_sub].nickname + "hat gepennt und muss eine Karte ziehen");
|
||||
advancePlayer(game,false,false)
|
||||
})
|
||||
}
|
||||
game.players[index].cardDrawn = false; //temp werte resetten
|
||||
if (change) { game.direction = game.direction * -1 }
|
||||
let step = game.direction;
|
||||
if (skip) { step = step * 2 };
|
||||
let newIndex = index + step;
|
||||
if (newIndex < 0) { newIndex += game.players.length }
|
||||
if (newIndex > (game.players.length - 1)) { newIndex -= game.players.length }
|
||||
console.log(newIndex)
|
||||
game.currentPlayer = game.players[newIndex].userId;
|
||||
game.clientUpdateCurrentPlayer();
|
||||
checkStack(game);
|
||||
checkRestart(game);
|
||||
}
|
||||
|
||||
function checkRestart(game:UnoSession) {
|
||||
if (game.players.length == 1) {
|
||||
log.logNotice("One Player Left. Restarting in 5s");
|
||||
game.unoChat.writeMessage("Ein Spieler verbleibend. Neustart in 5 Sekunden.");
|
||||
if(game.activeVote){game.activeVote.abortVote();}
|
||||
if(game.extraRules.sw_sleep){
|
||||
game.stopTimer();
|
||||
}
|
||||
setTimeout(() => { game.restartGame() }, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function drawPlayer(game:UnoSession, amount) {
|
||||
let index = 0;
|
||||
game.players.forEach((obj, ix) => {
|
||||
if (obj.userId == game.currentPlayer) { index = ix; }
|
||||
});
|
||||
//draw for player
|
||||
for (let i = 0; i < amount; i++) {
|
||||
let card = game.cardsMixed[game.cardsMixed.length - 1];
|
||||
game.cardsMixed.pop();
|
||||
log.logNotice("Pulled Card form Stack. Remaining: " + game.cardsMixed.length);
|
||||
game.players[index].hand.push(card);
|
||||
game.clientAddCard(game.players[index],card);
|
||||
}
|
||||
game.clientUpdatePlayer(game.players[index]);
|
||||
return [true, ""]
|
||||
}
|
||||
|
||||
function finishGame(game:UnoSession, player: UnoPlayer) {
|
||||
|
||||
game.players.forEach((obj, ix) => {
|
||||
if (obj.userId == player.userId) {
|
||||
//TODO: Score berechnen
|
||||
player.score += getScore(game,player);
|
||||
game.clientRemovePlayer(player)
|
||||
game.clientUpdateWinner();
|
||||
game.winners.push(obj)
|
||||
game.unoChat.writeMessage(obj.nickname + " hat die Runde beendet.");
|
||||
|
||||
}
|
||||
});
|
||||
game.clientRemovePlayer(player);
|
||||
game.clientUpdateWinner();
|
||||
game.players = game.players.filter(el => el.userId != player.userId);
|
||||
|
||||
voteEarlyFinish(game);
|
||||
}
|
||||
|
||||
function checkStack(game:UnoSession) {
|
||||
//remix stack
|
||||
if (game.cardsPlayed.length > 10) {
|
||||
log.logNotice("Remix played cards");
|
||||
game.unoChat.writeMessage("Karten werden neu gemischt.");
|
||||
for (let i = 0; i < game.cardsPlayed.length - 2; i++) {
|
||||
let card = game.cardsPlayed[i];
|
||||
game.cardsMixed.push(game.cardsPlayed[i]);
|
||||
console.log(game.cardsMixed.length)
|
||||
|
||||
}
|
||||
game.cardsPlayed = [game.cardsPlayed[game.cardsPlayed.length - 1]];
|
||||
|
||||
game.cardsMixed.sort(() => Math.random() - 0.5);
|
||||
game.cardsMixed.sort(() => Math.random() - 0.5);
|
||||
game.cardsMixed.sort(() => Math.random() - 0.5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getScore(game:UnoSession, player: UnoPlayer) {
|
||||
let score = 0;
|
||||
game.players.forEach(pl => {
|
||||
if (pl.userId != player.userId && game.winners.length == 0) {
|
||||
pl.hand.forEach(card => {
|
||||
switch (card.number) {
|
||||
case 'wild':
|
||||
score += 50;
|
||||
break;
|
||||
case 'wild+4':
|
||||
score += 50;
|
||||
break;
|
||||
case '+2':
|
||||
score += 20;
|
||||
break;
|
||||
case 'reverse':
|
||||
score += 20;
|
||||
break;
|
||||
case 'skip':
|
||||
score += 20;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return score;
|
||||
}
|
||||
|
||||
function voteEarlyFinish(game: UnoSession){
|
||||
game.activeVote = new UIVote(game,'Vorzeitig beenden',8000);
|
||||
game.activeVote.addQuestion("Soll die Runde vorzeitig beendet werden?",["Ja","Nein"]);
|
||||
game.activeVote.startVote((values)=>{
|
||||
console.log("Vote results", values);
|
||||
if (values[0].counter[0] > values[0].counter[1]){
|
||||
game.unoChat.writeMessage("Abstimmung erfolgreich. Nächste Runde wird gestartet.")
|
||||
game.restartGame();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function formatCard(card: UnoCard){
|
||||
let color = ''
|
||||
let number = ''
|
||||
switch(card.color){
|
||||
case 'red': color='<font color="#ed1c24">Rote</font>'; break;
|
||||
case 'blue': color='<font color="#0095da">Blaue</font>'; break;
|
||||
case 'green': color='<font color="#00ab67">Grüne</font>'; break;
|
||||
case 'yellow': color='<font color="#ffde00">Gelbe</font>'; break;
|
||||
}
|
||||
|
||||
switch(card.number){
|
||||
case '+2': number='<font color="#FFFACD">Zieh Zwei Karte</font>'; break;
|
||||
case 'reverse': number='<font color="#FFFACD">Retoure Karte</font>'; break;
|
||||
case 'skip': number='<font color="#FFFACD">Aussetzen Karte</font>'; break;
|
||||
case 'wild': number='<font color="#F08080">Farbwahlkarte</font>'; break;
|
||||
case 'wild+4': number='<font color="#F08080">Zieh Vier Farbwahlkarte</font>'; break;
|
||||
default: number = card.number.toString();
|
||||
}
|
||||
|
||||
return color + ' ' + number
|
||||
|
||||
}
|
||||
|
||||
532
UNO-Backend/src/gameLogic/UnoSession.ts
Normal file
532
UNO-Backend/src/gameLogic/UnoSession.ts
Normal file
@@ -0,0 +1,532 @@
|
||||
//imports
|
||||
import * as log from '../util/logging.js'
|
||||
import * as resp from '../interface/rest/response.js'
|
||||
import { mkstring } from '../util/token.js'
|
||||
import * as logic from './UnoRules.js'
|
||||
import { UnoChat } from './UnoChat.js'
|
||||
import { UnoSockets } from './UnoSocket.js'
|
||||
import WebSocket from 'ws';
|
||||
|
||||
import jsonCards from '../../config/cards.json'
|
||||
import jsonConf from '../../config/game.json'
|
||||
import { shuffle } from '../util/shuffle.js'
|
||||
import { UIVote } from './UiVote.js'
|
||||
|
||||
export interface UnoCard {
|
||||
id: number;
|
||||
color: string;
|
||||
number: string;
|
||||
tx: string;
|
||||
}
|
||||
|
||||
export interface UnoPlayer {
|
||||
nickname: string;
|
||||
lastseen: Date;
|
||||
userId: string;
|
||||
ready: boolean;
|
||||
uno: boolean;
|
||||
cardDrawn: boolean;
|
||||
score: number;
|
||||
rounds: number;
|
||||
hand: UnoCard[];
|
||||
socket: WebSocket;
|
||||
}1
|
||||
|
||||
export interface UnoExtraRules {
|
||||
sw_stacking: boolean;
|
||||
sw_jumpin: boolean;
|
||||
sw_double: boolean;
|
||||
sw_sleep: boolean;
|
||||
sw_seveno: boolean;
|
||||
}
|
||||
|
||||
export class UnoSession {
|
||||
sessionID: number; //SitzungsID
|
||||
players: UnoPlayer[]; //alle Spielerobjekte
|
||||
winners: UnoPlayer[]; //fertige spieler
|
||||
cardsPlayed: UnoCard[]; //gespielte Karten Satpel
|
||||
cardsMixed: UnoCard[]; //nachziehkarten Stapel
|
||||
started: boolean; //spiel gestartet
|
||||
password: string; //passwort f<>r den zutritt
|
||||
currentPlayer: string; //aktueller spieler
|
||||
direction: number; //spielrichtung (1=vor, -1=zur<75>ck, 0=nicht gestartet)
|
||||
startcards: number; //anzahl der maximalen karten
|
||||
maxPlayers: number; //maximale spieleranzahl
|
||||
serverName: string; //serever Name
|
||||
unoChat: UnoChat;
|
||||
sockets: UnoSockets;
|
||||
lastPlayedBy: UnoPlayer;
|
||||
testmode: boolean;
|
||||
activeVote: UIVote;
|
||||
|
||||
sessionId: string;
|
||||
canDelete: boolean;
|
||||
|
||||
extraRules: UnoExtraRules;
|
||||
|
||||
sleepTimer;
|
||||
sleepValue;
|
||||
|
||||
stackSize: number; //anzahl der Karten die genzpgen werden müssen
|
||||
|
||||
private checkTimer;
|
||||
|
||||
constructor(sessionId,custom: any){
|
||||
this.extraRules = {
|
||||
sw_stacking: custom.sw_stacking ,
|
||||
sw_jumpin: custom.sw_jumpin ,
|
||||
sw_double: custom.sw_double ,
|
||||
sw_sleep: custom.sw_sleep ,
|
||||
sw_seveno: custom.sw_seveno ,
|
||||
}
|
||||
console.log(custom)
|
||||
this.players= [];
|
||||
this.winners= [];
|
||||
this.unoChat= new UnoChat(this);
|
||||
this.sockets= undefined;
|
||||
this.sessionId= sessionId;
|
||||
//konfigurationsdate laden
|
||||
log.logNotice("Spiel Starten. Lade Konfigurationsdatei...");
|
||||
let t_this = jsonConf;
|
||||
this.password = t_this.password;
|
||||
this.startcards = custom.startcards || t_this.startCards;
|
||||
this.maxPlayers = t_this.maxPlayers;
|
||||
this.serverName = t_this.serverName;
|
||||
this.testmode = t_this.testMode;
|
||||
this.sockets = new UnoSockets(this);
|
||||
this.activeVote = undefined;
|
||||
this.canDelete = false;
|
||||
this.initLobby();
|
||||
//kick inactive
|
||||
this.checkTimer = setInterval(()=>{
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
var dif = ((new Date()).getTime()- el.lastseen.getTime())/1000;
|
||||
if(!this.started && dif > 10){
|
||||
this.kickUser(el, "10 Sekunden Inaktiv")
|
||||
}else if(this.started && dif > 60){
|
||||
this.kickUser(el, "60 Sekunden Inaktiv")
|
||||
}else if(this.started && dif > 29 && dif < 31){
|
||||
this.unoChat.writeMessage(el.nickname + " wird in 30 Sekunden wegen Inaktivität gekickt.")
|
||||
}
|
||||
else if(this.started && dif > 44 && dif < 46){
|
||||
this.unoChat.writeMessage(el.nickname + " wird in 15 Sekunden wegen Inaktivität gekickt.")
|
||||
}
|
||||
})
|
||||
if ([...this.players, ...this.winners].length == 0){
|
||||
log.logInfo('Lobby empty. Closing...');
|
||||
this.canDelete = true;
|
||||
this.deleteSession();
|
||||
}
|
||||
},1000);
|
||||
}
|
||||
|
||||
public deleteSession(){
|
||||
[...this.players, ...this.winners].forEach(el => el.socket.close())
|
||||
clearInterval(this.sockets.pingTimer)
|
||||
clearInterval(this.checkTimer)
|
||||
this.stopTimer();
|
||||
}
|
||||
|
||||
private initLobby() {
|
||||
this.cardsPlayed = []; //gespielte Karten Satpel
|
||||
this.cardsMixed = []; //nachziehkarten Stapel
|
||||
this.started = false; //spiel gestartet
|
||||
this.currentPlayer = "";
|
||||
this.direction = 0;
|
||||
this.stackSize = 0;
|
||||
//Karten Laden
|
||||
log.logNotice("Spiel Starten. Lade Karten...");
|
||||
let cards = jsonCards.cards;
|
||||
let counter = 0;
|
||||
cards.forEach(el => {
|
||||
for (let i = 0; i < el.count; i++) {
|
||||
this.cardsMixed.push({
|
||||
id: counter,
|
||||
color: el.color,
|
||||
number: el.number,
|
||||
tx: el.tx
|
||||
});
|
||||
counter++;
|
||||
}
|
||||
});
|
||||
shuffle(this.cardsMixed); //Karten mischen
|
||||
shuffle(this.cardsMixed); //Karten mischen
|
||||
shuffle(this.cardsMixed); //Karten mischen
|
||||
shuffle(this.cardsMixed); //Karten mischen
|
||||
log.logNotice(this.cardsMixed.length.toString() + " Karten geladen.");
|
||||
this.clientUpdateStatus();
|
||||
}
|
||||
|
||||
public restartGame() {
|
||||
this.players = [...this.players, ...this.winners]; //alle Spielerobjekte
|
||||
this.winners = [];
|
||||
shuffle(this.players);
|
||||
this.players.forEach(player => {
|
||||
player.hand = []; //übrige karten löschen
|
||||
player.ready = false;
|
||||
player.uno = false;
|
||||
player.cardDrawn = false;
|
||||
player.rounds++;
|
||||
|
||||
})
|
||||
this.initLobby();
|
||||
this.clientUpdateHands();
|
||||
this.clientUpdateAllPlayers();
|
||||
|
||||
}
|
||||
|
||||
public playerJoin(nickname: string):any[] {
|
||||
if (this.started) {
|
||||
return [false,"Das Spiel wurde bereits gestartet."]
|
||||
} else {
|
||||
if (!nickname) {
|
||||
log.logError("User tried to connect without Nickname")
|
||||
return [false,"Du musst einen benutzernamen angeben."]
|
||||
|
||||
}
|
||||
//wenn sonst soweit alles passt
|
||||
const playerObj: UnoPlayer = {
|
||||
nickname: nickname,
|
||||
lastseen: new Date(),
|
||||
userId: mkstring(20),
|
||||
ready: false,
|
||||
uno: false,
|
||||
cardDrawn: false,
|
||||
score: 0,
|
||||
rounds: 1,
|
||||
hand: [],
|
||||
socket: undefined,
|
||||
};
|
||||
|
||||
this.players.push(playerObj);
|
||||
this.clientUpdatePlayer(playerObj);
|
||||
log.logNotice("Player " + nickname + " joined with id " + playerObj.userId);
|
||||
this.unoChat.writeMessage(nickname + " ist dem Spiel beigetreten");
|
||||
|
||||
return [true,{
|
||||
userId: playerObj.userId
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
public checkReady() {
|
||||
let all = 0;
|
||||
let ready = 0;
|
||||
this.players.forEach(function (obj, ix) {
|
||||
all++;
|
||||
if (obj.ready) { ready++; }
|
||||
});
|
||||
log.logNotice(ready + "/" + all + " Players are ready");
|
||||
this.unoChat.writeMessage(ready + "/" + all + " spieler sind Bereit");
|
||||
if (all == ready && all > 1) {
|
||||
log.logNotice("Start Game");
|
||||
this.startGame();
|
||||
logic.onStart(this);
|
||||
}
|
||||
}
|
||||
|
||||
public startGame() {
|
||||
this.started = true;
|
||||
log.logNotice("Starting Game. Dealing Cards");
|
||||
for (let player_ix = 0; player_ix < this.players.length; player_ix++) {
|
||||
let pObj = this.players[player_ix];
|
||||
pObj.hand = [];
|
||||
for (let i = 0; i < this.startcards; i++) {
|
||||
pObj.hand.push(this.pullCardFromStack());
|
||||
}
|
||||
this.clientUpdatePlayer(pObj);
|
||||
}
|
||||
this.cardsPlayed.push(this.pullCardFromStack());
|
||||
|
||||
log.logNotice("Cards dealt");
|
||||
|
||||
this.unoChat.writeMessage("Die Runde wurde gestartet");
|
||||
this.currentPlayer = this.players[0].userId;
|
||||
this.direction = 1;
|
||||
this.clientUpdatePlayedCard()
|
||||
this.clientUpdateCurrentPlayer();
|
||||
this.clientUpdateStatus();
|
||||
this.clientUpdateHands();
|
||||
}
|
||||
|
||||
private pullCardFromStack() {
|
||||
let card = this.cardsMixed[this.cardsMixed.length - 1];
|
||||
this.cardsMixed.pop();
|
||||
log.logNotice("Pulled Card form Stack. Remaining: " + this.cardsMixed.length);
|
||||
return card;
|
||||
}
|
||||
|
||||
public register_socket(socket: WebSocket, id: string){
|
||||
this.sockets.register_socket(socket,id);
|
||||
}
|
||||
|
||||
|
||||
public initClient(player: UnoPlayer) {
|
||||
let respObj: any = {};
|
||||
//add hands
|
||||
let players_public = []
|
||||
let players_winners = []
|
||||
this.players.forEach((obj) => {
|
||||
players_public.push(this.getPlayerMeta(obj));
|
||||
});
|
||||
this.winners.forEach((obj) => {
|
||||
players_winners.push(this.getPlayerMeta(obj));
|
||||
});
|
||||
|
||||
respObj.hand = player ? player.hand : [];
|
||||
respObj.serverName = this.serverName;
|
||||
respObj.cardsMixed = this.cardsMixed.length;
|
||||
respObj.cardsPlayed = this.cardsPlayed;
|
||||
respObj.started = this.started;
|
||||
respObj.direction = this.direction;
|
||||
respObj.currentPlayer = this.currentPlayer;
|
||||
respObj.players = players_public;
|
||||
respObj.winners = players_winners;
|
||||
respObj.extraRules = this.extraRules;
|
||||
respObj.extraRules.cards = this.startcards;
|
||||
respObj.stack = this.stackSize;
|
||||
player.socket.send(JSON.stringify({
|
||||
initClientData: respObj
|
||||
}))
|
||||
}
|
||||
|
||||
public clientHearbeat(player: UnoPlayer){
|
||||
player.lastseen = new Date();
|
||||
}
|
||||
|
||||
public findPlayerIndex(id) {
|
||||
let index = 0;
|
||||
this.players.forEach((obj, ix) => {
|
||||
if (obj.userId == id) {
|
||||
index = ix;
|
||||
}
|
||||
});
|
||||
return index;
|
||||
}
|
||||
|
||||
public clientUpdatePlayer(player: UnoPlayer){ //modify or add player
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
player: "modify",
|
||||
data: this.getPlayerMeta(player)
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public clientRemovePlayer(player: UnoPlayer){ //remove player
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
player: "remove",
|
||||
data: this.getPlayerMeta(player)
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private getPlayerMeta(player: UnoPlayer){
|
||||
return {
|
||||
nickname: player.nickname,
|
||||
lastseen: player.lastseen,
|
||||
userId: player.userId,
|
||||
ready: player.ready,
|
||||
cards: player.hand ? player.hand.length : 0,
|
||||
uno: player.uno,
|
||||
score: player.score,
|
||||
rounds: player.rounds,
|
||||
}
|
||||
}
|
||||
|
||||
public clientUpdateWinner(){ //modify or add player
|
||||
let players_winners = []
|
||||
this.winners.forEach((obj) => {
|
||||
players_winners.push(this.getPlayerMeta(obj));
|
||||
});
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
|
||||
el.socket.send(JSON.stringify({
|
||||
player: "winners",
|
||||
data: players_winners
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public clientUpdateAllPlayers(){
|
||||
let players_public = []
|
||||
let players_winners = []
|
||||
this.players.forEach((obj) => {
|
||||
players_public.push(this.getPlayerMeta(obj));
|
||||
});
|
||||
this.winners.forEach((obj) => {
|
||||
players_winners.push(this.getPlayerMeta(obj));
|
||||
});
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
player: "all",
|
||||
players: players_public,
|
||||
winners: players_winners,
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public clientUpdatePlayedCard(){
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
gameUpdate: "playedStack",
|
||||
card: this.cardsPlayed,
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public clientUpdateCurrentPlayer(){
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
gameUpdate: "currentPlayer",
|
||||
currentplayer: this.currentPlayer,
|
||||
direction: this.direction,
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public clientUpdateStatus(){
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
gameUpdate: "status",
|
||||
started: this.started
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public clientUpdateHands(){
|
||||
this.players.forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
hand: "all",
|
||||
cards: el.hand
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public clientAddCard(player: UnoPlayer, card: UnoCard){ //modify or add player
|
||||
if (player.socket && player.socket?.OPEN){
|
||||
player.socket.send(JSON.stringify({
|
||||
hand: "add",
|
||||
card: card
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
public clientRemoveCard(player: UnoPlayer, card: UnoCard){ //modify or add player
|
||||
if (player.socket && player.socket?.OPEN){
|
||||
player.socket.send(JSON.stringify({
|
||||
hand: "remove",
|
||||
card: card
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
public kickUser(player: UnoPlayer, reason: string){
|
||||
log.logNotice("Player " + player.nickname + " (" + player.userId + ") kicked for reason : " + reason);
|
||||
this.unoChat.writeMessage(player.nickname + " wurde gekickt. Grund: " + reason);
|
||||
if (player.socket && player.socket?.OPEN){
|
||||
player.socket.send(JSON.stringify({kick:reason}));
|
||||
}
|
||||
if(this.started){
|
||||
this.cardsMixed = [...player.hand, ...this.cardsMixed];
|
||||
if (player.userId == this.currentPlayer) {
|
||||
logic.advancePlayer(this, false, false);
|
||||
}
|
||||
}
|
||||
this.winners = this.winners.filter(el2 => el2.userId != player.userId);
|
||||
this.players = this.players.filter(el2 => el2.userId != player.userId);
|
||||
this.clientUpdateAllPlayers();
|
||||
}
|
||||
|
||||
public startTimer(duration: number, event: Function){
|
||||
this.stopTimer();
|
||||
this.sendTimer(duration);
|
||||
this.sleepValue = duration;
|
||||
this.sleepTimer = setInterval(()=>{
|
||||
this.sleepValue --;
|
||||
this.sendTimer(this.sleepValue);
|
||||
if (this.sleepValue == -1){
|
||||
this.stopTimer();
|
||||
event();
|
||||
}
|
||||
},1000)
|
||||
}
|
||||
|
||||
public stopTimer(){
|
||||
if (this.sleepTimer){
|
||||
clearInterval(this.sleepTimer)
|
||||
}
|
||||
}
|
||||
|
||||
private sendTimer(value: number){
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
timer: value,
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public clientPlaySound(player: UnoPlayer, sound: string){
|
||||
if (player.socket && player.socket?.OPEN){
|
||||
player.socket.send(JSON.stringify({
|
||||
sound: sound,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
public clientNotify(player: UnoPlayer, message: string, failed: boolean){
|
||||
if (player.socket && player.socket?.OPEN){
|
||||
player.socket.send(JSON.stringify({
|
||||
notify: message,
|
||||
warning: !failed,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
public addStackSize(value: number){
|
||||
this.stackSize += value;
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
stack: this.stackSize
|
||||
}))
|
||||
}
|
||||
})
|
||||
this.sendStackSize();
|
||||
}
|
||||
|
||||
public resetStackSize(){
|
||||
this.stackSize = 0;
|
||||
this.sendStackSize();
|
||||
}
|
||||
|
||||
private sendStackSize(){
|
||||
[...this.players, ...this.winners].forEach(el =>{
|
||||
if (el.socket && el.socket?.OPEN){
|
||||
el.socket.send(JSON.stringify({
|
||||
stack: this.stackSize
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
74
UNO-Backend/src/gameLogic/UnoSocket.ts
Normal file
74
UNO-Backend/src/gameLogic/UnoSocket.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { UnoSession, UnoCard, UnoPlayer, } from './UnoSession.js';
|
||||
import { processUiEvents } from './UiEvents.js'
|
||||
import * as Log from './../util/logging.js'
|
||||
import WebSocket from 'ws';
|
||||
|
||||
export class UnoSockets {
|
||||
private game:UnoSession;
|
||||
pingTimer;
|
||||
|
||||
constructor(game) {
|
||||
//heatbeat
|
||||
this.game = game;
|
||||
this.pingTimer = setInterval(()=>{
|
||||
this.game.players.forEach(el => {
|
||||
if(el.socket){
|
||||
el.socket.send(JSON.stringify({
|
||||
heartbeat: true
|
||||
}))
|
||||
}
|
||||
})
|
||||
},10000)
|
||||
|
||||
}
|
||||
|
||||
public register_socket(socket: WebSocket, id: string){
|
||||
let valid: boolean = false;
|
||||
this.game.players.forEach((obj, ix) => {
|
||||
if (obj.userId == id) {
|
||||
console.log('registered socket fot ',obj.userId);
|
||||
obj.socket = socket;
|
||||
obj.socket.on('message', (message: string) => {
|
||||
console.log('received message form:',obj.userId,'data', message);
|
||||
const command = JSON.parse(message);
|
||||
this.processCommand(command,obj);
|
||||
});
|
||||
valid = true;
|
||||
}
|
||||
});
|
||||
this.game.winners.forEach((obj, ix) => {
|
||||
if (obj.userId == id) {
|
||||
console.log('registered socket fot ',obj.userId);
|
||||
obj.socket = socket;
|
||||
obj.socket.on('message', (message: string) => {
|
||||
console.log('received message form:',obj.userId,'data', message);
|
||||
const command = JSON.parse(message);
|
||||
this.processCommand(command,obj);
|
||||
});
|
||||
valid = true;
|
||||
}
|
||||
});
|
||||
if (!valid){
|
||||
socket.send(JSON.stringify({kick:"Ungültige session."}));
|
||||
}
|
||||
}
|
||||
|
||||
private processCommand(command: any, player: UnoPlayer){
|
||||
switch(command.action){
|
||||
case 'uibutton':
|
||||
processUiEvents(this.game,player,command)
|
||||
break;
|
||||
case 'initData':
|
||||
this.game.initClient(player);
|
||||
break;
|
||||
case 'heartbeat':
|
||||
this.game.clientHearbeat(player);
|
||||
break;
|
||||
default:
|
||||
//none
|
||||
}
|
||||
if (command.vote){
|
||||
if(this.game.activeVote){this.game.activeVote.voteEvent(command.vote, player)}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
UNO-Backend/src/interface/rest/response.ts
Normal file
10
UNO-Backend/src/interface/rest/response.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export function resp (req, res, success, data, code) {
|
||||
res.status(code);
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(JSON.stringify({
|
||||
success: success,
|
||||
data: data,
|
||||
request_time: (new Date()).toUTCString(),
|
||||
api: "UNOv1"
|
||||
}));
|
||||
};
|
||||
76
UNO-Backend/src/lobby/UnoLobby.ts
Normal file
76
UNO-Backend/src/lobby/UnoLobby.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { UnoSession } from '../gameLogic/UnoSession.js';
|
||||
import { mkstring } from '../util/token.js';
|
||||
import WebSocket from 'ws';
|
||||
|
||||
export interface UnoLobbyProperties {
|
||||
serverName: string;
|
||||
startcards: number;
|
||||
|
||||
}
|
||||
|
||||
export interface UnoLobbyElement {
|
||||
session?: UnoSession;
|
||||
sessionID: string;
|
||||
properties: UnoLobbyProperties;
|
||||
|
||||
}
|
||||
|
||||
export class UnoLobby {
|
||||
|
||||
sessions: UnoLobbyElement[];
|
||||
|
||||
constructor(){
|
||||
this.sessions = []
|
||||
setInterval(()=>{
|
||||
this.sessions = this.sessions.filter(el => !el.session.canDelete)
|
||||
},500)
|
||||
}
|
||||
|
||||
public createLobby(properties: UnoLobbyProperties){
|
||||
const sId: string = mkstring(30);
|
||||
this.sessions.push({
|
||||
sessionID: sId,
|
||||
properties: properties,
|
||||
session: new UnoSession(sId,properties)
|
||||
})
|
||||
return sId;
|
||||
}
|
||||
|
||||
public getLobbies(){
|
||||
let list = [ ];
|
||||
this.sessions.forEach(el => {
|
||||
list.push({
|
||||
id: el.sessionID,
|
||||
properties: el.properties,
|
||||
status: el.session.started,
|
||||
players: [...el.session.players, ...el.session.winners].length
|
||||
})
|
||||
})
|
||||
return list;
|
||||
}
|
||||
|
||||
public joinLobby(nickname: string, lobbyId: string){
|
||||
let returnval = [false,"Die Lobby wurde nicht gefunden."]
|
||||
this.sessions.forEach(el => {
|
||||
console.log(el.sessionID, lobbyId)
|
||||
if(el.sessionID == lobbyId){
|
||||
returnval = el.session.playerJoin(nickname);
|
||||
console.log("found",returnval)
|
||||
}
|
||||
})
|
||||
console.log("done",returnval)
|
||||
return returnval;
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
public registerLobby(message: string, ws: WebSocket){
|
||||
const command = JSON.parse(message);
|
||||
this.sessions.forEach(el => {
|
||||
if(el.sessionID == command.lobby){
|
||||
console.log("found session for " + command.id + " @ " + command.lobby )
|
||||
el.session.register_socket(ws,command.id);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
36
UNO-Backend/src/util/logging.ts
Normal file
36
UNO-Backend/src/util/logging.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
export function logInfo(text) {
|
||||
var tmp = "\x1b[32m[Info] \x1b[0m" + text;
|
||||
console.log(tmp)
|
||||
}
|
||||
|
||||
export function logWarning(text) {
|
||||
var tmp = "\x1b[33m[Warn] \x1b[0m" + text;
|
||||
console.log(tmp)
|
||||
}
|
||||
|
||||
|
||||
export function logError(text) {
|
||||
var tmp = "\x1b[31m[Error] \x1b[0m" + text;
|
||||
console.log(tmp)
|
||||
}
|
||||
|
||||
export function logCritical(text) {
|
||||
var tmp = "\x1b[4m\x1b[31m[Critical]\x1b[0m \x1b[4m" + text + "\x1b[0m";
|
||||
console.log(tmp)
|
||||
}
|
||||
|
||||
export function logNotice (text) {
|
||||
var tmp = "\x1b[36m[Notice] \x1b[0m" + text;
|
||||
console.log(tmp)
|
||||
}
|
||||
|
||||
export function logDebug(text) {
|
||||
var tmp = "\x1b[36m[DEBUG] \x1b[0m" + text;
|
||||
console.log(tmp)
|
||||
}
|
||||
|
||||
export function logChat (text) {
|
||||
var tmp = "\x1b[35m[CHAT] \x1b[0m" + text;
|
||||
console.log(tmp)
|
||||
}
|
||||
|
||||
3
UNO-Backend/src/util/shuffle.ts
Normal file
3
UNO-Backend/src/util/shuffle.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function shuffle(array) {
|
||||
array.sort(() => Math.random() - 0.5);
|
||||
}
|
||||
9
UNO-Backend/src/util/token.ts
Normal file
9
UNO-Backend/src/util/token.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export function mkstring(length) {
|
||||
var result = '';
|
||||
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
var charactersLength = characters.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
19
UNO-Backend/tsconfig - Copy.json
Normal file
19
UNO-Backend/tsconfig - Copy.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"importHelpers": true,
|
||||
"target": "es2015"
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
20
UNO-Backend/tsconfig.json
Normal file
20
UNO-Backend/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"importHelpers": true,
|
||||
"target": "es2015",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user